CVE-2017-6839: Integer Overflow or Wraparound (CWE-190)
value: Integer overflow in modules/MSADPCM.cpp in Audio File Library (aka audiofile) 0.3.6 allows remote attackers to cause a denial of service (crash) via a crafted file.
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 5.5
Published: 2017-03-20T16:59Z
Repository: https://github.com/antlarr/audiofile
Language: C++
Files changed: .gitignore, ACKNOWLEDGEMENTS, AUTHORS, COPYING, COPYING.GPL, ChangeLog, INSTALL, Makefile.am, NEWS, NOTES, README, TODO, audiofile-uninstalled.pc.in, audiofile.pc.in, audiofile.spec.in, autogen.sh, configure.ac, docs/.gitignore, docs/Makefile.am, docs/afCloseFile.3.txt, docs/afGetFrameCount.3.txt, docs/afGetFrameSize.3.txt, docs/afIdentifyFD.3.txt, docs/afInitAESChannelDataTo.3.txt, docs/afInitCompression.3.txt, docs/afInitFileFormat.3.txt, docs/afInitSampleFormat.3.txt, docs/afNewFileSetup.3.txt, docs/afOpenFile.3.txt, docs/afQuery.3.txt, docs/afReadFrames.3.txt, docs/afReadMisc.3.txt, docs/afSeekFrame.3.txt, docs/afSetErrorHandler.3.txt, docs/afSetVirtualSampleFormat.3.txt, docs/afWriteFrames.3.txt, docs/asciidoc.conf, docs/sfconvert.1.txt, docs/sfinfo.1.txt, examples/.gitignore, examples/Makefile.am, examples/adddcoffset.c, examples/alsaplay.cpp, examples/irixread.c, examples/irixtestloop.c, examples/linuxtest.c, examples/osxplay.c, examples/power.c, examples/sgi.c, examples/sgi.h, gtest/Makefile.am, gtest/README.audiofile, gtest/gtest-all.cc, gtest/gtest.h, libaudiofile/.gitignore, libaudiofile/AIFF.cpp, libaudiofile/AIFF.h, libaudiofile/AVR.cpp, libaudiofile/AVR.h, libaudiofile/AudioFormat.cpp, libaudiofile/AudioFormat.h, libaudiofile/Buffer.cpp, libaudiofile/Buffer.h, libaudiofile/CAF.cpp, libaudiofile/CAF.h, libaudiofile/Compiler.h, libaudiofile/FLACFile.cpp, libaudiofile/FLACFile.h, libaudiofile/Features.h, libaudiofile/File.cpp, libaudiofile/File.h, libaudiofile/FileHandle.cpp, libaudiofile/FileHandle.h, libaudiofile/IFF.cpp, libaudiofile/IFF.h, libaudiofile/IRCAM.cpp, libaudiofile/IRCAM.h, libaudiofile/Instrument.cpp, libaudiofile/Instrument.h, libaudiofile/Loop.cpp, libaudiofile/Makefile.am, libaudiofile/Marker.cpp, libaudiofile/Marker.h, libaudiofile/Miscellaneous.cpp, libaudiofile/NIST.cpp, libaudiofile/NIST.h, libaudiofile/NeXT.cpp, libaudiofile/NeXT.h, libaudiofile/PacketTable.cpp, libaudiofile/PacketTable.h, libaudiofile/Raw.cpp, libaudiofile/Raw.h, libaudiofile/SampleVision.cpp, libaudiofile/SampleVision.h, libaudiofile/Setup.cpp, libaudiofile/Setup.h, libaudiofile/Shared.h, libaudiofile/Tag.h, libaudiofile/Track.cpp, libaudiofile/Track.h, libaudiofile/UUID.cpp, libaudiofile/UUID.h, libaudiofile/VOC.cpp, libaudiofile/VOC.h, libaudiofile/WAVE.cpp, libaudiofile/WAVE.h, libaudiofile/aes.cpp, libaudiofile/af_vfs.cpp, libaudiofile/af_vfs.h, libaudiofile/afinternal.h, libaudiofile/alac/ALACAudioTypes.h, libaudiofile/alac/ALACBitUtilities.c, libaudiofile/alac/ALACBitUtilities.h, libaudiofile/alac/ALACDecoder.cpp, libaudiofile/alac/ALACDecoder.h, libaudiofile/alac/ALACEncoder.cpp, libaudiofile/alac/ALACEncoder.h, libaudiofile/alac/EndianPortable.c, libaudiofile/alac/EndianPortable.h, libaudiofile/alac/Makefile.am, libaudiofile/alac/ag_dec.c, libaudiofile/alac/ag_enc.c, libaudiofile/alac/aglib.h, libaudiofile/alac/dp_dec.c, libaudiofile/alac/dp_enc.c, libaudiofile/alac/dplib.h, libaudiofile/alac/matrix_dec.c, libaudiofile/alac/matrix_enc.c, libaudiofile/alac/matrixlib.h, libaudiofile/audiofile.exports, libaudiofile/audiofile.h, libaudiofile/aupv.c, libaudiofile/aupvinternal.h, libaudiofile/aupvlist.h, libaudiofile/byteorder.h, libaudiofile/compression.cpp, libaudiofile/compression.h, libaudiofile/data.cpp, libaudiofile/debug.cpp, libaudiofile/debug.h, libaudiofile/error.c, libaudiofile/error.h, libaudiofile/extended.c, libaudiofile/extended.h, libaudiofile/format.cpp, libaudiofile/g711.c, libaudiofile/g711.h, libaudiofile/modules/ALAC.cpp, libaudiofile/modules/ALAC.h, libaudiofile/modules/BlockCodec.cpp, libaudiofile/modules/BlockCodec.h, libaudiofile/modules/FLAC.cpp, libaudiofile/modules/FLAC.h, libaudiofile/modules/FileModule.cpp, libaudiofile/modules/FileModule.h, libaudiofile/modules/G711.cpp, libaudiofile/modules/G711.h, libaudiofile/modules/IMA.cpp, libaudiofile/modules/IMA.h, libaudiofile/modules/MSADPCM.cpp, libaudiofile/modules/MSADPCM.h, libaudiofile/modules/Makefile.am, libaudiofile/modules/Module.cpp, libaudiofile/modules/Module.h, libaudiofile/modules/ModuleState.cpp, libaudiofile/modules/ModuleState.h, libaudiofile/modules/PCM.cpp, libaudiofile/modules/PCM.h, libaudiofile/modules/RebufferModule.cpp, libaudiofile/modules/RebufferModule.h, libaudiofile/modules/SimpleModule.cpp, libaudiofile/modules/SimpleModule.h, libaudiofile/modules/UT_RebufferModule.cpp, libaudiofile/openclose.cpp, libaudiofile/pcm.cpp, libaudiofile/pcm.h, libaudiofile/query.cpp, libaudiofile/units.cpp, libaudiofile/units.h, libaudiofile/util.cpp, libaudiofile/util.h, sfcommands/.gitignore, sfcommands/Makefile.am, sfcommands/printinfo.c, sfcommands/printinfo.h, sfcommands/sfconvert.c, sfcommands/sfinfo.c, test/.gitignore, test/ADPCM.cpp, test/AES.cpp, test/ALAC.cpp, test/ChannelMatrix.cpp, test/Error.cpp, test/FLAC.cpp, test/FloatToInt.cpp, test/FormatWithChannels.cpp, test/Identify.cpp, test/Instrument.cpp, test/IntToFloat.cpp, test/InvalidCompressionFormat.cpp, test/InvalidSampleFormat.cpp, test/Large.cpp, test/Loop.cpp, test/Lossless.h, test/Makefile.am, test/Marker.cpp, test/Miscellaneous.cpp, test/NeXT.cpp, test/PCMData.cpp, test/PCMMapping.cpp, test/Pipe.cpp, test/Query.cpp, test/SampleFormat.cpp, test/Seek.cpp, test/Sign.cpp, test/TestUtilities.cpp, test/TestUtilities.h, test/VirtualFile.cpp, test/floatto24.c, test/instparamtest.c, test/instparamwrite.c, test/printmarkers.c, test/query2.c, test/sixteen-to-eight.c, test/testaupv.c, test/testchannelmatrix.c, test/testdouble.c, test/testfloat.c, test/testmarkers.c, test/twentyfour.c, test/twentyfour2.c, test/writealaw.c, test/writeraw.c, test/writeulaw.c
Commit date: 2017-03-06 13:57:51 +0100
Commit message: Check for multiplication overflow in MSADPCM decodeSample

Check for multiplication overflow (using __builtin_mul_overflow
if available) in MSADPCM.cpp decodeSample and return an empty
decoded block if an error occurs.

This fixes the 00193-audiofile-signintoverflow-MSADPCM case of #41

Diff: diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3444160
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+*.a
+*.gcda
+*.gcno
+*.la
+*.lo
+*.log
+*.o
+*.trs
+.DS_Store
+.deps
+.libs
+ABOUT-NLS
+COPYING
+Makefile
+Makefile.in
+aclocal.m4
+audiofile-uninstalled.pc
+audiofile.pc
+audiofile.spec
+autom4te.cache
+compile
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+intl
+libtool
+ltconfig
+ltmain.sh
+missing
+mkinstalldirs
+so_locations
+stamp-h
+stamp-h.in
+stamp-h1
+test-driver
+version.h
diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS
new file mode 100644
index 0000000..ed72835
--- /dev/null
+++ b/ACKNOWLEDGEMENTS
@@ -0,0 +1,25 @@
+Thanks to all who have contributed patches for the Audio File Library:
+* Jason Allen
+* Julien Boulnois
+* Davy Durham
+* Bruce Forsberg
+* Fabrizio Gennari
+* Simon Kagedal
+* Thomas Klausner
+* Daniel Kobras
+* Michael Krause
+* Wim Lewis
+* Eric Mitchell
+* Cristian Morales Vega
+* Mark Murnane
+* Michael Palimaka
+* Jean-Francois Panisset
+* Axel Roebel
+* Matthias Rumpke
+* Chris Wolf
+
+Thanks to Douglas Scott of SGI for helping me understand the tricky parts
+of the Audio File Library API.  Thanks to Chris Pirazzi and Scott Porter
+of SGI for creating the Audio File Library in the first place.
+
+Thanks also to all who have reported bugs.
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9f639cb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Audio File Library Authors
+
+Michael Pruett <michael@68k.org>
+
+Chris Pirazzi, Scott Porter, and Doug Scott
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..9361e98
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2122 @@
+2016-08-29  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/SimpleModule.h:
+	Fix undefined behavior in sign conversion.
+
+2016-07-05  Joerg Krause <joerg.krause@embedded.rocks>
+
+	* audiofile.pc.in:
+	Link with FLAC for static builds.
+
+2016-07-05  Michael Pruett <michael@68k.org>
+
+	* test/Identify.cpp,
+	test/Instrument.cpp,
+	test/Loop.cpp,
+	test/Lossless.h,
+	test/NeXT.cpp,
+	test/SampleFormat.cpp:
+	Fix warnings in tests comparing integers to enums.
+
+2016-07-05  Michael Pruett <michael@68k.org>
+
+	* test/Identify.cpp,
+	test/NeXT.cpp:
+	Fix type of test data arrays.
+
+2016-07-04  Nik Reiman <nik.reiman@gmail.com>
+
+	* libaudiofile/modules/FLAC.cpp:
+	Include <algorithm> in FLAC.cpp.
+
+2016-07-04  Michael Pruett <michael@68k.org>
+
+	* test/.gitignore,
+	test/FormatWithChannels.cpp,
+	test/Makefile.am:
+	Add test for changing both sample format and channel count.
+
+2016-07-04  Fabrizio Gennari <fabrizio.ge@tiscali.it>
+
+	* libaudiofile/modules/ModuleState.cpp:
+	Fix data corruption when changing both sample format and channel count.
+
+2016-07-04  Nik Reiman <nik.reiman@gmail.com>
+
+	* .gitignore:
+	Add compile to .gitignore.
+
+2016-07-04  Daniel Verkamp <daniel@drv.nu>
+
+	* libaudiofile/CAF.cpp:
+	Replace bzero() with memset().
+
+2016-07-04  Christoph J. Thompson <cjsthompson@gmail.com>
+
+	* Makefile.am,
+	configure.ac:
+	Allow configuring pkg-config installation directory.
+
+2016-07-04  Michael Pruett <michael@68k.org>
+
+	* autogen.sh:
+	Replace custom configuration script with autoreconf.
+
+2014-07-04  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AVR.cpp,
+	libaudiofile/IRCAM.cpp,
+	libaudiofile/NIST.cpp,
+	libaudiofile/Raw.cpp:
+	Remove redundant initialization.
+
+2014-05-26  Michael Pruett <michael@68k.org>
+
+	* examples/Makefile.am,
+	libaudiofile/modules/Makefile.am,
+	sfcommands/Makefile.am,
+	test/Makefile.am:
+	Change INCLUDES to AM_CPPFLAGS.
+
+2014-05-26  Michael Pruett <michael@68k.org>
+
+	* configure.ac:
+	Remove arguments to AM_INIT_AUTOMAKE.
+
+2014-05-26  Michael Pruett <michael@68k.org>
+
+	* gtest/*:
+	Update Google Test framework to version 1.7.0.
+
+2014-05-26  Michael Pruett <michael@68k.org>
+
+	* docs/Makefile.am,
+	docs/afIdentifyFD.3.txt,
+	test/Identify.cpp,
+	test/Makefile.am:
+	Add tests and documentation for afIdentifyFD() and afIdentifyNamedFD().
+
+2014-02-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/CAF.cpp,
+	libaudiofile/FLACFile.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/VOC.cpp,
+	test/Miscellaneous.cpp:
+	Prohibit creating files with miscellaneous data for incapable file formats.
+
+2014-02-05  Michael Pruett <michael@68k.org>
+
+	* test/Miscellaneous.cpp:
+	Refactor test for reading and writing miscellaneous data.
+
+2014-02-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/CAF.cpp,
+	libaudiofile/FLACFile.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/VOC.cpp,
+	test/Instrument.cpp:
+	Prohibit creating files with instruments for incapable file formats.
+
+2013-03-12  Antoine Jacoutot <ajacoutot@bsdfrog.org>
+
+	* configure.ac:
+	Fix sanitization of FLAC_CFLAGS.
+
+2013-03-10  Pino Toscano <toscano.pino@tiscali.it>
+
+	* test/TestUtilities.cpp,
+	test/TestUtilities.h,
+	test/floatto24.c,
+	test/sixteen-to-eight.c,
+	test/testchannelmatrix.c,
+	test/testdouble.c,
+	test/testfloat.c,
+	test/testmarkers.c,
+	test/twentyfour.c,
+	test/twentyfour2.c,
+	test/writealaw.c,
+	test/writeraw.c,
+	test/writeulaw.c:
+	Remove the usage of PATH_MAX in tests.
+
+	Replace static PATH_MAX-sized buffers with dynamically allocated strings.
+
+2013-03-07  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/g711.c:
+	Fix compiler warning regarding discarding const qualification.
+
+2013-03-07  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/g711.c:
+	Remove unused G.711 tables.
+
+2013-03-07  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/CAF.cpp,
+	libaudiofile/FLACFile.cpp,
+	libaudiofile/IFF.cpp,
+	libaudiofile/IRCAM.cpp,
+	libaudiofile/NIST.cpp,
+	libaudiofile/Raw.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/VOC.cpp,
+	libaudiofile/WAVE.cpp:
+	Refactor accessing track setup from file setup.
+
+2013-03-06  Michael Pruett <michael@68k.org>
+
+	Release version 0.3.6 of the Audio File Library.
+
+2013-03-06  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/alac/ALACDecoder.cpp,
+	libaudiofile/alac/ag_enc.c:
+	Fix unaligned memory accesses in ALAC.
+
+	Thanks to Erik de Castro Lopo for pointing out this problem.
+
+2013-03-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/WAVE.cpp,
+	test/.gitignore,
+	test/Instrument.cpp,
+	test/Makefile.am:
+	Fix instrument parameter validation.
+
+2013-03-03  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/alac/ALACAudioTypes.h,
+	libaudiofile/alac/EndianPortable.c:
+	Fix byte order detection for ALAC.
+
+2013-03-03  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/alac/EndianPortable.c,
+	libaudiofile/alac/ag_dec.c,
+	libaudiofile/alac/ag_enc.c:
+	Eliminate unnecessary header inclusion in ALAC source files.
+
+2013-03-03  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/alac/ALACEncoder.cpp:
+	Write ALAC channel layout tag in big-endian byte order.
+
+2013-03-03  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/alac/ALACEncoder.cpp:
+	Remove superfluous debugging print statements in ALAC encoder.
+
+2013-02-27  Michael Pruett <michael@68k.org>
+
+	Update address for Free Software Foundation.
+
+2013-02-26  Michael Pruett <michael@68k.org>
+
+	Update license to LGPL 2.1.
+
+2013-02-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am:
+	Add support for running unit tests under Valgrind.
+
+2013-02-20  Cristian Morales Vega <reddwarf@opensuse.org>
+
+	* configure.ac:
+	Add option for building without example programs.
+
+2013-02-20  Michael Pruett <michael@68k.org>
+
+	* README,
+	configure.ac,
+	docs/afInitCompression.3.txt,
+	docs/sfconvert.1.txt,
+	libaudiofile/Buffer.cpp,
+	libaudiofile/Buffer.h,
+	libaudiofile/CAF.cpp,
+	libaudiofile/CAF.h,
+	libaudiofile/Makefile.am,
+	libaudiofile/PacketTable.cpp,
+	libaudiofile/PacketTable.h,
+	libaudiofile/Track.cpp,
+	libaudiofile/Track.h,
+	libaudiofile/afinternal.h,
+	libaudiofile/alac/ALACAudioTypes.h,
+	libaudiofile/alac/ALACBitUtilities.c,
+	libaudiofile/alac/ALACBitUtilities.h,
+	libaudiofile/alac/ALACDecoder.cpp,
+	libaudiofile/alac/ALACDecoder.h,
+	libaudiofile/alac/ALACEncoder.cpp,
+	libaudiofile/alac/ALACEncoder.h,
+	libaudiofile/alac/EndianPortable.c,
+	libaudiofile/alac/EndianPortable.h,
+	libaudiofile/alac/Makefile.am,
+	libaudiofile/alac/ag_dec.c,
+	libaudiofile/alac/ag_enc.c,
+	libaudiofile/alac/aglib.h,
+	libaudiofile/alac/dp_dec.c,
+	libaudiofile/alac/dp_enc.c,
+	libaudiofile/alac/dplib.h,
+	libaudiofile/alac/matrix_dec.c,
+	libaudiofile/alac/matrix_enc.c,
+	libaudiofile/alac/matrixlib.h,
+	libaudiofile/audiofile.h,
+	libaudiofile/modules/ALAC.cpp,
+	libaudiofile/modules/ALAC.h,
+	libaudiofile/modules/Makefile.am,
+	libaudiofile/modules/ModuleState.cpp,
+	libaudiofile/units.cpp,
+	libaudiofile/units.h,
+	sfcommands/sfconvert.c,
+	test/.gitignore,
+	test/ALAC.cpp,
+	test/Makefile.am:
+	Add support for ALAC.
+
+2013-02-19  Michael Pruett <michael@68k.org>
+
+	* README,
+	configure.ac,
+	docs/afInitCompression.3.txt,
+	docs/sfconvert.1.txt,
+	libaudiofile/FLACFile.cpp,
+	libaudiofile/FLACFile.h,
+	libaudiofile/Features.h,
+	libaudiofile/FileHandle.cpp,
+	libaudiofile/Makefile.am,
+	libaudiofile/audiofile.h,
+	libaudiofile/data.cpp,
+	libaudiofile/modules/FLAC.cpp,
+	libaudiofile/modules/FLAC.h,
+	libaudiofile/modules/FileModule.cpp,
+	libaudiofile/modules/FileModule.h,
+	libaudiofile/modules/G711.cpp,
+	libaudiofile/modules/G711.h,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/IMA.h,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/MSADPCM.h,
+	libaudiofile/modules/Makefile.am,
+	libaudiofile/modules/ModuleState.cpp,
+	libaudiofile/modules/ModuleState.h,
+	libaudiofile/modules/PCM.cpp,
+	libaudiofile/modules/PCM.h,
+	libaudiofile/units.cpp,
+	libaudiofile/units.h,
+	sfcommands/sfconvert.c,
+	test/.gitignore,
+	test/FLAC.cpp,
+	test/Lossless.h,
+	test/Makefile.am:
+	Add support for FLAC.
+
+2013-02-10  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/FileHandle.cpp,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/SimpleModule.h:
+	Fix uninitialized fields in constructors.
+
+2013-02-09  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/BlockCodec.cpp,
+	libaudiofile/modules/BlockCodec.h,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/Makefile.am:
+	Factor out fixed-size block codec functionality common to IMA and MS ADPCM.
+
+2013-02-09  Michael Pruett <michael@68k.org>
+
+	* test/InvalidCompressionFormat.cpp,
+	test/InvalidSampleFormat.cpp,
+	test/Query.cpp:
+	Ignore errors in tests for which errors are expected.
+
+2013-02-09  Michael Pruett <michael@68k.org>
+
+	* test/PCMData.cpp:
+	Update PCMData test to validate PCM mappings.
+
+2013-02-09  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/CAF.cpp,
+	libaudiofile/IFF.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/VOC.cpp,
+	test/AES.cpp:
+	Ensure that initializing AES data fails on unsupported file formats.
+
+2013-02-05  Michael Pruett <michael@68k.org>
+
+	* Release version 0.3.5 of the Audio File Library.
+
+2013-02-04  Michael Pruett <michael@68k.org>
+
+	* gtest/Makefile.am,
+	libaudiofile/Makefile.am,
+	test/Makefile.am:
+	Disable exceptions and RTTI when building Google Test framework.
+
+2013-02-04  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/File.cpp,
+	libaudiofile/File.h:
+	Fix resource leak in File destructor.
+
+2013-02-02  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am,
+	libaudiofile/modules/Makefile.am:
+	Remove test coverage files when cleaning.
+
+2013-02-02  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/IRCAM.cpp:
+	Fix calculation of IRCAM frame size.
+
+2013-02-02  Michael Pruett <michael@68k.org>
+
+	* test/PCMData.cpp:
+	Update PCMData test to create multi-channel audio files.
+
+2013-01-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/CAF.cpp:
+	Report error when attempting to open a file with invalid sample width.
+
+2013-01-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/CAF.cpp,
+	libaudiofile/NeXT.cpp,
+	libaudiofile/VOC.cpp,
+	libaudiofile/WAVE.cpp:
+	Report error when attempting to open a file with zero channels.
+
+2013-01-31  Michael Pruett <michael@68k.org>
+
+	* test/NeXT.cpp:
+	Add test for opening a NeXT sound file with zero channels.
+
+2013-01-30  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/NIST.cpp:
+	Remove unnecessary check for positive channel count.
+
+	This check is already performed in afInitChannels().
+
+2013-01-30  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/SampleVision.cpp:
+	Set compression type before initializing sample format.
+
+2013-01-30  Michael Pruett <michael@68k.org>
+
+	* test/TestUtilities.cpp:
+	Include <unistd.h> to provide declaration of close().
+
+2013-01-30  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.h,
+	libaudiofile/AVR.h,
+	libaudiofile/CAF.h,
+	libaudiofile/Compiler.h,
+	libaudiofile/IFF.h,
+	libaudiofile/IRCAM.h,
+	libaudiofile/NIST.h,
+	libaudiofile/NeXT.h,
+	libaudiofile/SampleVision.h,
+	libaudiofile/VOC.h,
+	libaudiofile/WAVE.h,
+	libaudiofile/modules/G711.cpp,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/PCM.cpp,
+	libaudiofile/modules/RebufferModule.h,
+	libaudiofile/modules/SimpleModule.h:
+	Use C++11 override keyword with compilers that support it.
+
+2013-01-19  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/CAF.cpp,
+	libaudiofile/util.cpp:
+	Fix conversion specifications in error messages.
+
+2013-01-19  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/format.cpp,
+	test/Makefile.am,
+	test/SampleFormat.cpp:
+	Fix null checks in afGetSampleFormat() and afGetVirtualSampleFormat().
+
+	Thanks to David Lassonde for pointing out this problem.
+
+2013-01-19  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/AudioFormat.h,
+	libaudiofile/CAF.cpp,
+	libaudiofile/NeXT.cpp,
+	libaudiofile/VOC.cpp,
+	libaudiofile/WAVE.cpp,
+	libaudiofile/modules/G711.cpp,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/ModuleState.cpp,
+	test/InvalidCompressionFormat.cpp:
+	Validate compressed audio formats.
+
+2012-11-13  Michael Pruett <michael@68k.org>
+
+	* configure.ac, docs/Makefile.am:
+	Add support for building without documentation.
+
+2012-11-12  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/File.cpp:
+	Open files in binary mode on Windows.
+
+	Thanks to Fabrizio Gennari for proposing this change.
+
+2012-10-13  Michael Pruett <michael@68k.org>
+
+	* test/*:
+	Use unique filenames for temporary files in tests.
+
+	Thanks to Giovanni Mascellani for pointing out this problem.
+
+	http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=687405
+
+2012-09-12  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/AVR.cpp,
+	libaudiofile/AudioFormat.cpp,
+	libaudiofile/AudioFormat.h,
+	libaudiofile/CAF.cpp,
+	libaudiofile/CAF.h,
+	libaudiofile/IFF.cpp,
+	libaudiofile/IRCAM.cpp,
+	libaudiofile/NIST.cpp,
+	libaudiofile/NeXT.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/Track.cpp,
+	libaudiofile/Track.h,
+	libaudiofile/VOC.cpp,
+	libaudiofile/WAVE.cpp:
+	Refactor calculation of frame count from audio data size.
+
+2012-09-06  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am, libaudiofile/modules/Makefile.am:
+	Reorganize build.
+
+2012-09-06  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp,
+	libaudiofile/AIFF.h,
+	libaudiofile/CAF.cpp,
+	libaudiofile/SampleVision.cpp,
+	libaudiofile/VOC.cpp,
+	libaudiofile/WAVE.cpp,
+	libaudiofile/WAVE.h,
+	libaudiofile/util.cpp,
+	libaudiofile/util.h,
+	test/Makefile.am,
+	test/Marker.cpp:
+	Refactor marker writing. Record marker comments in WAVE files.
+
+2012-07-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Setup.cpp:
+	Fix array overrun in afInitFileFormat().
+
+2012-07-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/query.cpp, test/Makefile.am, test/Query.cpp:
+	Fix handling of queries for unimplemented compression formats.
+
+2012-07-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AudioFormat.cpp, libaudiofile/compression.cpp,
+	libaudiofile/compression.h, libaudiofile/debug.cpp,
+	libaudiofile/modules/ModuleState.cpp, libaudiofile/query.cpp,
+	libaudiofile/util.cpp:
+	Refactor accessing compression units by compression type.
+
+2012-07-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/compression.cpp, libaudiofile/format.cpp,
+	libaudiofile/modules/ModuleState.cpp, libaudiofile/openclose.cpp,
+	libaudiofile/query.cpp, libaudiofile/units.cpp,
+	libaudiofile/units.h:
+	Remove leading underscores from _Unit and _CompressionUnit types.
+
+2012-07-31  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/ModuleState.cpp:
+	Improve error handling in ModuleState::arrange().
+
+2012-07-26  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp, libaudiofile/NeXT.cpp,
+	libaudiofile/Setup.cpp, libaudiofile/WAVE.cpp,
+	libaudiofile/format.cpp, libaudiofile/modules/G711.cpp,
+	libaudiofile/modules/IMA.cpp, libaudiofile/modules/PCM.cpp:
+	Remove unnecessary debugging print statements.
+
+2012-07-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/RebufferModule.cpp,
+	libaudiofile/modules/UT_RebufferModule.cpp:
+	Fix error in rebuffer module when buffering after pulling a short chunk.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/SampleVision.cpp, libaudiofile/compression.cpp:
+	Report an error when initializing a file with an invalid compression format.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* test/InvalidCompressionFormat.cpp, test/Makefile.am:
+	Add test for creating audio files with invalid compression formats.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp, libaudiofile/AIFF.h:
+	Refactor discrimination between AIFF and AIFF-C.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* Prefix member variables with 'm_'.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* Mark default file setup structures as constant.
+
+2012-07-14  Michael Pruett <michael@68k.org>
+
+	* Refactor file handle initialization.
+
+2012-07-05  Michael Pruett <michael@68k.org>
+
+	* docs/sfconvert.1.txt, sfcommands/sfconvert.c:
+	Add support for compression to sfconvert.
+
+2012-07-05  Michael Pruett <michael@68k.org>
+
+	* docs/afInitCompression.3.txt,
+	libaudiofile/WAVE.cpp,
+	libaudiofile/WAVE.h,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/MSADPCM.h,
+	libaudiofile/units.cpp,
+	test/ADPCM.cpp:
+	Implement Microsoft ADPCM encoding for WAVE files.
+
+2012-07-05  Michael Pruett <michael@68k.org>
+
+	* docs/afInitCompression.3.txt,
+	libaudiofile/AIFF.cpp,
+	libaudiofile/AIFF.h,
+	libaudiofile/CAF.cpp,
+	libaudiofile/CAF.h,
+	libaudiofile/WAVE.cpp,
+	libaudiofile/WAVE.h,
+	libaudiofile/afinternal.h,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/IMA.h,
+	libaudiofile/modules/Makefile.am,
+	libaudiofile/units.cpp,
+	test/ADPCM.cpp,
+	test/Makefile.am:
+	Implement IMA ADPCM encoding and decoding for AIFF-C, CAF, and WAVE files.
+
+2012-07-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AudioFormat.h,
+	libaudiofile/WAVE.cpp,
+	libaudiofile/afinternal.h,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp:
+	Add framesPerPacket and bytesPerPacket fields to AudioFormat.
+
+2012-07-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/data.cpp, libaudiofile/modules/Module.h:
+	Fix mismatched deallocation of temporary buffer in afReadFrames.
+
+2012-07-01  Michael Pruett <michael@68k.org>
+
+	* sfcommands/sfconvert.c: Improve error handling in sfconvert.
+
+2012-07-01  Michael Pruett <michael@68k.org>
+
+	* sfcommands/Makefile.am, sfcommands/sfconvert.c:
+	Clean up sfconvert.
+
+2012-07-01  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/FileModule.cpp,
+	libaudiofile/modules/FileModule.h,
+	libaudiofile/modules/G711.cpp,
+	libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp,
+	libaudiofile/modules/PCM.cpp:
+	Refactor error reporting in file modules.
+
+2012-06-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/SampleVision.cpp: Fix comparisons between signed
+	and unsigned integers.
+
+2012-06-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp, libaudiofile/IFF.cpp,
+	libaudiofile/WAVE.cpp, libaudiofile/modules/MSADPCM.cpp:
+	Remove unused variables.
+
+2012-06-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AVR.cpp, libaudiofile/Marker.cpp,
+	libaudiofile/NIST.cpp, libaudiofile/NeXT.cpp,
+	libaudiofile/Setup.cpp, libaudiofile/error.h,
+	libaudiofile/modules/G711.cpp, libaudiofile/modules/IMA.cpp,
+	libaudiofile/modules/MSADPCM.cpp, libaudiofile/modules/PCM.cpp:
+	Fix conversion specifications in error messages.
+
+2012-06-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/ModuleState.cpp,
+	libaudiofile/modules/RebufferModule.cpp,
+	libaudiofile/modules/RebufferModule.h
+	libaudiofile/modules/UT_RebufferModule.cpp:
+	Refactor rebuffer module.
+
+2012-05-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/RebufferModule.cpp: Fix error in rebuffering
+	when pulling multiple blocks at once.
+
+2012-05-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am,
+	libaudiofile/modules/UT_RebufferModule.cpp: Add unit test for
+	rebuffer module.
+
+2012-05-20  Michael Pruett <michael@68k.org>
+
+	* Move Google Test framework to top of source tree.
+
+2012-05-20  Michael Pruett <michael@68k.org>
+
+	* Reorganize code coverage build configuration.
+
+2012-05-10  Michael Pruett <michael@68k.org>
+
+	* docs/*: Update documentation.
+
+2012-05-06  Michael Pruett <michael@68k.org>
+
+	* docs/sfconvert.1.txt, sfcommands/sfconvert.c: Add support for
+	Sample Vision to sfconvert.
+
+2012-05-06  Michael Pruett <michael@68k.org>
+
+	* Update documentation to include support for Sample Vision.
+
+2012-05-06  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/VOC.cpp: Report an error when initializing a VOC file
+	with an invalid sample format.
+
+2012-05-06  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/InvalidSampleFormat.cpp: Add test for
+	creating audio files with invalid sample formats.
+
+2012-05-06  Michael Pruett <michael@68k.org>
+
+	* Reorganize tests.
+
+2012-04-30  Michael Pruett <michael@68k.org>
+
+	* Release version 0.3.4 of the Audio File Library.
+
+2012-04-29  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/pipe.cpp: Add test for reading and writing
+	with non-seekable file handles.
+
+2012-04-29  Michael Pruett <michael@68k.org>
+
+	* Add support for SampleVision format.
+
+2012-04-29  Michael Pruett <michael@68k.org>
+
+	* sfcommands/printinfo.c: Fix field width for sample rate when
+	printing short information.
+
+2012-04-29  Michael Pruett <michael@68k.org>
+
+	* examples/alsaplay.cpp: Update alsaplay to wait for samples to
+	finish playing before closing.
+
+2012-04-18  Michael Pruett <michael@68k.org>
+
+	* Use hidden visibility for internal symbols.
+
+	Previously all symbols had default visibility, leading to possible symbol
+	conflicts. Thanks to Thomas Eschenbacher for pointing out this problem.
+
+2012-01-17  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/extended.c: Update license for extended-precision
+	floating-point conversion routines.
+
+2012-01-11  Michael Pruett <michael@68k.org>
+
+	* Release version 0.3.3 of the Audio File Library.
+
+2012-01-11  Michael Pruett <michael@68k.org>
+
+	* configure.ac: Update library's soname version.
+
+	Changing the definitions of AFframecount and AFfileoffset breaks
+	backwards binary compatibility and requires incrementing the
+	soname version.
+
+2012-01-11  Michael <kensington@astralcloak.net>
+
+	* examples/Makefile.am, test/Makefile.am: Link examples/power
+	and test/printmarkers explicitly against libm.
+
+2012-01-11  Matthias Rampke <matthias@rampke.de>
+
+	* libaudiofile/Makefile.am: Link against libm.
+
+2011-12-04  Michael Pruett <michael@68k.org>
+
+	* Refactor file handle and track creation and destruction.
+
+2001-11-30  Thomas Klausner <wiz@NetBSD.org>
+
+	* configure.ac: Replace nonstandard '==' operator with '=' in test
+	expressions.
+
+2011-11-29  Michael Pruett <michael@68k.org>
+
+	* Release version 0.3.2 of the Audio File Library.
+
+2011-11-28  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/VOC.cpp: Fix initialization of byte order in
+	Creative Voice File format.
+
+2011-10-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/NIST.cpp: Fix calculation of frame count in NIST
+	SPHERE sound files.
+
+2011-10-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/byteorder.h: Remove unused byte-swapping macros.
+
+2011-10-20  Michael Pruett <michael@68k.org>
+
+	* Simplify calculation of track data size.
+
+2011-10-11  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/af_vfs.h: Remove duplicate definition of AFvirtualfile.
+
+2011-09-19  Michael Pruett <michael@68k.org>
+
+	* Don't treat compiler warnings as errors by default.
+
+2011-09-18  Michael Pruett <michael@68k.org>
+
+	* Released version 0.3.1 of the Audio File Library.
+
+2011-09-17  Michael Pruett <michael@68k.org>
+
+	* Support u-law and A-law compression in Core Audio Format files.
+
+2011-09-17  Michael Pruett <michael@68k.org>
+
+	* Add support for Creative Voice File format.
+
+2011-09-14  Michael Pruett <michael@68k.org>
+
+	* docs/Makefile.am: Fix installation of man pages.
+
+2011-09-14  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/channelmatrix.cpp: Add test for channel
+	matrix.
+
+2011-09-12  Michael Pruett <michael@68k.org>
+
+	* Released version 0.3.0 of the Audio File Library.
+
+2011-09-11  Michael Pruett <michael@68k.org>
+
+	* Define AFframecount and AFfileoffset as 64-bit signed integers.
+
+	Previously these types were defined using off_t, whose size can vary
+	depending upon whether large file support is enabled. Now the library
+	is built with large file support and the API uses 64-bit frame counts
+	and file offsets.
+
+2011-08-20  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/aes.cpp: Add test for reading and writing
+	AES channel data.
+
+2011-08-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/AIFF.cpp, libaudiofile/Instrument.cpp,
+	libaudiofile/Instrument.h, libaudiofile/Loop.cpp,
+	libaudiofile/Setup.cpp, libaudiofile/Setup.h, test/Makefile.am,
+	test/loop.cpp: Fix initialization of loop data.
+
+2011-08-16  Michael Pruett <michael@68k.org>
+
+	* win32: Remove obsolete Windows project files.
+
+2011-05-07  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am,  libaudiofile/WAVE.{cpp,h},
+	libaudiofile/UUID.{cpp,h}: Add support for extensible WAVE format.
+
+2011-04-16  Michael Pruett <michael@68k.org>
+
+	* Refactor file parsing and writing. Update VFS interface.
+
+2011-04-11  Michael Pruett <michael@68k.org>
+
+	* Reorganize source files.
+
+2011-04-11  Michael Pruett <michael@68k.org>
+
+	* Support more sample formats in IRCAM sound files.
+
+2011-04-04  Michael Pruett <michael@68k.org>
+
+	* Add support for Core Audio Format.
+
+2011-04-04  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/IRCAM.cpp, libaudiofile/IRCAM.h,
+	libaudiofile/IRCAMWrite.cpp: Handle byte-swapped IRCAM sound files.
+
+2011-04-04  Michael Pruett <michael@68k.org>
+
+	* test/pcmdata.cpp, test/Makefile.am: Test reading and writing
+	PCM data formats supported by each file format.
+
+2011-03-29  Michael Pruett <michael@68k.org>
+
+	* test/large.cpp, test/seek.cpp, test/Makefile.am: Convert large
+	and seek test cases to use Google Test framework.
+
+2011-03-27  Michael Pruett <michael@68k.org>
+
+	* docs/*: Update documentation and convert to AsciiDoc format.
+
+2011-03-27  Michael Pruett <michael@68k.org>
+
+	* sfcommands/sfconvert.c: Update help message for sfconvert to
+	include NIST SPHERE format.
+
+2011-03-27  Michael Pruett <michael@68k.org>
+
+	* sfcommands/sfconvert.c, sfcommands/sfinfo.c,
+	sfcommands/printinfo.[ch]: Add --short and --reporterror options
+	to sfinfo. Add --help and --version options to sfconvert and
+	sfinfo.
+
+2011-03-27  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/NeXT.cpp, test/Makefile.am, test/next.cpp: Fix handling
+	of NeXT sound files with unspecified or inconsistent length.
+
+2011-01-16  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/audiofile.h, libaudiofile/Loop.cpp,
+	libaudiofile/Marker.cpp, libaudiofile/Miscellaneous.cpp,
+	libaudiofile/Track.cpp, libaudiofile/util.cpp, libaudiofile/util.h:
+	Change type of id arrays in initialization functions from int *
+	to const int *.
+
+2011-01-16  Michael Pruett <michael@68k.org>
+
+	* Refactor file parsing and writing.
+
+2011-01-12  Stefano Magni <stefano.magni@akerue.it>
+
+	* libaudiofile/openclose.cpp: Fix leak of miscellaneous data buffers.
+
+2011-01-12  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/IFF.cpp: Allow writing miscellaneous data in IFF/8SVX files.
+
+2011-01-12  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/miscellaneous.cpp: Add test for reading and
+	writing miscellaneous data.
+
+2011-01-12  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/audiofile.h, libaudiofile/Miscellaneous.cpp: Change
+	type of buffer parameter of afWriteMisc() from void * to const void *.
+
+2011-01-09  Michael Pruett <michael@68k.org>
+
+	* configure.ac, test/Makefile.am: Support running tests under Valgrind.
+
+2011-01-01  Michael Pruett <michael@68k.org>
+
+	Convert library implementation to C++; refactor file parsing and writing.
+
+2010-12-02  Michael Pruett <michael@68k.org>
+
+	Use local copy of Google Test framework.
+
+2010-11-29  Michael Pruett <michael@68k.org>
+
+	Refactor rebuffering module.
+
+2010-11-14  Michael Pruett <michael@68k.org>
+
+	Refactor audio conversion.
+
+2010-11-14  Michael Pruett <michael@68k.org>
+
+	Refactor file I/O.
+
+	Eliminate VFS interface since it cannot support large files or provide
+	context for handling error conditions.
+
+2010-10-30  Michael Pruett <michael@68k.org>
+
+	* examples/Makefile.am, examples/alsaplay.cpp: Add example
+	program demonstrating audio file playback using ALSA.
+
+2010-10-30  Michael Pruett <michael@68k.org>
+
+	* test/floattoint.cpp, test/inttofloat.cpp, test/pcmmapping.cpp,
+	test/sign.cpp: Add tests for converting between integer and
+	floating-point audio data, between signed and unsigned integer
+	audio data, and between audio data with different PCM mappings.
+
+2010-09-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/pcm.h, test/floatto24.c: Update default mapping
+	between floating-point and integer audio data.
+
+	Map N-bit integer audio data to [-1, 1) rather than the previous
+	range of [-1 - 1/(2^N - 1), 1].
+
+2010-09-11  Michael Pruett <michael@68k.org>
+
+	* configure.ac, Makefile.am, libaudiofile/Makefile.am,
+	libaudiofile/modules/Makefile.am, test/Makefile.am: Enable code
+	coverage reporting with lcov.
+
+2010-09-11  Michael Pruett <michael@68k.org>
+
+	* audiofile-config.in, audiofile.m4: Remove configuration files
+	superseded by pkg-config.
+
+2010-04-14  Brian Cameron <brian.cameron@oracle.com>
+
+	* audiofile-uninstalled.pc.in, configure.ac: Add uninstalled
+	pkg-config file.
+
+2010-03-29  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/af_vfs.h: Specify C linkage.
+
+2010-03-25  Daniel Kobras <kobras@debian.org>
+
+	* libaudiofile/af_vfs.h: Include <audiofile.h>.
+
+2010-03-25  Daniel Kobras <kobras@debian.org>
+
+	* audiofile.pc.in: Link against libm only for static builds.
+
+2010-03-21  Michael Pruett <michael@68k.org>
+
+	* Released version 0.2.7 of the Audio File Library.
+
+2010-03-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/wavewrite.c: Write fact chunk in WAVE files
+	with floating-point audio data.
+
+2010-03-21  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
+	libaudiofile/iff.c, libaudiofile/iffwrite.c,
+	libaudiofile/util.c, libaudiofile/util.h, libaudiofile/wave.c,
+	libaudiofile/wavewrite.c: Add convenience functions for reading
+	and writing bytes and Pascal strings.
+
+2010-03-18  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/wave.c, libaudiofile/wavewrite.c: Add support
+	for writing double-precision floating-point WAVE files.
+
+	* test/Makefile.am, test/testdouble.c: Add test for reading and
+	writing double-precision floating-point audio files.
+
+2010-03-18  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiffwrite.c, libaudiofile/avr.c, libaudiofile/ircam.c,
+	libaudiofile/next.c, libaudiofile/raw.c, libaudiofile/wave.c,
+	libaudiofile/wavewrite.c: Fix handling of audio files with more than
+	2^24 frames.
+
+	* test/Makefile.am, test/large.c: Add test for reading and writing
+	audio files with more than 2^24 frames.
+
+2010-03-17  Michael Pruett <michael@68k.org>
+
+	* Mark module function tables as constant.
+
+2010-03-17  Jason Allen <lorddut@gmail.com>
+
+	* Mark data as constant in order to minimize unshared data.
+
+2010-03-16  Michael Pruett <michael@68k.org>
+
+	* Use C99 bool type.
+
+2010-03-16  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/afinternal.h, libaudiofile/modules/adpcm.c,
+	libaudiofile/modules/adpcm.h, libaudiofile/modules/ima.c,
+	libaudiofile/modules/msadpcm.c, libaudiofile/wave.c: Fix decoding
+	of multi-channel ADPCM audio files.
+
+2010-03-15  Michael Pruett <michael@68k.org>
+
+	* Use C99 integer types.
+
+2010-03-12  Wim Lewis <wiml@omnigroup.com>
+
+	* libaudiofile/debug.c, libaudiofile/modules/msadpcm.c,
+	libaudiofile/modules/ima.c, libaudiofile/wavewrite.c,
+	libaudiofile/query.c: Remove unused variables and fix warnings.
+
+2004-11-14  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiff.c: Add support for reading more nonstandard
+	uncompressed two's complement AIFF-C files created by Mac OS X.
+
+2004-09-14  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiff.c: Add support for reading nonstandard
+	uncompressed AIFF-C files created by Mac OS X.
+
+2004-07-21  Michael Pruett <michael@68k.org>
+
+	* examples/power.c: Change invocations of 'abs' to 'fabs' since
+	arguments are doubles.
+
+	* sfcommands/sfconvert.c: Add support for converting to the NIST
+	SPHERE file format.
+
+2004-06-26  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiff.c, libaudiofile/aiff.h, libaudiofile/aiffwrite.c,
+	libaudiofile/next.c, libaudiofile/nextwrite.c, libaudiofile/wave.c,
+	libaudiofile/wavewrite.c: Clean up AIFF, WAVE, and NeXT file parsing
+	and writing code by using af_{read,write}_uint{16,32}_{be,le} where
+	appropriate.
+
+2004-04-14  Michael Pruett <michael@68k.org>
+
+	* configure.in: Update configure.in to conform to current
+	autoconf conventions.
+
+	Thanks to Nico Roeser for this patch.
+
+2004-03-29  Michael Pruett <michael@68k.org>
+
+	* docs/*: Update documentation.
+
+2004-03-11  Michael Pruett <michael@68k.org>
+
+	* audiofile.m4: Quote AM_PATH_AUDIOFILE in order to fix
+	automake warning.
+
+	* libaudiofile/Makefile.am: Prepend audiofile.exports with
+	$(srcdir) in order to allow building from another directory.
+
+	Thanks to Frederic L. W. Meunier for these fixes.
+
+	* libaudiofile/audiofile.exports: Add VFS functions to list of
+	exported symbols.
+
+	Thanks to Daniel Kobras for pointing out this omission.
+
+2004-03-05  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am, libaudiofile/audiofile.exports:
+	Export only public entry points.
+
+	* Released version 0.2.6 of the Audio File Library.
+
+2004-02-19  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/audiofile.h: Update comments to reflect the fact
+	that AVR and IFF/8SVX file formats are now implemented.
+
+2004-02-18  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/writeavr.c. test/writeiff.c,
+	test/writenist.c: Add regression tests for AVR, IFF/8SVX, and
+	NIST SPHERE file formats.
+
+2004-02-14  Michael Pruett <michael@68k.org>
+
+	* configure.in, examples/Makefile.am, examples/osxplay.c: Add
+	example program for Mac OS X demonstrating audio file playback
+	using the Audio File Library and Core Audio.
+
+2004-02-09  Michael Pruett <michael@68k.org>
+
+	Fabrizio Gennari has contributed several Windows-related fixes:
+
+	* libaudiofile/openclose.c, win32/config.h: Open files with
+	binary translation mode under MinGW and Cygwin.
+	* win32/sfinfo.dsp: Link against non-debug version of libaudiofile
+	when building non-debug version of sfinfo.
+	* win32/*: Sychronize MSVC project files with latest source code.
+
+2004-01-27  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/afinternal.h, libaudiofile/openclose.c: Store
+	file name in AFfilehandle structure.
+
+	* libaudiofile/Makefile.am, libaudiofile/avr.c,
+	libaudiofile/avr.h, libaudiofile/avrwrite.c,
+	libaudiofile/units.c: Add support for reading and writing AVR
+	files.
+
+2004-01-22  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/util.[ch]: Add functions for reading and writing
+	16-bit and 32-bit integers with specified byte order.
+
+	* libaudiofile/Makefile.am, libaudiofile/iff.c,
+	libaudiofile/iff.h, libaudiofile/iffwrite.c,
+	libaudiofile/units.c: Add support for reading and writing
+	IFF/8SVX files.
+
+2004-01-15  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am, libaudiofile/nist.c,
+	libaudiofile/nist.h, libaudiofile/nistwrite.c: Add support for
+	reading and writing NIST SPHERE files.
+
+	* libaudiofile/audiofile.h: Add constants for new file
+	formats.
+
+	* libaudiofile/units.c, libaudiofile/units.h: Define units for
+	new file formats.
+
+2004-01-12  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/Makefile.am, libaudiofile/util.[ch],
+	libaudiofile/debug.[ch]: Move debugging routines into a
+	separate file.
+
+	* libaudiofile/modules.c: Include "debug.h" for debugging
+	routines.
+
+2004-01-06  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/afinternal.h, libaudiofile/aiff.h,
+	libaudiofile/aiffwrite.c: Eliminate duplicate definition of
+	AIFC_VERSION_1 constant.
+
+2003-12-21  Michael Pruett <michael@68k.org>
+
+	* Released version 0.2.5 of the Audio File Library.
+
+2003-12-20  Michael Pruett <michael@68k.org>
+
+	* test/seek.c: Delete temporary file before exiting.
+
+2003-12-17  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/aiff.c: When reading an AIFF-C file with an
+	unknown compression type, return an error.
+
+	* libaudiofile/aiff.c: Skip zero-length miscellaneous chunks.
+
+	* libaudiofile/aiff.c: Add support for reading AIFF-C files with
+	little-endian audio data.
+
+2003-12-17  Michael Pruett <michael@68k.org>
+
+	Fix two bugs related to processing 24-bit audio data.
+
+	* libaudiofile/data.c: Fix calculation of bytes per virtual frame
+	in the case of 24-bit audio data.  Previously, requesting more
+	than _AF_ATOMIC_NVFRAMES from afReadFrames when reading a 24-bit
+	audio file would result in corrupted audio data since the audio
+	data pointer would be incremented using a sample size of 3 bytes
+	rather than 4 bytes.
+
+	* libaudiofile/openclose.c: Set virtual sample width by default to
+	the same value as file sample width.  Previously for 24-bit audio
+	data, the virtual sample width would be incorrectly set to 32.
+
+	* test/twentyfour2.c: Add new test which checks reading and
+	writing a large amount of 24-bit audio data.  This program
+	serves as a regression test for a bug in the Audio File Library
+	in which requesting more than 1024 frames (_AF_ATOMIC_NVFRAMES)
+	from afReadFrames when reading a 24-bit audio file would result
+	in corrupted audio data.
+
+2003-12-08  Michael Pruett <michael@68k.org>
+
+	* examples/*, test/*: Add examples subdirectory. Separate
+	example programs from regression test programs. Remove obsolete
+	test programs.
+
+2003-12-03  Michael Pruett <michael@68k.org>
+
+	* sfcommands/sfconvert.c: Fix argument parsing in sfconvert.
+	* sfcommands/printinfo.c: Fix format strings to handle different
+	sizes of off_t when printing track byte count, data offset,
+	and frame count.
+
+2003-10-01  Michael Pruett <michael@68k.org>
+
+	* sfcommands/printinfo.c: Change printfileinfo to display duration
+	with millisecond accuracy.
+
+2003-09-29  Michael Pruett <michael@68k.org>
+
+	* test/seek.c: Include <string.h> for memcmp.  Thanks to Christian
+	Weisgerber for catching this omission.
+
+2003-09-25  Michael Pruett <michael@68k.org>
+
+	* Released version 0.2.4 of the Audio File Library.
+
+2003-09-24  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/afinternal.h: Remove unused structure definitions.
+	* libaudiofile/audiofile.h: Correct return type of afTellFrame
+	to be AFframecount rather than AFfileoffset.
+
+2003-09-23  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/modules/ima.c: Include <config.h>.
+
+2003-09-16  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/audiofile.h: Define LIBAUDIOFILE_MICRO_VERSION.
+
+2003-09-15  Michael Pruett <michael@68k.org>
+
+	* test/Makefile.am, test/seek.c: Add test case for seeking within
+	an audio file.
+
+2003-09-11  Michael Pruett <michael@68k.org>
+
+	* test/*.c: Update tests to use exit(EXIT_FAILURE) upon abnormal
+	termination.
+
+2003-09-11  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/wave.c, libaudiofile/wavewrite.c: Add support
+	for miscellaneous data in WAVE files.  Thanks to Davy Durham
+	for this patch.
+
+	* test/{misc.sh,miscread.c,miscwrite.c}: Update miscellaneous
+	data tests to support WAVE as well as AIFF.
+
+2003-09-11  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/*.c: Replace use of off_t with AFfileoffset and
+	AFframecount, as appropriate.
+	* configure.in: Add AC_SYS_LARGEFILE in order to support large
+	files.
+
+2003-09-09  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/*.c: Include <config.h> as necessary.
+
+2003-09-08  Michael Pruett <michael@68k.org>
+
+	* test/*.c: Update test programs to include <config.h> as necessary.
+
+2003-09-04  Michael Pruett <michael@68k.org>
+
+	* configure.in, libaudiofile/{aiff.c,aiff.h,aiffwrite.c},
+	libaudiofile/{ircam.c,ircamwrite.c}, libaudiofile/modules.h,
+	libaudiofile/{next.c,nextwrite.c}, libaudiofile/nist.c,
+	libaudiofile/{wave.c,wavewrite.c}, libaudiofile/modules/adpcm.h,
+	test/{pipe.c,sixteen-to-eight.c,twentyfour.c}: Check for
+	<inttypes.h> and include it if available.
+
+	Thanks to Daniel Bergstrom for proposing this change.
+
+2003-08-21  Michael Pruett <mpruett@sgi.com>
+
+	* configure.in, Makefile.am, win32/Makefile.am: Include win32
+	directory in distribution.
+
+2003-07-02  Michael Pruett <mpruett@sgi.com>
+
+	* test/testchannelmatrix.c, test/Makefile.am: Add regression
+	test for channel matrix functionality.
+
+2003-07-01  Michael Pruett <mpruett@sgi.com>
+
+	Applying a patch from Masahiro Sakai to enable building as a
+	DLL under Cygwin.
+
+	* configure.in: Add AC_LIBTOOL_WIN32_DLL and call
+	AM_PROG_LIBTOOL after AC_PROG_CC.
+	* libaudiofile/Makefile.am: Add -no-undefined to
+	libaudiofile_la_LDFLAGS.
+
+2003-06-10  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/format.c: Fix error in channel matrix
+	initialization.  Thanks to Jasmin Frenette for reporting this
+	problem.
+
+2002-09-11  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/raw.c: Account for data offset when calculating
+	frame count on raw audio data files.
+
+	Thanks to Davy Durham for reporting this problem.
+
+	* test/writeraw.c, test/Makefile.am: Add a regression test for
+	raw audio data files.
+
+2002-05-17  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/wave.c: Add support for reading names of markers
+	in WAVE files.  Locations of WAVE markers are now assumed to be
+	in units of frames as is the case with Sound Forge.
+	* libaudiofile/wavewrite.c, libaudiofile/wave.h: Add support
+	for writing markers in WAVE files.
+
+	Thanks to Davy Durham for the above patches.
+
+	* libaudiofile/marker.[ch]: Change static function findMarkByID
+	to non-static _af_mark_find_by_id for use by WAVE file marker
+	code.
+
+	* test/testmarkers.c: Add a regression test for markers.
+	* test/printmarkers.c: Add a utility for printing marker
+	information.
+	* test/Makefile.am: Add testmarkers and printmarkers.
+
+2002-05-16  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/wave.c: Compute the frame count of uncompressed
+	WAVE files using double-precision floating-point arithmetic.
+
+2002-05-16  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/openclose.c: Implement afOpenVirtualFile.
+
+2002-03-24  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/marker.c: afInitMarkerComment was corrupting the
+	marker's name because it would free and allocate the marker's
+	name but write to its comment.  Thanks to Daniel Kobras and
+	Davy Durham for noticing and fixing this problem.
+
+2002-02-20  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/*: Eliminate unnecessary global symbols.  Thanks
+	to Daniel Kobras for fixing this problem.
+
+2002-02-04  Michael Pruett <mpruett@sgi.com>
+
+	* audiofile.spec.in: Add /usr/lib/libaudiofile.la and
+	/usr/lib/pkgconfig/audiofile.pc to the RPM spec file.
+
+2001-10-25  Michael Pruett <mpruett@sgi.com>
+
+	* test/irixread.c: Improve error handling.  Use proper
+	conversion specifications in printf statements.
+
+	* Makefile.am, configure.in, audiofile.pc.in: Add pkgconfig file.
+
+	* Released version 0.2.3 of the Audio File Library.
+
+2001-10-10  Michael Pruett <mpruett@sgi.com>
+
+	* test/error.c: Expanded the error test to include several more
+	library functions.
+
+	* libaudiofile/format.c: Improve error checking and add comments.
+
+2001-09-20  Michael Pruett <mpruett@sgi.com>
+
+	* test/irixread.c, test/irixtestloop.c, test/linuxtest.c:
+	Always use virtual audio format in calculations regarding audio
+	data in memory.
+
+2001-09-18  Michael Pruett <mpruett@sgi.com>
+
+	* configure.in: Bump version to 0.2.3 in anticipation of the
+	upcoming release.
+
+2001-09-08  Michael Pruett <mpruett@sgi.com>
+
+	* test/sgi.c: Replace fixed-point shift with a call to the more
+	elegant alDoubleToFixed.
+
+2001-08-29  Michael Pruett <mpruett@sgi.com>
+
+	* test/pipe.{c,sh}: Added simple test of Audio File Library
+	operation on non-seekable file handles.
+
+2001-08-28  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/openclose.c: Applied Chris Wolf's patch invoking
+	the macro SETBINARYMODE on all file pointers before handing
+	them off to the AF VFS.  This macro does nothing on non-Windows
+	systems.
+
+2001-08-27  Michael Pruett <mpruett@sgi.com>
+
+	* win32/*: Added Chris Wolf's Windows port of the Audio File Library.
+
+2001-08-24  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/error.c: Include <config.h>.
+
+	* libaudiofile/modules.c: Replacing null macro arguments with
+	the token NULLMODULEPARAM so that the module macros will work
+	with bad preprocessors.
+
+2001-08-23  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/openclose.c: Include <unistd.h> only if the
+	system has this header file.
+
+	* libaudiofile/modules/rebuffer.c: Don't define min and max if
+	they've been defined already.
+
+2001-08-23  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/modules/Makefile.am, libaudiofile/units.[ch]:
+	Added IMA and MS ADPCM compression modules.
+
+	* libaudiofile/modules/msadpcm.[ch]: Checked in MS ADPCM
+	compression module.
+
+	* libaudiofile/modules/{ima,adpcm}.[ch]: Checked in IMA
+	compression module and Stichting Mathematisch Centrum's IMA
+	reference codec.
+
+	* libaudiofile/afinternal.h: Declared new internal tokens for
+	compression parameters in PV lists.
+
+	* libaudiofile/audiofile.h: Declared constants for DV and MS
+	ADPCM compression formats.
+
+	* libaudiofile/wave.[ch]: Handle IMA and MS ADPCM compression
+	in WAVE files.
+
+	* libaudiofile/openclose.c: If a track has compression
+	parameters, deallocate them before closing the file.
+
+	* sfcommands/printinfo.c: Added support for compressed audio
+	data to sound commands.
+
+2001-08-07  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/query.c: Added support for
+	AF_QUERYTYPE_COMPRESSION.
+
+2001-08-04  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/util.c, libaudiofile/util.h: Add utility
+	routines _af_pv_getlong, _af_pv_getdouble, and _af_pv_getptr.
+
+2001-07-19  Michael Pruett <mpruett@sgi.com>
+
+	* Released version 0.2.2 of the Audio File Library.
+
+2001-07-19  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/format.c: Add afSetChannelMatrix and
+	afGetVirtualChannels.
+
+	* libaudiofile/openclose.c: Add afIdentifyFD, afIdentifyNamedFD,
+	afOpenFD, and afOpenNamedFD.
+
+2001-07-18  Michael Pruett <mpruett@sgi.com>
+
+	* sfcommands/sfconvert.c: Use a fixed-size buffer for reading
+	and writing audio data, thus reducing memory usage when
+	converting large sound files.  Add float, integer, and channels
+	keywords to sfconvert.
+
+	* docs/sfconvert: Updated documentation to reflect new
+	keywords.
+
+	* libaudiofile/setup.c: Change the default file format for
+	big-endian systems from AIFF to AIFF-C.
+
+	* libaudiofile/{data.c,audiofile.h}: Change the type of the
+	buffer parameter of afWriteFrames from void * to const void *.
+
+2001-07-12  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/{aiffwrite.c,wavewrite.c}: Since
+	_af_format_frame_size takes compression into account, compute
+	the extent of compressed and uncompressed audio data using
+	_af_format_frame_size.
+
+	* libaudiofile/wave.c: Add support for double-precision
+	floating-point WAVE files.
+
+2001-07-10  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/util.[ch]: Make _af_format_sample_size and
+	_af_format_frame_size consider compression.
+
+2001-07-09  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/aiffwrite.c: Make AIFF code handle compressed
+	data formats more cleanly.
+
+	* libaudiofile/{wave.h,wave.c,wavewrite.c}: Make WAVE code
+	handle compressed data formats more cleanly.
+
+	* test/query2.c: Print default value of instrument parameters
+	if instrument parameters are supported.
+
+	* test/{writeulaw.c,writealaw.c}: Update writeulaw and
+	writealaw to test G.711 compression in AIFF-C and WAVE files in
+	addition to NeXT .snd.
+
+2001-07-08  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/{aiff.c,aiffwrite.c}: Add support for
+	floating-point AIFF-C files.
+
+	* test/testfloat.c: Add a test for reading and writing
+	floating-point audio files.
+
+	* libaudiofile/af_vfs.[ch]: Change the virtual file read and
+	write operations to use size_t and ssize_t as read(2) and
+	write(2) do.
+
+2001-07-07  Michael Pruett <mpruett@sgi.com>
+
+	* configure.in, test/Makefile.am: Link against libaudio.so only
+	for programs which use it.
+
+2001-07-04  Michael Pruett <mpruett@sgi.com>
+
+	* test/floatto24.c: Added program to test virtual sample format
+	conversion from float to 24-bit signed integer.
+
+2001-06-28  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/pcm.c: Added afInitPCMMapping(),
+	afGetPCMMapping(), and afGetVirtualPCMMapping().
+
+2001-06-28  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/{wave.c,wavewrite.c}: Improved support for
+	floating-point WAVE files.
+
+	* libaudiofile/wave.c: Made error messages more informative for
+	currently unsupported data formats such as ADPCM and MPEG
+	audio.
+
+	* libaudiofile/wave.h: Declared additional WAVE format tag
+	constants.
+
+2001-06-28  Mark Murnane <mark.murnane@sun.com>
+
+	* libaudiofile/{openclose.c,track.c}: Included string.h to
+	ensure proper declaration of memset().
+
+	* libaudiofile/util.c: Ditto for memset(), strlen() and strcpy().
+
+	* libaudiofile/modules/g711.c: Ditto for strerror().
+
+	* sfcommands/sfconvert.c: Ditto for strcmp().
+
+2001-06-19  Michael Pruett <mpruett@sgi.com>
+
+	* test/power.c: Adding a new example program which calculates
+	the power and peak amplitudes of an audio file.  This program
+	is based on Chris Vaill's normalize.
+
+2001-06-06  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/modules.c: Fix conversion between 24-bit and
+	32-bit data formats on little-endian systems.  Thanks to Axel
+	Roebel for pointing out this problem.
+
+	* libaudiofile/aiffwrite.c:  Don't write a MARK chunk unless
+	markers are present.  Don't confuse the big-endian marker id
+	used for writing to the file with its native-endian value used
+	in calls to afGetMark*.
+
+	* test/twentyfour.c: Add a new program to test the conversion
+	between 24-bit signed integer data in a file and 32-bit signed
+	integer data in memory.
+
+2001-06-05  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/af_vfs.c: Prevent division by zero in af_fread
+	and af_fwrite when size is zero.
+
+	* libaudiofile/aiff.c: Check that the number of markers in a
+	MARK chunk is positive before allocating markers.
+
+	Thanks to Axel Roebel for pointing out both of these problems.
+
+2001-05-19  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/nist.[ch]: Checked in support for recognizing
+	NIST SPHERE files.
+
+2001-05-16  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/query.c: Backing out last change.  The file
+	format and instrument parameter selectors once again return
+	arrays of type 'int' rather than arrays of type 'long'.
+
+	Although the AUpv structure uses only long integers, the Audio
+	File Library's API uses 'int' and not 'long' when describing
+	file formats and instrument parameters.  Furthermore all
+	existing applications expect the affected query calls to return
+	arrays of int.
+
+	* test/query2.c: Expect arrays of int rather than arrays of
+	long when querying on file formats and instrument parameters.
+
+2001-05-09  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/aiffwrite.c: Fix a memory leak in WriteMARK, and
+	make WriteMARK use the afGetMark* calls rather than accessing
+	track->markers directly.
+
+	* libaudiofile/util.[ch]: Add _af_print_pvlist for debugging.
+
+2001-05-04  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/ircam.[ch]: Make a first pass at supporting the
+	IRCAM file format.
+
+2001-04-25  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/query.c: Although the documentation states that
+	certain selectors return an array of integers, the AUpv structure
+	uses only long integers.  I'm resolving the ambiguity in the
+	documentation by making such selectors return an array of long
+	integers.
+
+	This change has no impact on platforms where sizeof (int) ==
+	sizeof (long), but it makes the query system consistent on
+	platforms where the above is not the case.
+
+2001-04-23  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/wavewrite.c: Fixed a bug seen on 64-bit systems
+	in which WAVE files would be created with zero-length RIFF and
+	data chunks.  (Thanks to Wayne Price for bringing this bug to
+	my attention.)
+
+2001-04-19  Michael Pruett <mpruett@sgi.com>
+
+	* sfcommands/sfconvert.c: Make sfconvert use the sample rate of
+	the input file.
+
+2001-04-09  Michael Pruett <mpruett@sgi.com>
+
+	* Include <string.h> in source files which use string functions.
+	(Thanks to Michael Madore for pointing out this omission.)
+	* Fix calculation of file position for G.711 compression.
+	(Thanks to Bruce Forsberg for pointing out this bug.)
+	* configure.in: Check for int{8,16,32}_t and define them
+	appropriately if they are missing.
+
+2001-02-20  Michael Pruett <mpruett@sgi.com>
+
+	* Released version 0.2.1.
+	* Removed -release flag on library build.
+	* libaudiofile/*: Added some lint-style comments to clean up
+	some warnings pointed out by Jean-Francois Panisset.
+
+2000-12-15  Michael Pruett <mpruett@sgi.com>
+
+	* Released version 0.2.
+
+2000-11-01  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/*: Finished integrating the modules code.
+
+2000-10-26  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/raw.[ch]: Added support for raw file reading and
+	writing.
+
+2000-10-24  Michael Pruett <mpruett@sgi.com>
+
+	* libaudiofile/*: Cleaned up the Audio File Library and improved
+	error handling.
+
+2000-10-09  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/wave*.[ch]: WAVE format chunks can occur in any
+	order.  Processing of WAVE chunks now acts accordingly.
+	(Thanks to Michael Krause for pointing out shortcomings in the
+	previous implementation.)
+	* libaudiofile/*.[ch]: The VFS layer doesn't handle SEEK_END
+	as a valid mode for fseek; we must use af_flength instead.
+	* Removed query from the test suite as it did not handle
+	values of AU_NULL_PVLIST returned from afQuery.  (It even
+	crashes under IRIX.)
+
+2000-10-04  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/*.c: Added better error handling.
+	* libaudiofile/*.c: Added the file format unit structure,
+	updated querying accordingly.  All queries except compression
+	types are implemented.
+	* Added query and query2 to the test suite.
+
+2000-09-13  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/*.c: Added support for G.711 a-law, thanks to
+	Bruce Forsberg.
+
+1999-11-20  Michael Pruett <michael@68k.org>
+
+	* libaudiofile/*.c: Cleaning up, added afOpenFD.
+
+1999-08-21  Kjartan Maraas  <kmaraas@online.no>
+
+	* */*c: Even more warning fixes - initialize vars, add 'int' as return
+	type of a function, and include headers.
+	
+1999-08-20 Elliot Lee <sopwith@redhat.com>
+	* */*.c: More warning fixes - remove unused variables, add 'int' as return type
+	of main(), and include some more header files.
+
+1999-08-18 Anders Carlsson  <anders.carlsson@tordata.se>
+
+	* Fixed compiler warnings.
+
+1999-08-16 Elliot Lee <sopwith@redhat.com>
+	* libaudiofile/af_vfs.[ch]: Virtualize file access.
+	* libaudiofile/*.[ch]: Use the new virtualized file access routines.
+
+1999-05-09  Michael Pruett  <michael@68k.org>
+
+	* bread.c, ulaw.c: If more sample frames are requested than
+	remain in the file, limit the number of sample frames that can
+	be returned.  This bug was brought to my attention by Scott
+	Heavner.
+	* test/sgi.[ch]: These files contain SGI Audio Library routines
+	used in SGI-specific test programs.
+	* test/irixread.c, test/irixtest.c, test/irixtestloop.c: These
+	programs now use the routines contained in sgi.[ch] and are more
+	robust.
+
+1999-05-23  Raja R Harinath  <harinath@cs.umn.edu>
+
+	* test/miscread.c: Include <config.h>.
+	* test/miscwrite.c: Likewise.
+	* test/writeaiff.c: Likewise.
+	* test/writenext.c: Likewise.
+	* test/writeulaw.c: Likewise.
+	* test/writewave.c: Likewise.
+ 	  
+1999-05-09  Michael Pruett  <michael@68k.org>
+
+	* Merge in Audio File Library version 0.1.7.
+
+	* aiff.c: Fixed an obscure bug in AIFF parsing in the
+	instrument chunk parsing code.  Made AIFF parsing slightly
+	cleaner by replacing multiple-character constant comparisons
+	with memcmp and strings.
+
+	* compression.[ch]: Added support for compressed audio.
+
+	* au.c, auwrite.c, ulaw.c, g711.[ch]: Incorporated support for
+	G.711 mu-law encoding.  Currently this encoding is only available
+	for NeXT/Sun .snd/.au format files.
+
+	* audiofile.c: Virtual byte order is now set properly.
+
+	* aiff.c, audiofile.c, auwrite.c, bread.c, bwrite.c,
+	compression.c, instrument.c, loop.c, marker.c, misc.c,
+	query.c, ulaw.c: Added more error checking.
+
+	* docs/*: Documentation has been improved.
+
+	* test/*: Several simple test programs have been added as a
+	test suite.
+
+	* sfcommands/*: Fix hard-coded virtual byte order since it's
+	now set by the library.
+
+	* configure.in: Fixed platform-specific tests and detect byte
+	order at configuration time.
+
+1999-04-11  James Henstridge  <james@daa.com.au>
+
+	* audiofile.spec.in: added %{prefix}/share/aclocal/* to files
+	list for the devel package.
+
+1999-02-24  Martin Baulig  <martin@home-of-linux.org>
+
+	* configure.in (BUILD_STATIC_LIBS): New automake conditional.
+
+	* sfcommands/Makefile.am, test/Makefile.am: Only link statically
+	if we build static libraries.
+
+1999-02-22  Raja R Harinath  <harinath@cs.umn.edu>
+
+	* libaudiofile/audiofile.h (extern "C"): Remove duplicated
+	__cplusplus guards.
+
+1999-02-22  Michael Fulbright <drmike@redhat.com>
+	* Fixed spec file to be autogenerated
+
+1999-02-22  Michael Pruett  <michael@68k.org>
+	    Elliot Lee  <sopwith@redhat.com>
+
+	* */*: Merge in audiofile 0.1.6.
+	
+1999-01-20  Jeff Garzik  <jgarzik@pobox.com>
+
+	* libaudiofile/wave.c:
+	Fix newly-uncovered bug caught by Mike Bond <mike.bond@template.com>.
+
+1999-01-17  Jeff Garzik  <jgarzik@pobox.com>
+
+	* aiff.c, wave.c:
+	Replaced some [int == '1234'] comparisons with memcmp.
+
+	* aiff.h:
+	Replaced large enum value with 'const unsigned long' instead, to
+	silence ANSI C compiler warning.
+
+	* ulaw.c:
+	Converted function declarations from K&R to ANSI C, silencing a
+	(big surprise) ANSI C compiler warning.
+
+	* libaudiofile/Makefile.am:
+	Remove non-existent instrument.h, loop.h, marker.h
+
+	* sfcommands/Makefile.am:
+	Add README to EXTRA_DIST.
+
+	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
+	  libaudiofile/audiofile.c, libaudiofile/auwrite.c,
+	  libaudiofile/bread.c, libaudiofile/bwrite.c,
+	  libaudiofile/byteorder.c, libaudiofile/byteorder.h,
+	  libaudiofile/extended.c, libaudiofile/extended.h,
+	  libaudiofile/instrument.c, libaudiofile/loop.c,
+	  libaudiofile/marker.c, libaudiofile/misc.c,
+	  libaudiofile/swapblock.c, libaudiofile/swapblock.h,
+	  libaudiofile/ulaw.c, libaudiofile/ulaw.h:
+	More namespace cleanups.  Made a few functions static, several
+	more renamed to add "_af_" prefix.
+
+	* libaudiofile/instrument.h, libaudiofile/loop.h,
+	  libaudiofile/marker.h:
+	Removed because they only contained prototypes of static funcs,
+	and were included only by their implementation modules.
+
+1999-01-16  Jeff Garzik  <jgarzik@pobox.com>
+
+	* test/transparency.c:
+	Change to unsigned short to avoid Sun CC warning.
+
+	* libaudiofile/swapblock.c:
+	Changed const long to a #define, Sun CC choked on the const.
+	The definition of u_int16_t may be interfering with array
+	definitions like this one, b/c u_int16_t is a macro instead of a
+	typedef on Solaris platforms.
+
+	* acconfig.h:
+	Protected against multiple inclusion, using @TOP@ and @BOTTOM@.
+
+	* libaudiofile/afinternal.h:
+	Include config.h for u_int8_t and friends.
+
+	* libaudiofile/audiofile.h, libaudiofile/aupvlist.h:
+	Mark as extern 'c' if C++ compile.
+
+	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
+	  libaudiofile/au.c, libaudiofile/audiofile.c,
+	  libaudiofile/auwrite.c, libaudiofile/bread.c,
+	  libaudiofile/bwrite.c, libaudiofile/byteorder.c,
+	  libaudiofile/swapblock.c, libaudiofile/util.c,
+	  libaudiofile/wave.c, libaudiofile/wavewrite.c,
+	  test/miscread.c, test/miscwrite.c:
+	s/#if HAVE_CONFIG_H/#ifdef HAVE_CONFIG_H/
+
+1999-01-16  Jeff Garzik  <jgarzik@pobox.com>
+
+	* libaudiofile/afinternal.h, libaudiofile/aiff.c,
+	  libaudiofile/aiffwrite.c, libaudiofile/au.c,
+	  libaudiofile/audiofile.c, libaudiofile/auwrite.c,
+	  libaudiofile/bread.c, libaudiofile/bwrite.c,
+	  libaudiofile/error.c, libaudiofile/error.h,
+	  libaudiofile/instrument.c, libaudiofile/loop.c,
+	  libaudiofile/marker.c, libaudiofile/misc.c,
+	  libaudiofile/util.c, libaudiofile/util.h,
+	  libaudiofile/wave.c, libaudiofile/wavewrite.c:
+	Major namespace cleanups:
+	Made several functions static as warranted.
+	Renamed a some exported private functions to _af_funcname
+	to prevent collision.
+
+1999-01-16  Jeff Garzik  <jgarzik@pobox.com>
+
+	* autogen.sh configure.in acconfig.h:
+	Added AM_CONFIG_HEADER and requisite support for it.
+
+	* libaudiofile/aiff.c libaudiofile/aiffwrite.c libaudiofile/au.c
+	  libaudiofile/audiofile.c libaudiofile/auwrite.c
+	  libaudiofile/bread.c libaudiofile/bwrite.c
+	  libaudiofile/byteorder.c libaudiofile/swapblock.c
+	  libaudiofile/util.c libaudiofile/wave.c
+	  libaudiofile/wavewrite.c test/miscread.c test/miscwrite.c:
+	Conditionally include config.h.
+
+1999-01-16  Raja R Harinath  <harinath@cs.umn.edu>
+
+	* libaudiofile/error.c (afSetErrorHandler): Provide a better
+	implementation which agrees with the semantics of the variable
+	names, and usual "set_error_handler" type of functions.  (Modifies
+	a "fix" in commit: "1999-01-16  Jeff Garzik  <jgarzik@pobox.com>").
+
+1999-01-16  Jeff Garzik  <jgarzik@pobox.com>
+
+	* libaudiofile/aes.c, libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
+	  libaudiofile/au.c, libaudiofile/audiofile.c, libaudiofile/aupv.c,
+	  libaudiofile/auwrite.c, libaudiofile/bread.c, libaudiofile/bwrite.c,
+	  libaudiofile/error.c, libaudiofile/loop.c, libaudiofile/misc.c,
+	  libaudiofile/swapblock.c, libaudiofile/util.c, libaudiofile/wave.c,
+	  libaudiofile/wavewrite.c, sfcommands/printinfo.c,
+	  sfcommands/sfconvert.c, sfcommands/sfinfo.c:
+	Corrected missing-default-case, unused-var, no-return-value,
+	implicit-declaration, other gcc warnings.  Fixing those warnings
+	also fixed many bugs.
+
+	* test/adddcoffset.c, test/copy.c, test/linuxtest.c, test/miscread.c,
+	  test/miscwrite.c, test/results.c, test/transparency.c:
+	Changed main() declaration to standard one, fixed warnings.
+
+1999-01-01  Jeff Garzik  <jgarzik@pobox.com>
+
+	* libaudiofile/audiofile.h:
+	Corrected comma-in-final-element warnings.
+
+1998-12-10  Jeff Garzik  <jgarzik@pobox.com>
+
+	* tests/miscwrite.c:
+	include string.h to silence warning about strlen
+
+Tue Dec  8 21:38:08 PST 1998 Manish Singh <yosh@gimp.org>
+
+	* auto* fixes for make dist
+
+1998-12-07  Jeff Garzik  <jgarzik@pobox.com>
+
+	* LICENSE:
+	Removed.  Automake automatically adds the file COPYING to the
+	distribution, so this file is redundant.
+
+1998-12-01  Yo Ric Dude  <ricdude@ix.netcom.com>
+
+	* libaudiofile/Makefile.am, au.c, audiofile.c, audiofile.h,
+	bread.c, teach libaudiofile how to handle u-law encoded .au
+	files. NOTE: only added routines for reading files.
+
+	* libaudiofile/ulaw.c, libaudiofile/ulaw.h: u-law algorithms from 
+	http://www.itl.atr.co.jp/comp.speech/Section2/Q2.7.html.
+
+1998-10-21 Bertrand Guiheneuf <Bertrand.Guiheneuf@inria.fr>
+	* added an audiofile-config and an audiofile.m4
+	
+1998-10-17  Raja R Harinath  <harinath@cs.umn.edu>
+
+	* configure.in (u_int_{8,16,32}_t): Define these to some "natural"
+	C types if the typedefs are missing.
+
+	* libaudiofile/Makefile.am (include_HEADERS): 
+	Remove spurious empty line.
+
+Wed Oct  7 02:13:34 PDT 1998 Manish Singh <yosh@gimp.org>
+
+	* auto* stuff fixes
+
+Wed Oct  7 02:08:30 CDT 1998   Frank Belew   <frb@umr.edu>
+	
+	* added support for automake, and libtool
+
+1998-07-16  Michael Pruett  <michael@68k.org>
+
+	* Changes for the Audio File Library version 0.1.4.
+
+	AES data functions are now implemented.  They're only effective
+	whenusing the AIFF/AIFF-C formats.
+
+	Miscellaneous data functions are now implemented for the
+	AIFF/AIFF-C file formats.
+
+	The Audio File Library now uses GNU autoconf.
+
+	The Audio File Library now builds shared libraries.
+
+	Some rudimentary documentation is now included.
+
+1998-06-22  Michael Pruett  <michael@68k.org>
+
+	* Changes for the Audio File Library version 0.1.3
+
+	The Linux-specific test programs should work on all Linux
+	platforms which support audio.  (I believe this includes just
+	Linux/i386, Linux/PowerPC, and Linux/Alpha.  I may be wrong.)
+
+	The function afReadFrames now returns the proper value.
+
+	The afGetInstParams, afSetInstParams, afGetInstParamLong, and
+	afSetInstParamLong calls are now implemented to the same extent
+	that SGI's versions are.
+
+	Instrument, marker, and loop data functions are now fully
+	implemented.  I'll eventually get around to the miscellaneous data
+	functions.
+
+	The AUpvlist functions have been implemented and tested.  The
+	afQuery calls are on my list of things to implement.
+
+	A few minor bugs have been fixed.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..d4706e2
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,57 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = gtest libaudiofile sfcommands test examples docs
+
+EXTRA_DIST = \
+	ACKNOWLEDGEMENTS \
+	NOTES \
+	README \
+	TODO \
+	COPYING.GPL \
+	configure configure.ac \
+	audiofile.spec.in \
+	audiofile.pc.in \
+	audiofile-uninstalled.pc.in
+
+pkgconfig_DATA = audiofile.pc
+
+dist-hook: audiofile.spec
+	cp audiofile.spec $(distdir)
+
+if ENABLE_COVERAGE
+coverage:
+	$(MAKE) coverage-reset
+	$(MAKE) check
+	$(MAKE) coverage-report
+
+coverage-reset:
+	$(LCOV) --base-directory=@top_srcdir@ --directory @top_srcdir@/libaudiofile --zerocounters
+
+coverage-report:
+	$(LCOV) --directory @top_srcdir@/libaudiofile \
+		--capture \
+		--output-file @top_builddir@/lcov.info
+
+	$(LCOV) --directory @top_srcdir@/libaudiofile \
+		--output-file @top_builddir@/lcov.info \
+		--remove @top_builddir@/lcov.info \
+		"/usr/include/*" "gtest/*" "*/UT_*"
+
+	$(mkdir_p) @top_builddir@/coverage
+	git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`; \
+	$(GENHTML) --title "@PACKAGE@ @VERSION@ $$git_commit" \
+		--output-directory @top_builddir@/coverage @top_builddir@/lcov.info
+	@echo
+	@echo 'lcov report can be found here:'
+	@echo 'file://@abs_top_builddir@/coverage/index.html'
+	@echo
+
+clean-local:
+	-rm -rf coverage
+
+.PHONY: coverage-reset coverage coverage-report
+else
+coverage:
+	@echo "Code coverage is not enabled."
+	@exit 1
+endif
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..54f5dc7
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,53 @@
+Changes for Audio File Library version 0.3.6:
+
+* Implement FLAC and ALAC encoding and decoding.
+* Update license to LGPL 2.1.
+
+Changes for Audio File Library version 0.3.5:
+
+* Implement IMA ADPCM encoding and decoding for AIFF-C, CAF, and WAVE files.
+* Implement Microsoft ADPCM encoding for WAVE files.
+* Fix calculation of IRCAM frame size.
+* Record marker comments in WAVE files.
+* Improve validation of compressed audio formats.
+* Add support for building without documentation.
+
+Changes for Audio File Library version 0.3.4:
+
+* Use hidden visibility for internal symbols.
+* Add support for Sample Vision format.
+* Update license for extended-precision floating-point conversion routines.
+
+Changes for Audio File Library version 0.3.3:
+
+* Update library's soname version.
+* Link against libm.
+
+Changes for Audio File Library version 0.3.2:
+
+* Fix initialization of byte order in Creative Voice File format.
+* Fix calculation of frame count in NIST SPHERE sound files.
+* Remove duplicate definition of AFvirtualfile.
+* Don't treat compiler warnings as errors by default.
+
+Changes for Audio File Library version 0.3.1:
+
+* Fix installation of man pages.
+* Add support for Creative Voice File format.
+* Support u-law and A-law compression in Core Audio Format files.
+
+Changes for Audio File Library version 0.3.0:
+
+* Define AFframecount and AFfileoffset as 64-bit integers regardless of
+  whether system specifies off_t as 64 bits.
+* Added support for Core Audio Format.
+* Added support for extensible WAVE format files.
+* Fixed leak of miscellaneous data buffers. (Thanks to Stefano Magni
+  for finding and fixing this problem.)
+* Fixed default mapping between integer and floating-point audio data.
+* Fix handling of NeXT sound files with unspecified or inconsistent length.
+* Added support for miscellaneous data in IFF/8SVX files.
+* Added support for byte-swapped IRCAM sound files.
+* Refactored file parsing and writing.
+* Refactored audio conversion.
+* Updated and expanded documentation.
diff --git a/NOTES b/NOTES
new file mode 100644
index 0000000..d33c6dc
--- /dev/null
+++ b/NOTES
@@ -0,0 +1,41 @@
+Audio File Library 0.3.6
+Development Notes
+Michael Pruett <michael@68k.org>
+
+----
+
+Large file support is now enabled by default on all systems.  This change
+has no effect on systems where off_t is always 64 bits (e.g. IRIX,
+FreeBSD, NetBSD, OpenBSD, Mac OS X).
+
+Many compressed data formats are not supported.  This is currently the
+most important issue to address.
+
+Error handling is at the present quite robust, but more work can always
+be done in this area.
+
+SGI's Audio File Library on IRIX implements the following formats which
+this version of the library does not:
+
+	MPEG1 audio bitstream
+	Sound Designer II
+	SoundFont2
+
+I plan to implement some of these as time permits.  Sound Designer
+II is out of the question because of its dependency upon Macintosh
+resource forks.  Handling these files on Unix systems is simply not
+worth the effort.
+
+----
+
+This version of the Audio File Library has been tested under the following
+operating environments:
+
+	i686-pc-linux-gnu / Ubuntu 12.10 (gcc 4.7.2)
+	x86_64-pc-linux-gnu / Ubuntu 12.10 (gcc 4.7.2)
+	x86_64-pc-linux-gnu / Ubuntu 12.10 (clang 3.0)
+	armv6l-raspberrypi-linux-gnueabihf / Raspbian Wheezy (gcc 4.6.3)
+	i386-apple-darwin10.8.0 / Mac OS X 10.6.8 (gcc 4.2.1)
+	x86_64-apple-darwin10.8.0 / Mac OS X 10.6.8 (gcc 4.2.1)
+	i386-pc-freebsd9.1 / FreeBSD 9.1 (gcc 4.2.1)
+	sparc64-sun-freebsd9.1 / FreeBSD 9.1 (gcc 4.2.1)
diff --git a/README b/README
new file mode 100644
index 0000000..c90025f
--- /dev/null
+++ b/README
@@ -0,0 +1,64 @@
+Audio File Library
+Version 0.3.6
+Wednesday, 6 March 2013
+
+Copyright (C) 1998-2000, 2003-2004, 2010-2013 Michael Pruett
+Copyright (C) 2000-2001 Silicon Graphics, Inc.
+
+michael@68k.org
+http://audiofile.68k.org/
+
+----
+
+The Audio File Library handles reading and writing audio files in many
+common formats.
+
+Key goals of the Audio File Library are file format transparency and data
+format transparency. The same calls for opening a file, accessing and
+manipulating audio metadata (e.g. sample rate, sample format, textual
+information, MIDI parameters), and reading and writing sample data will
+work with any supported audio file format. Likewise, the format of the
+audio data presented to the application need not be tied to the format
+of the data contained in the file.
+
+The following file formats are currently supported:
+* AIFF/AIFF-C
+* WAVE
+* NeXT .snd/Sun .au
+* Berkeley/IRCAM/CARL Sound File
+* Audio Visual Research
+* Amiga IFF/8SVX
+* Sample Vision
+* Creative Voice File
+* NIST SPHERE
+* Core Audio Format
+* FLAC
+
+The following compression formats are currently supported:
+* G.711 mu-law and A-law
+* IMA ADPCM
+* Microsoft ADPCM
+* FLAC
+* Apple Lossless Audio Codec
+
+The Audio File Library itself is available under the GNU Lesser General
+Public License, and the programs in this package are available under the
+GNU General Public License. The two licenses are included in the files
+COPYING and COPYING.GPL, respectively.
+
+----
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA  02110-1301  USA
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..1dde488
--- /dev/null
+++ b/TODO
@@ -0,0 +1,32 @@
+Audio File Library
+To Do List
+
+Michael Pruett <michael@68k.org>
+
+Short-term
+----------
+
+Handle more compressed data formats, most importantly Ogg Vorbis.
+GSM 06.10 would also be nice.
+
+Handle sample rate conversion.
+
+More comprehensive tests should be developed to stress-test the
+library.  Tests are needed most for the following sets of functions:
+	* af{Get,Set}VirtualChannels/afSetChannelMatrix
+	* afGetSampleFormat/af{Get,Set}VirtualSampleFormat
+	* af{Get,Set}Loop{IDs,Mode,Count,Start,End,StartFrame,EndFrame,Track}
+
+Support for auxiliary data in IRCAM files (maximum amplitude, comments,
+etc.) should be added.
+
+Long-term
+---------
+
+It would be nice to support some more file formats.
+
+Add locale support for error messages.
+
+Whenever a compression format is requested, the library should scan
+through /usr/lib/audiofile/*.so to see if any DSOs support the requested
+format.
diff --git a/audiofile-uninstalled.pc.in b/audiofile-uninstalled.pc.in
new file mode 100644
index 0000000..5b6fcf9
--- /dev/null
+++ b/audiofile-uninstalled.pc.in
@@ -0,0 +1,6 @@
+Name: audiofile
+Description: audiofile
+Requires:
+Version: @VERSION@
+Libs: ${pc_top_builddir}/${pcfiledir}/libaudiofile/libaudiofile.la -lm
+Cflags: -I${pc_top_builddir}/${pcfiledir}/libaudiofile
diff --git a/audiofile.pc.in b/audiofile.pc.in
new file mode 100644
index 0000000..43c0f49
--- /dev/null
+++ b/audiofile.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: audiofile
+Description: audiofile
+Requires:
+Version: @VERSION@
+Libs: -L${libdir} -laudiofile
+Libs.private: @FLAC_LIBS@ -lm
+Cflags: -I${includedir}
diff --git a/audiofile.spec.in b/audiofile.spec.in
new file mode 100644
index 0000000..fbeefec
--- /dev/null
+++ b/audiofile.spec.in
@@ -0,0 +1,69 @@
+%define  ver     @VERSION@
+%define  RELEASE 1
+%define  rel     %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
+%define  prefix  /usr
+
+Summary: A library to handle various audio file formats.
+Name: audiofile
+Version: %ver
+Release: %rel
+Copyright: LGPL
+Group: Libraries/Sound
+Source: ftp://ftp.gnome.org/pub/GNOME/sources/audiofile/audiofile-%{PACKAGE_VERSION}.tar.gz
+URL: http://www.68k.org/~michael/audiofile/
+BuildRoot:/var/tmp/audiofile-%{PACKAGE_VERSION}-root
+Docdir: %{prefix}/doc
+Obsoletes: libaudiofile
+
+%description
+The Audio File Library provides an elegant API for accessing a variety
+of audio file formats, such as AIFF/AIFF-C, WAVE, and NeXT/Sun
+.snd/.au, in a manner independent of file and data formats.
+
+%package devel
+Summary: Library, headers, etc. to develop with the Audio File Library.
+Group: Libraries
+
+%description devel
+Library, header files, etc. for developing applications with the Audio
+File Library.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%prefix
+make $MAKE_FLAGS
+
+%install
+
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+
+#
+# makefile is broken, sets exec_prefix explicitely.
+#
+make exec_prefix=$RPM_BUILD_ROOT/%{prefix} prefix=$RPM_BUILD_ROOT/%{prefix} install 
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%changelog
+
+* Fri Nov 20 1998 Michael Fulbright <drmike@redhat.com>
+- First try at a spec file
+
+%files
+%defattr(-, root, root)
+%doc COPYING TODO README ChangeLog docs
+%{prefix}/bin/*
+%{prefix}/lib/lib*.so.*
+
+%files devel
+%defattr(-, root, root)
+%{prefix}/lib/lib*.so
+%{prefix}/lib/*.a
+%{prefix}/lib/*.la
+%{prefix}/lib/pkgconfig/*.pc
+%{prefix}/include/*
+%{prefix}/share/aclocal/*
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..c18bd7b
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+test -n "$srcdir" || srcdir=`dirname $0`
+test -n "$srcdir" || srcdir=.
+
+AUTORECONF=`which autoreconf`
+if test -z $AUTORECONF; then
+	echo "autoreconf was not found; you must install automake, autoconf,"
+	echo "and libtool to build libaudiofile."
+	exit 1
+fi
+
+rootme=`pwd`
+cd $srcdir
+autoreconf --install --verbose || exit $?
+cd $rootme
+
+$srcdir/configure "$@"
+
+echo 
+echo "Now type 'make' to compile libaudiofile."
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0628cc5
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,171 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT([audiofile], [0.3.6])
+AC_CONFIG_SRCDIR([libaudiofile/AIFF.cpp])
+
+dnl Set libtool version information.
+AUDIOFILE_VERSION_INFO=1:0:0
+AUDIOFILE_VERSION=$PACKAGE_VERSION
+
+AC_SUBST(AUDIOFILE_VERSION)
+AC_SUBST(AUDIOFILE_VERSION_INFO)
+
+AM_INIT_AUTOMAKE
+AC_CONFIG_HEADER([config.h])
+
+dnl Checks for programs.
+AC_PROG_CC_C99
+AC_PROG_CXX
+AC_PROG_INSTALL
+AM_PROG_LIBTOOL
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_BIGENDIAN
+
+dnl Enable large file support by default.
+AC_SYS_LARGEFILE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+
+dnl Set up platform specific stuff
+platform=none
+AC_MSG_CHECKING([for platform specific tests to compile])
+case "$host_os" in
+  linux*)
+    TEST_BIN="linuxtest alsaplay"
+    platform=linux
+    ;;
+  irix5* | irix6*)
+    TEST_BIN="irixread irixtestloop"
+    platform=irix
+    ;;
+  darwin*)
+    if test -e /System/Library/Frameworks/CoreAudio.framework; then
+      TEST_BIN="osxplay"
+      platform="Mac OS X"
+    fi
+    ;;
+esac
+AC_MSG_RESULT($platform)
+AC_SUBST(TEST_BIN)
+
+AC_ARG_ENABLE(werror,
+	AS_HELP_STRING([--enable-werror], [treat compiler warnings as errors]),
+	[enable_werror=$enableval],
+	[enable_werror=no])
+AM_CONDITIONAL(ENABLE_WERROR, [test "$enable_werror" = "yes"])
+
+AS_IF([test "$enable_werror" = "yes"],
+	[WERROR_CFLAGS="-Werror"
+	AC_SUBST(WERROR_CFLAGS)])
+
+AC_ARG_ENABLE(coverage,
+	AS_HELP_STRING([--enable-coverage], [enable code coverage]),
+	[enable_coverage=$enableval],
+	[enable_coverage=no])
+AM_CONDITIONAL(ENABLE_COVERAGE, [test "$enable_coverage" = "yes"])
+
+AS_IF([test "$enable_coverage" = "yes"],
+	[COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage"
+	COVERAGE_LIBS="-lgcov"
+	AC_SUBST(COVERAGE_CFLAGS)
+	AC_SUBST(COVERAGE_LIBS)
+
+	AC_PATH_PROG(LCOV, lcov, :)
+	AC_PATH_PROG(GENHTML, genhtml, :)
+	AC_SUBST(LCOV)
+	AC_SUBST(GENHTML)
+	AS_IF([test "$LCOV" = :],
+		[AC_MSG_ERROR([lcov must be installed for code coverage: http://ltp.sourceforge.net/coverage/lcov.php])]
+	)]
+)
+
+AC_ARG_ENABLE(valgrind,
+	AS_HELP_STRING([--enable-valgrind], [enable testing with Valgrind]),
+	[enable_valgrind=$enableval],
+	[enable_valgrind=no])
+AM_CONDITIONAL(ENABLE_VALGRIND, [test "$enable_valgrind" = "yes"])
+
+AS_IF([test "$enable_valgrind" = "yes"],
+	[AC_PATH_PROG(VALGRIND, valgrind, :)
+	AC_SUBST(VALGRIND)
+	AS_IF([test "$VALGRIND" = :],
+		[AC_MSG_ERROR([Could not find Valgrind.])]
+	)]
+)
+
+AC_ARG_ENABLE(docs,
+	AS_HELP_STRING([--disable-docs], [disable documentation]),
+	[enable_documentation=$enableval],
+	[enable_documentation=yes])
+
+AM_CONDITIONAL(ENABLE_DOCUMENTATION, [test "$enable_documentation" = "yes"])
+
+AS_IF([test "$enable_documentation" = "yes"],
+	[AC_PATH_PROG(A2X, a2x, :)
+	AC_PATH_PROG(ASCIIDOC, asciidoc, :)
+	AS_IF([test "$A2X" = :],
+		[AC_MSG_WARN([Could not find a2x.])]
+	)
+	AS_IF([test "$ASCIIDOC" = :],
+		[AC_MSG_WARN([Could not find asciidoc.])]
+	)]
+)
+
+AC_ARG_ENABLE(examples,
+	AS_HELP_STRING([--disable-examples], [disable examples]),
+		[enable_examples=$enableval],
+		[enable_examples=yes])
+AS_IF([test "$enable_examples" != "yes"], [TEST_BIN=""])
+
+AC_ARG_ENABLE(flac,
+	AS_HELP_STRING([--disable-flac], [disable FLAC]),
+	[enable_flac=$enableval],
+	[enable_flac=yes])
+
+PKG_PROG_PKG_CONFIG
+PKG_INSTALLDIR
+
+FLAC_CFLAGS=""
+FLAC_LIBS=""
+
+if test -n "$PKG_CONFIG" ; then
+	if test "$enable_flac" = "yes" ; then
+		PKG_CHECK_MODULES([FLAC], [flac >= 1.2.1], [ac_cv_flac=yes], [ac_cv_flac=no])
+		FLAC_CFLAGS=`echo $FLAC_CFLAGS | $SED "s:include/FLAC:include:"`
+		if test "$ac_cv_flac" = "no" ; then
+			enable_flac=no
+		fi
+	fi
+else
+	enable_flac=no
+fi
+
+AC_SUBST(FLAC_CFLAGS)
+AC_SUBST(FLAC_LIBS)
+
+AM_CONDITIONAL(ENABLE_FLAC, [test "$enable_flac" = "yes"])
+if test "$enable_flac" = "yes" ; then
+	AC_DEFINE_UNQUOTED([ENABLE_FLAC], [1], [Whether FLAC is enabled.])
+else
+	AC_DEFINE_UNQUOTED([ENABLE_FLAC], [0], [Whether FLAC is enabled.])
+fi
+
+AC_CONFIG_FILES([
+	audiofile.spec
+	audiofile.pc
+	audiofile-uninstalled.pc
+	sfcommands/Makefile
+	test/Makefile
+	gtest/Makefile
+	examples/Makefile
+	libaudiofile/Makefile
+	libaudiofile/alac/Makefile
+	libaudiofile/modules/Makefile
+	docs/Makefile
+	Makefile])
+AC_OUTPUT
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..c048af6
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,3 @@
+*.[1-8]
+*.html
+*.xml
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 0000000..327b394
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1,73 @@
+if ENABLE_DOCUMENTATION
+
+DOCS_TXT_MAN1 = \
+	sfconvert.1.txt \
+	sfinfo.1.txt
+
+DOCS_TXT_MAN3 = \
+	afCloseFile.3.txt \
+	afGetFrameCount.3.txt \
+	afGetFrameSize.3.txt \
+	afIdentifyFD.3.txt \
+	afInitAESChannelDataTo.3.txt \
+	afInitCompression.3.txt \
+	afInitFileFormat.3.txt \
+	afInitSampleFormat.3.txt \
+	afNewFileSetup.3.txt \
+	afOpenFile.3.txt \
+	afQuery.3.txt \
+	afReadFrames.3.txt \
+	afReadMisc.3.txt \
+	afSeekFrame.3.txt \
+	afSetErrorHandler.3.txt \
+	afSetVirtualSampleFormat.3.txt \
+	afWriteFrames.3.txt
+
+DOCS_TXT = $(DOCS_TXT_MAN1) $(DOCS_TXT_MAN3)
+
+EXTRA_DIST = \
+	$(DOCS_TXT) \
+	asciidoc.conf
+
+DOCS_MAN1 = $(DOCS_TXT_MAN1:.txt=)
+DOCS_MAN3 = $(DOCS_TXT_MAN3:.txt=)
+DOCS_MAN3_EXTRA = \
+	afIdentifyNamedFD.3 \
+	afInitAESChannelData.3 \
+	afInitByteOrder.3 \
+	afInitChannels.3 \
+	afInitRate.3 \
+	afGetDataOffset.3 \
+	afGetTrackBytes.3 \
+	afQueryLong.3 \
+	afQueryDouble.3 \
+	afQueryPointer.3 \
+	afSeekMisc.3 \
+	afSetVirtualByteOrder.3 \
+	afSetVirtualChannels.3 \
+	afSetVirtualPCMMapping.3 \
+	afTellFrame.3 \
+	afWriteMisc.3
+
+DOCS_HTML = $(DOCS_TXT:.txt=.html)
+
+dist_man1_MANS = $(DOCS_MAN1)
+dist_man3_MANS = $(DOCS_MAN3) $(DOCS_MAN3_EXTRA)
+
+ASCIIDOCFLAGS = -arevnumber=$(VERSION) -amansource="Audio File Library"
+A2XFLAGS = $(ASCIIDOCFLAGS) -d manpage -f manpage
+
+%.html: %.txt
+	$(ASCIIDOC) $(ASCIIDOCFLAGS) -b html4 -d manpage -f asciidoc.conf $<
+
+%.1: %.1.txt
+	$(A2X) $(A2XFLAGS) --asciidoc-opts="-f asciidoc.conf" $<
+
+%.3: %.3.txt
+	$(A2X) $(A2XFLAGS) --asciidoc-opts="-f asciidoc.conf" $<
+
+html: $(DOCS_HTML)
+
+CLEANFILES = *.1 *.3 *.html
+
+endif
diff --git a/docs/afCloseFile.3.txt b/docs/afCloseFile.3.txt
new file mode 100644
index 0000000..19b1fdd
--- /dev/null
+++ b/docs/afCloseFile.3.txt
@@ -0,0 +1,42 @@
+afCloseFile(3)
+==============
+
+NAME
+----
+afCloseFile - close an open audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  int afCloseFile(AFfilehandle file);
+
+PARAMETERS
+----------
+`file` is a valid file handle created by linkaf:afOpenFile[3].
+
+DESCRIPTION
+-----------
+`afCloseFile` closes the audio file 'file', updating the file if it was
+opened for writing.
+
+RETURN VALUE
+------------
+`afCloseFile` returns 0 if the file was closed properly and -1 if an
+error occurred while closing the file.
+
+ERRORS
+------
+`afCloseFile` can generate these possible errors:
+
+* `AF_BAD_FILEHANDLE`
+* `AF_BAD_LSEEK`
+* `AF_BAD_WRITE`
+
+SEE ALSO
+--------
+linkaf:afOpenFile[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afGetFrameCount.3.txt b/docs/afGetFrameCount.3.txt
new file mode 100644
index 0000000..431391b
--- /dev/null
+++ b/docs/afGetFrameCount.3.txt
@@ -0,0 +1,63 @@
+afGetFrameCount(3)
+==================
+
+NAME
+----
+afGetFrameCount, afGetTrackBytes, afGetDataOffset - get the total sample
+frame count, length of audio track in bytes, offset of the audio track for a
+track in an audio file
+
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFframecount afGetFrameCount (AFfilehandle file, int track);
+
+  AFfileoffset afGetTrackBytes (AFfilehandle file, int track);
+
+  AFfileoffset afGetDataOffset (AFfilehandle file, int track);
+
+
+PARAMETERS
+----------
+'file' is an audio file handle created by a previous call to
+linkaf:afOpenFile[3].
+
+'track' is an integer which specifies an audio track within 'file'.
+All supported file formats contain exactly one audio track per file,
+so the constant `AF_DEFAULT_TRACK` should always be used.
+
+
+DESCRIPTION
+-----------
+`afGetFrameCount` returns the total number of sample frames contained
+within the specified track of the specified file.
+
+Each sample frame of audio consists of a fixed number of samples
+(equal to the number of audio channels in the track. For monaural data,
+a sample frame consists of one audio sample. For stereophonic data,
+a sample frame consists of a stereo pair.
+
+`afGetTrackBytes` returns the total number of bytes of raw audio data
+(i.e., prior to decompression or conversion) in the track.
+
+`afGetDataOffset` returns the offset in bytes of the start of the audio
+data contained within the specified track of the specified file.
+
+
+RETURN VALUE
+------------
+`afGetFrameCount` returns the total number of sample frames in 'track'.
+
+`afGetTrackBytes` returns the total number of bytes of audio data
+in 'track'.
+
+`afGetDataOffset` returns the offset in bytes to the beginning of the
+audio data in 'track'.
+
+Each of these routines returns -1 in case of error.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afGetFrameSize.3.txt b/docs/afGetFrameSize.3.txt
new file mode 100644
index 0000000..f22f5c8
--- /dev/null
+++ b/docs/afGetFrameSize.3.txt
@@ -0,0 +1,46 @@
+afGetFrameSize(3)
+=================
+
+NAME
+----
+afGetFrameSize - calculate the frame size in bytes for an audio track
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  float afGetFrameSize (AFfilehandle file, int track, int expand3to4);
+
+PARAMETERS
+----------
+'file' is a valid AFfilehandle.
+
+'track' is an integer which refers to a specific audio track in the
+file.  At present no supported audio file format allows for more than
+one audio track within a file, so track should always be
+`AF_DEFAULT_TRACK`.
+
+'expand3to4' is a boolean-valued integer indicating whether frame size
+calculation will treat 24-bit data as having a size of 3 bytes or 4
+bytes.
+
+DESCRIPTION
+-----------
+`afGetFrameSize` returns the number of bytes in a frame in a given
+audio track.
+
+A sample frame consists of one or more samples.  For a monaural track,
+a sample frame will always contain one sample.  For a stereophonic
+track, a sample frame will always contain two samples, one for the left
+channel and one for the right channel.
+
+A non-zero value of 'expand3to4' should be used when calculating the
+frame size for storage in memory (since 24-bit audio data is presented
+in memory as a 4-byte sign-extended integer), while a value of zero
+should be used for calculating storage on disk where no padding is added.
+The parameter 'expand3to4' is ignored unless the specified audio track
+contains 24-bit audio data.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afIdentifyFD.3.txt b/docs/afIdentifyFD.3.txt
new file mode 100644
index 0000000..ab78d6a
--- /dev/null
+++ b/docs/afIdentifyFD.3.txt
@@ -0,0 +1,50 @@
+afIdentifyFD(3)
+===============
+
+NAME
+----
+afIdentifyFD, afIdentifyNamedFD - identify the format of a file descriptor
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  int afIdenfityFD(int fd);
+  int afIdentifyNamedFD(int fd, const char *path, int *implemented);
+
+PARAMETERS
+----------
+'fd' is a file descriptor to be examined.
+
+'path' is the path to the file to be examined.
+
+'implemented' is a pointer to an integer whose value will be set to 0 or 1
+by `afIdentifyNamedFD`.
+
+RETURN VALUE
+------------
+`afIdentifyFD` and `afIdentifyNamedFD` return an integer value indicating
+the format of the specified file. If the format could not be identified
+or if the file is not a valid audio file, the value `AF_FILE_UNKNOWN`
+is returned.
+
+DESCRIPTION
+-----------
+`afIdentifyFD` and `afIdentifyNamedFD` examine the given file descriptor
+to determine the file's format.
+
+ERRORS
+------
+`afIdentifyFD` and `afIdentifyNamedFD` can produce the following errors:
+
+`AF_BAD_READ`:: A call to `read` failed
+`AF_BAD_WRITE`:: A call to `write` failed.
+`AF_BAD_LSEEK`:: A call to `lseek` failed.
+
+SEE ALSO
+--------
+linkaf:afOpenFile[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afInitAESChannelDataTo.3.txt b/docs/afInitAESChannelDataTo.3.txt
new file mode 100644
index 0000000..4afe851
--- /dev/null
+++ b/docs/afInitAESChannelDataTo.3.txt
@@ -0,0 +1,51 @@
+afInitAESChannelDataTo(3)
+=========================
+
+NAME
+----
+afInitAESChannelDataTo, afInitAESChannelData - initialize AES non-audio
+data in an audio file setup
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  void afInitAESChannelDataTo(AFfilesetup setup, int track, int willHaveData);
+  void afInitAESChannelData(AFfilesetup setup, int track);
+
+PARAMETERS
+----------
+`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].
+
+`track` specifies a track within the audio file setup. `track` is always
+`AF_DEFAULT_TRACK` for all currently supported file formats.
+
+`willHaveData` is a boolean-valued integer indicating whether AES
+non-audio data will be present.
+
+DESCRIPTION
+-----------
+Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3]
+and a track identified by `track` (`AF_DEFAULT_TRACK` for all currently
+supported file formats), `afInitAESChannelDataTo` initializes the track to
+contain or not contain AES non-audio data. `afInitAESChannelData` behaves
+similarly but always initializes the track to contain AES non-audio data.
+
+Currently only AIFF and AIFF-C file formats can store AES non-audio data;
+this data is ignored in all other file formats.
+
+ERRORS
+------
+`afInitAESChannelDataTo` and `afInitAESChannelData` can produce the
+following errors:
+
+`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
+`AF_BAD_TRACKID`:: `track` represents an invalid track identifier.
+
+SEE ALSO
+--------
+linkaf:afNewFileSetup[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afInitCompression.3.txt b/docs/afInitCompression.3.txt
new file mode 100644
index 0000000..90adeb3
--- /dev/null
+++ b/docs/afInitCompression.3.txt
@@ -0,0 +1,57 @@
+afInitByteOrder(3)
+==================
+
+NAME
+----
+afInitCompression - initialize compression for a track in an audio
+file setup
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  void afInitCompression(AFfilesetup setup, int track, int compression);
+
+PARAMETERS
+----------
+`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].
+
+`track` specifies a track within the audio file setup. `track` is always
+`AF_DEFAULT_TRACK` for all currently supported file formats.
+
+`compression` is an identifier specifying the compression type (such as
+`AF_COMPRESSION_G711_ULAW`) to be used for audio data in the track.
+
+DESCRIPTION
+-----------
+Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3]
+and a track identified by `track` (`AF_DEFAULT_TRACK` for all currently
+supported file formats), `afInitCompression` initializes the track to
+the specified compression.
+
+The following compression types are currently supported:
+
+`AF_COMPRESSION_NONE`:: no compression
+`AF_COMPRESSION_G711_ULAW`:: CCITT G.711 mu-law encoding
+`AF_COMPRESSION_G711_ALAW`:: CCITT G.711 A-law encoding
+`AF_COMPRESSION_IMA`:: IMA ADPCM encoding
+`AF_COMPRESSION_MS_ADPCM`:: MS ADPCM encoding
+`AF_COMPRESSION_FLAC`:: FLAC
+`AF_COMPRESSION_ALAC`:: Apple Lossless Audio Codec
+
+ERRORS
+------
+`afInitCompression` can produce the following errors:
+
+`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
+`AF_BAD_TRACKID`:: `track` represents an invalid track identifier.
+`AF_BAD_COMPTYPE`:: `compression` represents an invalid compression type.
+
+SEE ALSO
+--------
+linkaf:afNewFileSetup[3],
+linkaf:afInitSampleFormat[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afInitFileFormat.3.txt b/docs/afInitFileFormat.3.txt
new file mode 100644
index 0000000..c0b020e
--- /dev/null
+++ b/docs/afInitFileFormat.3.txt
@@ -0,0 +1,56 @@
+afInitFileFormat(3)
+===================
+
+NAME
+----
+afInitFileFormat - initialize file format of an audio file setup
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  void afInitFileFormat(AFfilesetup setup, int fileFormat);
+
+PARAMETERS
+----------
+`setup` is a valid file setup created by linkaf:afNewFileSetup[3].
+
+`fileFormat` is an integer constant specifying a file format.
+
+DESCRIPTION
+-----------
+Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3],
+`afInitFileFormat` initializes the file format to that specified by
+`fileFormat`.
+
+The following file formats are currently supported:
+
+`AF_FILE_RAWDATA`:: raw audio data
+`AF_FILE_AIFF`:: Audio Interchange File Format
+`AF_FILE_AIFFC`:: Audio Interchange File Format AIFF-C
+`AF_FILE_NEXTSND`:: NeXT .snd/Sun .au
+`AF_FILE_WAVE`:: Microsoft RIFF WAVE
+`AF_FILE_BICSF`:: Berkeley/IRCAM/CARL Sound File
+`AF_FILE_AVR`:: Audio Visual Research
+`AF_FILE_IFF_8SVX`:: Amiga IFF/8SVX
+`AF_FILE_SAMPLEVISION`:: Sample Vision
+`AF_FILE_VOC`:: Creative Voice File
+`AF_FILE_NIST_SPHERE`:: NIST SPHERE
+`AF_FILE_CAF`:: Core Audio Format
+
+ERRORS
+------
+`afInitFileFormat` can produce the following errors:
+
+`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
+`AF_BAD_FILEFMT`:: `fileFormat` represents an unknown file format.
+`AF_BAD_NOT_IMPLEMENTED`:: `fileFormat` represents a file format which
+is not currently implemented.
+
+SEE ALSO
+--------
+linkaf:afNewFileSetup[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afInitSampleFormat.3.txt b/docs/afInitSampleFormat.3.txt
new file mode 100644
index 0000000..6ff1235
--- /dev/null
+++ b/docs/afInitSampleFormat.3.txt
@@ -0,0 +1,94 @@
+afInitSampleFormat(3)
+=====================
+
+NAME
+----
+afInitSampleFormat, afInitByteOrder, afInitChannels, afInitRate -
+initialize audio data format for a track in an audio file setup
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  void afInitSampleFormat(AFfilesetup setup, int track, int sampleFormat,
+      int sampleWidth);
+  void afInitByteOrder(AFfilesetup setup, int track, int byteOrder);
+  void afInitChannels(AFfilesetup setup, int track, int channels);
+  void afInitRate(AFfilesetup setup, int track, double rate);
+
+PARAMETERS
+----------
+`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].
+
+`track` specifies a track within the audio file setup. `track` is always
+`AF_DEFAULT_TRACK` for all currently supported file formats.
+
+`sampleFormat` is a symbolic constant specifying the sample format
+for the audio data in the track. `sampleFormat` must be one of
+`AF_SAMPFMT_TWOSCOMP`, `AF_SAMPFMT_UNSIGNED`, `AF_SAMPFMT_FLOAT`, or
+`AF_SAMPFMT_DOUBLE`.
+
+`sampleWidth` is a positive integer specifying the number of bits for
+each sample in the track.
+
+`byteOrder` is a symbolic constant specifying the byte order of
+the track. `byteOrder` must be one of `AF_BYTEORDER_BIGENDIAN` or
+`AF_BYTEORDER_LITTLEENDIAN`.
+
+`channels` is a positive integer specifying the number of channels in
+the track.
+
+`rate` is a positive double-precision floating-point number specifying
+the sample rate of the track.
+
+DESCRIPTION
+-----------
+`afInitSampleFormat` initializes the track to the specified sample format
+and sample width.
+
+`afInitByteOrder` initializes the track to the specified byte order.
+
+`afInitChannels` initializes the track to the specified number of channels.
+
+`afInitRate` initializes the track to the specified sample rate.
+
+ERRORS
+------
+`afInitSampleFormat`, `afInitByteOrder`, `afInitChannels`, and
+`afInitRate` can produce the following errors:
+
+[horizontal]
+`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
+`AF_BAD_TRACK`:: `track` represents an invalid track identifier.
+
+`afInitSampleFormat` can also produce the following errors:
+
+[horizontal]
+`AF_BAD_SAMPFMT`:: `sampleFormat` does not represent a valid sample format.
+`AF_BAD_WIDTH`:: `sampleWidth` is not a valid sample width.
+
+`afInitByteOrder` can also produce the following error:
+
+[horizontal]
+`AF_BAD_BYTEORDER`:: `byteOrder` does not represent a valid byte order. 
+
+`afInitChannels` can also produce the following error:
+
+[horizontal]
+`AF_BAD_CHANNELS`:: `channels` specifies an invalid number of channels.
+
+`afInitRate` can also produce the following error:
+
+[horizontal]
+`AF_BAD_RATE`:: `rate` specifies an invalid sample rate.
+
+SEE ALSO
+--------
+linkaf:afNewFileSetup[3],
+linkaf:afInitFileFormat[3],
+linkaf:afInitCompression[3],
+linkaf:afOpenFile[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afNewFileSetup.3.txt b/docs/afNewFileSetup.3.txt
new file mode 100644
index 0000000..ac660d1
--- /dev/null
+++ b/docs/afNewFileSetup.3.txt
@@ -0,0 +1,33 @@
+afNewFileSetup(3)
+=================
+
+NAME
+----
+afNewFileSetup - create and initialize a new AFfilesetup structure
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFfilesetup afNewFileSetup(void);
+
+RETURN VALUE
+------------
+`afNewFileSetup` returns, upon success, a valid AFfilesetup structure.
+
+Upon failure, `afNewFileSetup` returns a null `AFfilesetup`. This case
+should only occur when no memory is available.
+
+DESCRIPTION
+-----------
+The opaque `AFfilesetup` structure returned by `afNewFileSetup` can
+be used to specify parameters for a file to be opened for writing by
+linkaf:afOpenFile[3].
+
+SEE ALSO
+--------
+linkaf:afOpenFile[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afOpenFile.3.txt b/docs/afOpenFile.3.txt
new file mode 100644
index 0000000..4d56ab1
--- /dev/null
+++ b/docs/afOpenFile.3.txt
@@ -0,0 +1,63 @@
+afOpenFile(3)
+=============
+
+NAME
+----
+afOpenFile - open an audio file and create a file handle structure used
+for subsequent calls to the Audio File Library
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFfilehandle afOpenFile(const char *path, const char *mode,
+      AFfilesetup setup);
+
+PARAMETERS
+----------
+'path' is the path to the file to be opened.
+
+'mode' specifies a mode for opening the file: `"r"` for reading or
+`"w"` for writing.
+
+'setup' is an AFfilesetup created by linkaf:afNewFileSetup[3]. This value
+is ignored for files opened for reading except when the file format is
+`AF_FILE_RAWDATA`.
+
+RETURN VALUE
+------------
+Upon success, `afOpenFile` returns a valid `AFfilehandle` which can
+be used in subsequent calls to the Audio File Library. Upon failure,
+`afOpenFile` returns NULL and generates an error.
+
+linkaf:afCloseFile[3] is used to close the file when it is no longer
+needed.
+
+ERRORS
+------
+`afOpenFile` can produce the following errors:
+
+`AF_BAD_OPEN`:: A call to `open` failed.
+`AF_BAD_READ`:: A call to `read` failed
+`AF_BAD_WRITE`:: A call to `write` failed.
+`AF_BAD_LSEEK`:: A call to `lseek` failed.
+`AF_BAD_MALLOC`:: Memory allocation failed.
+`AF_BAD_FILEFMT`:: `setup` specifies a file format which is unsupported for `mode`.
+`AF_BAD_SAMPFMT`:: The file's sample format is not supported.
+`AF_BAD_WIDTH`:: The file's sample width is not supported.
+`AF_BAD_RATE`:: The file's sample rate is not supported.
+`AF_BAD_CHANNELS`:: The number of channels in the file is not supported.
+`AF_BAD_FILESETUP`:: `setup` specifies an invalid or unsupported configuration.
+
+SEE ALSO
+--------
+linkaf:afCloseFile[3],
+linkaf:afNewFileSetup[3],
+linkaf:afInitFileFormat[3],
+linkaf:afInitSampleFormat[3],
+linkaf:afReadFrames[3],
+linkaf:afWriteFrames[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afQuery.3.txt b/docs/afQuery.3.txt
new file mode 100644
index 0000000..70c5fe8
--- /dev/null
+++ b/docs/afQuery.3.txt
@@ -0,0 +1,124 @@
+afQuery(3)
+==========
+
+NAME
+----
+afQuery, afQueryLong, afQueryDouble, afQueryPointer - query the
+capabilities of the Audio File Library
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);
+
+  long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);
+
+  double afQueryDouble (int querytype, int arg1, int arg2, int arg3,
+      int arg4);
+
+  void *afQueryPointer (int querytype, int arg1, int arg2, int arg3,
+      int arg4);
+
+PARAMETERS
+----------
+'querytype' can be one of the following:
+
+* `AF_QUERYTYPE_FILEFMT`
+* `AF_QUERYTYPE_INST`
+* `AF_QUERYTYPE_INSTPARAM`
+* `AF_QUERYTYPE_COMPRESSION`
+* `AF_QUERYTYPE_COMPRESSIONPARAM`
+* `AF_QUERYTYPE_MISC`
+* `AF_QUERYTYPE_MARK`
+* `AF_QUERYTYPE_LOOP`
+
+'arg1', 'arg2', 'arg3', and 'arg4' are integer selectors whose
+meaning depends upon 'querytype'.
+
+
+RETURN VALUE
+------------
+Upon success, `afQuery` will return a non-null `AUpvlist` value.
+Upon failure, `afQuery` will return null while `afQueryLong` and
+`afQueryDouble` will return -1 and `afQueryPointer` will return
+null.
+
+Pointers representing character strings are owned by the Audio File
+Library and must not be freed; all other pointer values must be
+freed by the caller.
+
+DESCRIPTION
+-----------
+For `AF_QUERYTYPE_FILEFMT`, the following selectors are valid values for 'arg1':
+
+`AF_QUERY_LABEL`:: Request a short label string for the format (e.g., "aiff").
+
+`AF_QUERY_NAME`:: Request a short name for the format (e.g., "MS RIFF WAVE").
+
+`AF_QUERY_DESC`:: Request a descriptive name for the format (e.g., "Audio
+Interchange File Format").
+
+`AF_QUERY_IMPLEMENTED`:: Request a boolean value indicating whether the
+format is implemented for reading and writing in the Audio File Library.
+
+`AF_QUERY_ID_COUNT`:: Request the total number of formats implemented.
+
+`AF_QUERY_IDS`:: Request an integer array of the id token values of all
+implemented file formats.
+
+`AF_QUERY_COMPRESSION_TYPES`:: Used with the selector AF_QUERY_VALUE_COUNT
+in 'arg2', this will return a long integer containing the number of
+compression schemes available for use within the format specified in 'arg3'.
+Used with selector `AF_QUERY_VALUES`, it returns a pointer to an integer
+array containing the compression id values of the compression schemes
+supported by the format specified in 'arg3'.
+
+`AF_QUERY_SAMPLE_FORMATS`:: Used with the selector AF_QUERY_DEFAULT in 'arg2',
+this will return the default sample format for the file format specified in
+'arg3'.
+
+`AF_QUERY_SAMPLE_SIZES`:: Used with selector AF_QUERY_DEFAULT in 'arg2', this
+will return the default sample width for the file format specified in 'arg3'.
+
+
+For `AF_QUERYTYPE_INST`, the following selectors are valid for 'arg1':
+
+`AF_QUERY_SUPPORTED`:: Request a boolean value indicating whether
+the file format in 'arg2' supports instruments.
+
+`AF_QUERY_MAX_NUMBER`:: Request an integer value indicating the
+maximum number of instruments supported by the file format in 'arg2'.
+
+
+For `AF_QUERYTYPE_INSTPARAM`, the following selectors are valid for 'arg1':
+
+`AF_QUERY_SUPPORTED`:: Request a boolean value indicating whether
+the file format in 'arg2' supports instrument parameters.
+
+`AF_QUERY_ID_COUNT`:: Request an integer value indicating the number
+of instrument parameters supported by the file format in 'arg2'.
+
+`AF_QUERY_IDS`:: Request an integer array containing the instrument
+parameter values for the file format in 'arg2'.
+
+`AF_QUERY_TYPE`:: For the file format in 'arg2', request the type
+of the instrument parameter in 'arg3'.
+
+`AF_QUERY_NAME`:: For the file format in 'arg2', request the name
+of the instrument parameter in 'arg3'.
+
+`AF_QUERY_DEFAULT`:: For the file format in 'arg2', request the
+default value of the instrument parameter in 'arg3'.
+
+
+ERRORS
+------
+afQuery can produce the following errors:
+
+`AF_BAD_QUERYTYPE`:: The query type is unsupported.
+`AF_BAD_QUERY`:: The arguments to the query are bad.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afReadFrames.3.txt b/docs/afReadFrames.3.txt
new file mode 100644
index 0000000..3c080ee
--- /dev/null
+++ b/docs/afReadFrames.3.txt
@@ -0,0 +1,49 @@
+afReadFrames(3)
+===============
+
+NAME
+----
+afReadFrames - read sample frames from a track in an audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFframecount afReadFrames(AFfilehandle file, int track, void *data,
+      int count);
+
+DESCRIPTION
+-----------
+`afReadFrames` attempts to read up to 'count' frames of audio data from
+the audio file handle 'file' into the buffer at 'data'.
+
+PARAMETERS
+----------
+'file' is a valid file handle returned by linkaf:afOpenFile[3].
+
+'track' is always `AF_DEFAULT_TRACK` for all currently supported file formats.
+
+'data' is a buffer of storing 'count' frames of audio sample data.
+
+'count' is the number of sample frames to be read.
+
+RETURN VALUE
+------------
+`afReadFrames` returns the number of frames successfully read from 'file'.
+
+ERRORS
+------
+`afReadFrames` can produce these errors:
+
+`AF_BAD_FILEHANDLE`:: the file handle was invalid
+`AF_BAD_TRACKID`:: the track parameter is not `AF_DEFAULT_TRACK`
+`AF_BAD_READ`:: reading audio data from the file failed
+`AF_BAD_LSEEK`:: seeking within the file failed
+
+SEE ALSO
+--------
+linkaf:afWriteFrames[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afReadMisc.3.txt b/docs/afReadMisc.3.txt
new file mode 100644
index 0000000..b89ac41
--- /dev/null
+++ b/docs/afReadMisc.3.txt
@@ -0,0 +1,55 @@
+afReadMisc(3)
+=============
+
+NAME
+----
+afReadMisc, afWriteMisc, afSeekMisc - access miscellaneous metadata in an audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  int afReadMisc (AFfilehandle file, int miscid, void *buffer, int nbytes);
+
+  int afWriteMisc (AFfilehandle file, int miscid, const void *buffer, int nbytes);
+
+  int afSeekMisc (AFfilehandle file, int miscid, int offbytes);
+
+DESCRIPTION
+-----------
+`afReadMisc` reads up to 'nbytes' from the miscellaneous data chunk
+identified by 'miscid' in 'file'.
+
+`afWriteMisc` writes up to 'nbytes' to the miscellaneous data chunk
+identified by 'miscid' in 'file'.
+
+`afSeekMisc` changes the current offset within the miscellaneous data
+chunk identified by 'miscid' to the offset 'offbytes'.
+
+RETURN VALUE
+------------
+`afReadMisc` returns the number of bytes read from the specified
+miscellaneous chunk into the buffer referred to by 'buffer'.
+
+`afWriteMisc` returns the number of bytes written to the specified
+miscellaneous chunk from the buffer referred to by 'buffer'.
+
+`afSeekMisc` returns the new location of the logical data pointer as
+measured as an offset in bytes from the beginning of the miscellaneous
+chunk's data area.
+
+ERRORS
+------
+`afReadMisc`, `afWriteMisc`, and `afSeekMisc` can produce the following
+error codes:
+
+* `AF_BAD_READ`
+* `AF_BAD_WRITE`
+* `AF_BAD_MISCSEEK`
+* `AF_BAD_MISCID`
+* `AF_BAD_TRACKID`
+* `AF_BAD_FILEHANDLE`
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afSeekFrame.3.txt b/docs/afSeekFrame.3.txt
new file mode 100644
index 0000000..18e8261
--- /dev/null
+++ b/docs/afSeekFrame.3.txt
@@ -0,0 +1,56 @@
+afSeekFrame(3)
+==============
+
+NAME
+----
+afSeekFrame, afTellFrame - update or access the current sample frame
+position for a track in an audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFframecount afSeekFrame(AFfilehandle file, int track,
+      AFframecount frameOffset);
+
+  AFframecount afTellFrame(AFfilehandle file, int track);
+
+PARAMETERS
+----------
+'file' is a valid audio file handle created by linkaf:afOpenFile[3].
+
+'track' identifies an audio track within the file. `track` is always
+`AF_DEFAULT_TRACK` for all currently supported audio file formats.
+
+'frameOffset' is a sample frame offset. Valid sample frame offsets must
+be greater than or equal to zero and strictly less than the number of
+sample frames contained within the specified audio track. The special
+value `-1` is also allowed.
+
+DESCRIPTION
+-----------
+`afSeekFrame` moves the logical file position for a specified audio
+track to a desired sample frame location. If `frameOffset` is `-1`,
+`afSeekFrame` will not modify the current file offset and will instead
+return the current file position.
+
+`afTellFrame` returns current file position in sample frames.
+
+RETURN VALUE
+------------
+On success, `afSeekFrame` and `afTellFrame` will return the current file
+position as measured in sample frames from the start of the audio
+track. On failure, `afSeekFrame` and `afTellFrame` will return the value
+`-1`.
+
+ERRORS
+------
+The following errors can be generated by `afSeekFrame` or `afTellFrame`:
+
+`AF_BAD_FILEHANDLE`:: `file` does not represent a valid file handle.
+`AF_BAD_TRACK`:: `track` does not identify a valid track.
+`AF_BAD_LSEEK`:: A call to `lseek` failed.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afSetErrorHandler.3.txt b/docs/afSetErrorHandler.3.txt
new file mode 100644
index 0000000..f41e292
--- /dev/null
+++ b/docs/afSetErrorHandler.3.txt
@@ -0,0 +1,30 @@
+afSetErrorHandler(3)
+====================
+
+NAME
+----
+afSetErrorHandler - install a custom error handling routine
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFerrfunc afSetErrorHandler (AFerrfunc errorFunction);
+
+PARAMETERS
+----------
+'errorFunction' is a pointer to an error handling function.
+
+DESCRIPTION
+-----------
+`afSetErrorHandler` allows the user to install an error handling function
+overriding the default function.
+
+RETURN VALUE
+------------
+The value returned from `afSetErrorHandler` is a pointer to the previous
+error handling function.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afSetVirtualSampleFormat.3.txt b/docs/afSetVirtualSampleFormat.3.txt
new file mode 100644
index 0000000..766f67e
--- /dev/null
+++ b/docs/afSetVirtualSampleFormat.3.txt
@@ -0,0 +1,62 @@
+afSetVirtualSampleFormat(3)
+===========================
+
+NAME
+----
+afSetVirtualByteOrder, afSetVirtualChannels, afSetVirtualPCMMapping,
+afSetVirtualSampleFormat - set the virtual data format for a track in
+an audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  int afSetVirtualByteOrder (AFfilehandle file, int track, int byteOrder);
+
+  int afSetVirtualChannels (AFfilehandle file, int track, int channels);
+
+  int afSetVirtualSampleFormat (AFfilehandle file, int track,
+      int sampleFormat, int sampleWidth);
+
+  int afSetVirtualPCMMapping (AFfilehandle file, int track,
+      double slope, double intercept, double minclip, double maxclip);
+
+PARAMETERS
+----------
+* 'file' is an AFfilehandle which refers to an open audio file and is
+  usually created by afOpenFile.
+
+* 'track' is an integer which identifies a particular track in an open
+  audio file.  The only valid track is `AF_DEFAULT_TRACK` for all
+  currently supported file formats.
+
+* 'sampleFormat' is an integer which denotes a virtual sample format.
+  Valid values are `AF_SAMPFMT_TWOSCOMP`, `AF_SAMPFMT_UNSIGNED`,
+  `AF_SAMPFMT_FLOAT`, and `AF_SAMPFMT_DOUBLE`.
+
+* 'sampleWidth' is a positive integer which specifies the number of bits
+  in a sample.
+
+* 'channels' is a positive integer which specifies the number of
+  interleaved audio channels in the given audio track.
+
+* 'byteOrder' is an integer which specifies the virtual byte order of
+  samples in the given audio track.  'byteOrder' can be either
+  `AF_BYTEORDER_BIGENDIAN` or `AF_BYTEORDER_LITTLEENDIAN`.
+
+* 'slope' and 'intercept' are double-precision floating point values which
+  indicate the audio data sample slope and zero-crossing value,
+  respectively, for the given sample format.
+
+* 'minclip' and 'maxclip' are double-precision floating point values
+  which indicates the minimum or maximum sample values to be returned.
+  Any values less than 'minclip' will be set to 'minclip', and any values
+  greater than 'maxclip' will be set to 'maxclip'.
+
+RETURN VALUE
+------------
+These functions return 0 for success and -1 for failure.
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/afWriteFrames.3.txt b/docs/afWriteFrames.3.txt
new file mode 100644
index 0000000..393d82e
--- /dev/null
+++ b/docs/afWriteFrames.3.txt
@@ -0,0 +1,50 @@
+afWriteFrames(3)
+================
+
+NAME
+----
+afWriteFrames - write sample frames to a track in an audio file
+
+SYNOPSIS
+--------
+  #include <audiofile.h>
+
+  AFframecount afWriteFrames(AFfilehandle file, int track, const void *data,
+      AFframecount count);
+
+DESCRIPTION
+-----------
+`afWriteFrames` attempts to write up to 'count' frames of audio data
+from the buffer 'data' to the audio file handle 'file'.
+
+PARAMETERS
+----------
+'file' is a valid file handle returned by linkaf:afOpenFile[3].
+
+'track' is always `AF_DEFAULT_TRACK` for all currently supported file formats.
+
+'data' is a buffer of sample frames to be written to the file.
+
+'count' is the number of sample frames to be written.
+
+RETURN VALUE
+------------
+`afWriteFrames` returns the number of sample frames successfully written
+to 'file'.
+
+ERRORS
+------
+`afWriteFrames` can produce these errors:
+
+`AF_BAD_FILEHANDLE`:: the file handle was invalid
+`AF_BAD_TRACKID`:: the track is not `AF_DEFAULT_TRACK`
+`AF_BAD_WRITE`:: writing audio data to the file failed
+`AF_BAD_LSEEK`:: seeking within the file failed
+
+SEE ALSO
+--------
+linkaf:afReadFrames[3]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/asciidoc.conf b/docs/asciidoc.conf
new file mode 100644
index 0000000..100932f
--- /dev/null
+++ b/docs/asciidoc.conf
@@ -0,0 +1,23 @@
+#
+# Usage: linkaf:command[manpage-section]
+#
+# Note, {0} is the manpage section, while {target} is the command.
+#
+# Show Audio File Library link as: <command>(<section>); if section is
+# defined, else just show the command.
+
+[macros]
+(?su)[\\]?(?P<name>linkaf):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+ifdef::backend-docbook[]
+[linkaf-inlinemacro]
+{0%{target}}
+{0#<citerefentry>}
+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+{0#</citerefentry>}
+endif::backend-docbook[]
+
+ifdef::backend-html4[]
+[linkaf-inlinemacro]
+<a href="{target}.{0}.html">{target}({0})</a>
+endif::backend-html4[]
diff --git a/docs/sfconvert.1.txt b/docs/sfconvert.1.txt
new file mode 100644
index 0000000..c1a1284
--- /dev/null
+++ b/docs/sfconvert.1.txt
@@ -0,0 +1,70 @@
+sfconvert(1)
+============
+
+NAME
+----
+sfconvert - convert audio files
+
+SYNOPSIS
+--------
+*sfconvert* 'infile' 'outfile' ['output options']
+
+DESCRIPTION
+-----------
+The `sfconvert` command converts an audio file to another file format or data format.
+
+OPTIONS
+-------
+The following keywords specify the format of the output sound file:
+
+`format` 'f'::
+  Output file format. 'f' must be one of the following:
+[horizontal]
+    `aiff`::: Audio Interchange File Format
+    `aifc`::: AIFF-C
+    `next`::: NeXT/Sun .snd/.au Format
+    `wave`::: MS RIFF WAVE
+    `bicsf`::: Berkeley/IRCAM/CARL Sound File Format
+    `smp`::: Sample Vision Format
+    `voc`::: Creative Voice File Format
+    `nist`::: NIST SPHERE Format
+    `caf`::: Core Audio Format
+    `flac`::: FLAC
+`compression` 'c'::
+[horizontal]
+    `ulaw`::: G.711 mu-law
+    `alaw`::: G.711 A-law
+    `ima`::: IMA ADPCM
+    `msadpcm`::: Microsoft ADPCM
+    `flac`::: FLAC
+    `alac`::: Apple Lossless Audio Codec
+`byteorder` 'e'::
+  Output byte order. 'e' may be either `big` or `little`.
+`channels` 'n'::
+  Number of output channels. 'n' is 1 for mono, and 2 for stereo.
+`integer` 'n' 's'::
+  Convert to integer audio data. 'n' indicates the output sample width
+  in bits. 's' specifies the sample format and may be either `2scomp`
+  for 2's complement signed data or `unsigned` for unsigned data.
+`float` 'm'::
+  Convert to floating-point audio data with a maximum amplitude of
+  'm' (usually `1.0`). The `integer` and `float` options are mutually
+  exclusive.
+
+The following options take no additional arguments:
+
+`--help`::
+`-h`::
+Print help message.
+
+`--version`::
+`-v`::
+Print version information.
+
+SEE ALSO
+--------
+linkaf:sfinfo[1]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/docs/sfinfo.1.txt b/docs/sfinfo.1.txt
new file mode 100644
index 0000000..a8b101d
--- /dev/null
+++ b/docs/sfinfo.1.txt
@@ -0,0 +1,76 @@
+sfinfo(1)
+=========
+
+NAME
+----
+sfinfo - display information about audio files
+
+SYNOPSIS
+--------
+*sfinfo* ['options'] 'audio files'...
+
+DESCRIPTION
+-----------
+`sfinfo` prints information about the specified audio files, including
+file format, sample rate, duration, and audio data format.
+
+By default `sfinfo` displays information in a longer, multi-line format;
+specifying the --short or -s option produces a short, single-line summary.
+
+Any files which are not recognized as valid audio files will be ignored
+unless the --reporterror or -r option is given. The file formats
+currently supported by `sfinfo` are AIFF, AIFF-C, NeXT/Sun .snd/.au,
+WAVE, Berkeley/IRCAM/CARL Sound File, AVR, Amiga IFF/8SVX, Sample Vision,
+Creative Voice File, NIST SPHERE, and Core Audio Format.
+
+OPTIONS
+-------
+
+`--short`::
+`-s`::
+Print short single-line summary of each recognized audio file.
+
+`--reporterror`::
+`-r`::
+Print an error message if any of the specified files are not recognized
+as valid audio files.
+
+`--help`::
+`-h`::
+Print help message.
+
+`--version`::
+`-v`::
+Print version information.
+
+EXAMPLES
+--------
+Display summary of an audio file:
+
+----
+% sfinfo drum.aiff
+File Name      drum.aiff
+File Format    Audio Interchange File Format (aiff)
+Data Format    16-bit integer (2's complement, big endian)
+Audio Data     1569972 bytes begins at offset 54 (36 hex)
+               2 channels, 392493 frames
+Sampling Rate  44100.00 Hz
+Duration       8.900 seconds
+----
+
+List all recognized audio files in the current directory using
+the short output format:
+
+----
+% sfinfo -s *
+    9.60s 44100.00 aiff  1ch 16b -- bass.aiff
+    8.90s 44100.00 aiff  2ch 16b -- drum.aiff
+----
+
+SEE ALSO
+--------
+linkaf:sfconvert[1]
+
+AUTHOR
+------
+Michael Pruett <michael@68k.org>
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 0000000..ca2aa57
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,7 @@
+adddcoffset
+alsaplay
+irixread
+irixtestloop
+linuxtest
+osxplay
+power
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..22b0019
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,31 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile
+
+noinst_PROGRAMS = \
+	adddcoffset \
+	power \
+	@TEST_BIN@
+
+EXTRA_PROGRAMS = alsaplay irixread irixtestloop linuxtest osxplay
+
+LIBAUDIOFILE = $(top_builddir)/libaudiofile/libaudiofile.la
+
+alsaplay_SOURCES = alsaplay.cpp
+alsaplay_LDADD = $(LIBAUDIOFILE) -lasound
+
+irixread_SOURCES = irixread.c sgi.c sgi.h
+irixread_LDADD = $(LIBAUDIOFILE) -laudio
+
+irixtestloop_SOURCES = irixtestloop.c sgi.c sgi.h
+irixtestloop_LDADD = $(LIBAUDIOFILE) -laudio
+
+linuxtest_SOURCES = linuxtest.c
+
+osxplay_SOURCES = osxplay.c
+osxplay_LDFLAGS = -framework AudioUnit -framework CoreServices
+
+power_SOURCES = power.c
+power_LDADD = $(LIBAUDIOFILE) -lm
+
+LDADD = $(LIBAUDIOFILE)
+
+DEPENDENCIES = $(LIBAUDIOFILE)
diff --git a/examples/adddcoffset.c b/examples/adddcoffset.c
new file mode 100644
index 0000000..594004f
--- /dev/null
+++ b/examples/adddcoffset.c
@@ -0,0 +1,98 @@
+/*
+	Audio File Library
+
+	Copyright 1998, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	adddcoffset.c
+
+	This program adds a user-specified DC offset term to a sound file.
+	It's not very useful.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include "audiofile.h"
+#endif
+
+void adddcoffset (float offset, char *infilename, char *outfilename);
+void usageerror (void);
+
+int main (int ac, char **av)
+{
+	float	offset;
+
+	if (ac != 4)
+		usageerror();
+
+	offset = atof(av[1]);
+	adddcoffset(offset, av[2], av[3]);
+	return 0;
+}
+
+void adddcoffset (float offset, char *infilename, char *outfilename)
+{
+	AFfilehandle	infile = afOpenFile(infilename, "r", NULL);
+	int				channelCount, frameCount;
+	short			*buffer;
+	int				i;
+
+	AFfilesetup		outfilesetup = afNewFileSetup();
+	AFfilehandle	outfile;
+
+	frameCount = afGetFrameCount(infile, AF_DEFAULT_TRACK);
+	channelCount = afGetChannels(infile, AF_DEFAULT_TRACK);
+
+	afInitFileFormat(outfilesetup, AF_FILE_AIFF);
+	afInitByteOrder(outfilesetup, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN);
+	afInitChannels(outfilesetup, AF_DEFAULT_TRACK, channelCount);
+	afInitRate(outfilesetup, AF_DEFAULT_TRACK, 44100.0);
+	afInitSampleFormat(outfilesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	outfile = afOpenFile(outfilename, "w", outfilesetup);
+
+	if (infile == NULL)
+	{
+		printf("unable to open input file '%s'.\n", infilename);
+		return;
+	}
+
+	printf("afGetFrameCount: %d\n", (int)afGetFrameCount(infile, AF_DEFAULT_TRACK));
+	printf("afGetChannels: %d\n", afGetChannels(infile, AF_DEFAULT_TRACK));
+
+	buffer = (short *) malloc(frameCount * channelCount * sizeof (short));
+	afReadFrames(infile, AF_DEFAULT_TRACK, (void *) buffer, frameCount);
+
+	for (i=0; i<frameCount; i++)
+	{
+		buffer[i] += offset;
+	}
+
+	afWriteFrames(outfile, AF_DEFAULT_TRACK, (void *) buffer, frameCount);
+	afCloseFile(outfile);
+}
+
+void usageerror (void)
+{
+	fprintf(stderr, "usage: adddcoffset offset infile outfile\n");
+	exit(EXIT_FAILURE);
+}
diff --git a/examples/alsaplay.cpp b/examples/alsaplay.cpp
new file mode 100644
index 0000000..4c11f55
--- /dev/null
+++ b/examples/alsaplay.cpp
@@ -0,0 +1,101 @@
+/*
+	Audio File Library
+
+	Copyright (c) 2010, Michael Pruett.  All rights reserved.
+
+	Redistribution and use in source and binary forms, with or
+	without modification, are permitted provided that the following
+	conditions are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above
+	copyright notice, this list of conditions and the following
+	disclaimer in the documentation and/or other materials provided
+	with the distribution.
+
+	3. The name of the author may not be used to endorse or promote
+	products derived from this software without specific prior
+	written permission.
+
+	THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+	WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+	DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <alsa/asoundlib.h>
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: %s filename\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	AFfilehandle file = afOpenFile(argv[1], "r", AF_NULL_FILESETUP);
+	if (!file)
+	{
+		fprintf(stderr, "Could not open '%s'.\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	int channels = afGetChannels(file, AF_DEFAULT_TRACK);
+	double rate = afGetRate(file, AF_DEFAULT_TRACK);
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	int err;
+	snd_pcm_t *handle;
+	if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+	{
+		fprintf(stderr, "Could not open audio output: %s\n", snd_strerror(err));
+		exit(EXIT_FAILURE);
+	}
+
+	if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16,
+		SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 1, 500000)) < 0)
+	{
+		fprintf(stderr, "Could not set audio output parameters: %s\n", snd_strerror(err));
+		exit(EXIT_FAILURE);
+	}
+
+	const int bufferFrames = 4096;
+	int16_t *buffer = new int16_t[bufferFrames * channels];
+
+	while (true)
+	{
+		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer, bufferFrames);
+		if (framesRead <= 0)
+			break;
+
+		snd_pcm_sframes_t framesWritten = snd_pcm_writei(handle, buffer, bufferFrames);
+		if (framesWritten < 0)
+			framesWritten = snd_pcm_recover(handle, framesWritten, 0);
+		if (framesWritten < 0)
+		{
+			fprintf(stderr, "Could not write audio data to output device: %s\n",
+				snd_strerror(err));
+			break;
+		}
+	}
+
+	snd_pcm_drain(handle);
+	snd_pcm_close(handle);
+	delete [] buffer;
+
+	afCloseFile(file);
+
+	return 0;
+}
diff --git a/examples/irixread.c b/examples/irixread.c
new file mode 100644
index 0000000..9bc3684
--- /dev/null
+++ b/examples/irixread.c
@@ -0,0 +1,122 @@
+/*
+	Audio File Library
+
+	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	irixread.c
+
+	This program reads and plays a given audio file using Irix's
+	default audio output device.  This file will not work on any
+	operating system other than Irix.
+
+	The only difference between this program and irixtest is that this
+	program does not load the entire audio track into memory at once.
+	Only a small number of frames are read into a buffer and then
+	written to the audio port.  While there are more frames to be
+	read, this process is repeated.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dmedia/audio.h>
+#include <dmedia/audiofile.h>
+
+#include "sgi.h"
+
+const int BUFFERED_FRAME_COUNT = 65536;
+
+void usage (void)
+{
+	fprintf(stderr, "usage: irixread filename\n");
+	exit(EXIT_FAILURE);
+}
+
+main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	AFframecount	count, frameCount;
+	int		channelCount, sampleFormat, sampleWidth;
+	float		frameSize;
+	void		*buffer;
+	double		sampleRate;
+
+	ALport		outport;
+	ALconfig	outportconfig;
+
+	if (argc < 2)
+		usage();
+
+	file = afOpenFile(argv[1], "r", NULL);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "Could not open file %s.\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
+	frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
+	channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
+	sampleRate = afGetRate(file, AF_DEFAULT_TRACK);
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat,
+		&sampleWidth);
+
+	if (sampleFormat == AF_SAMPFMT_UNSIGNED)
+	{
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
+			AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+
+	printf("frame count: %lld\n", frameCount);
+	printf("frame size: %d bytes\n", (int) frameSize);
+	printf("channel count: %d\n", channelCount);
+	printf("sample rate: %.2f Hz\n", sampleRate);
+	buffer = malloc(BUFFERED_FRAME_COUNT * frameSize);
+
+	outportconfig = alNewConfig();
+	setwidth(outportconfig, sampleWidth);
+	setsampleformat(outportconfig, sampleFormat);
+	alSetChannels(outportconfig, channelCount);
+
+	count = afReadFrames(file, AF_DEFAULT_TRACK, buffer, BUFFERED_FRAME_COUNT);
+
+	outport = alOpenPort("irixread", "w", outportconfig);
+	setrate(outport, sampleRate);
+
+	do
+	{
+		printf("count = %lld\n", count);
+		alWriteFrames(outport, buffer, count);
+
+		count = afReadFrames(file, AF_DEFAULT_TRACK, buffer,
+			BUFFERED_FRAME_COUNT);
+	} while (count > 0);
+
+	waitport(outport);
+
+	alClosePort(outport);
+	alFreeConfig(outportconfig);
+
+	afCloseFile(file);
+}
diff --git a/examples/irixtestloop.c b/examples/irixtestloop.c
new file mode 100644
index 0000000..688da39
--- /dev/null
+++ b/examples/irixtestloop.c
@@ -0,0 +1,149 @@
+/*
+	Audio File Library
+
+	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	irixtestloop.c
+
+	This file reads the loop points from a file (presumably AIFF) and
+	loops that part of the file several times.  Audio output is routed
+	to IRIX's default audio output device.  This program will not
+	compile on any platform other than IRIX.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dmedia/audio.h>
+#include <dmedia/audiofile.h>
+
+#include "sgi.h"
+
+const int REPEAT_COUNT = 3;
+
+void usage (void)
+{
+	printf("usage: irixtestloop file\n");
+	printf("where file is of a format which contains a loop (e.g. AIFF)\n");
+	exit(EXIT_FAILURE);
+}
+
+main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	void		*buffer;
+
+	AFframecount	frameCount;
+	int		sampleFormat, sampleWidth, channelCount;
+	float		frameSize;
+	double		sampleRate;
+
+	int		*loopids, *markids;
+	int		i, loopCount, markCount;
+	int		startmarkid, endmarkid;
+	AFframecount	startloop, endloop;
+
+	ALport		outport;
+	ALconfig	outportconfig;
+
+	if (argc < 2)
+		usage();
+
+	file = afOpenFile(argv[1], "r", NULL);
+	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
+	frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
+	channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	sampleRate = afGetRate(file, AF_DEFAULT_TRACK);
+
+	/*
+		If the file's sample format is unsigned integer data,
+		change the virtual sample format to two's complement
+		since the SGI Audio Library won't accept unsigned
+		data.
+	*/
+	if (sampleFormat == AF_SAMPFMT_UNSIGNED)
+	{
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
+			AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+
+	printf("frame count: %lld\n", frameCount);
+	printf("frame size: %d bytes\n", frameSize);
+	printf("channel count: %d\n", channelCount);
+	printf("sample rate: %.2f Hz\n", sampleRate);
+
+	buffer = malloc(frameCount * frameSize);
+	afReadFrames(file, AF_DEFAULT_TRACK, buffer, frameCount);
+
+	loopCount = afGetLoopIDs(file, AF_DEFAULT_INST, NULL);
+	loopids = malloc(sizeof (int) * loopCount);
+	afGetLoopIDs(file, AF_DEFAULT_INST, loopids);
+
+	markCount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
+	markids = malloc(sizeof (int) * markCount);
+	afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);
+
+	printf("loop ids:");
+	for (i=0; i<loopCount; i++)
+		printf(" %d", loopids[i]);
+	printf("\n");
+
+	printf("mark ids:");
+	for (i=0; i<markCount; i++)
+		printf(" %d", markids[i]);
+	printf("\n");
+
+	startmarkid = afGetLoopStart(file, AF_DEFAULT_INST, 1);
+	endmarkid = afGetLoopEnd(file, AF_DEFAULT_INST, 1);
+	startloop = afGetMarkPosition(file, AF_DEFAULT_TRACK, startmarkid);
+	endloop = afGetMarkPosition(file, AF_DEFAULT_TRACK, endmarkid);
+
+	afCloseFile(file);
+
+	outportconfig = alNewConfig();
+	setwidth(outportconfig, sampleWidth);
+	setsampleformat(outportconfig, sampleFormat);
+	alSetChannels(outportconfig, channelCount);
+
+	outport = alOpenPort("irixtestloop", "w", outportconfig);
+	setrate(outport, sampleRate);
+
+	alWriteFrames(outport, buffer, startloop);
+	for (i=0; i<REPEAT_COUNT; i++)
+	{
+		printf("iteration %d: start %lld, end %lld, length %lld\n",
+			i, endloop, startloop, endloop - startloop);
+		alWriteFrames(outport,
+			(char *) buffer + (int) (startloop * frameSize),
+			endloop - startloop);
+	}
+
+	waitport(outport);
+
+	alClosePort(outport);
+	alFreeConfig(outportconfig);
+
+	free(buffer);
+}
diff --git a/examples/linuxtest.c b/examples/linuxtest.c
new file mode 100644
index 0000000..a4029af
--- /dev/null
+++ b/examples/linuxtest.c
@@ -0,0 +1,163 @@
+/*
+	Audio File Library
+
+	Copyright (c) 1998-1999, Michael Pruett <michael@68k.org>
+	Copyright (c) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	linuxtest.c
+
+	This file plays a 16-bit, 44.1 kHz monophonic or stereophonic
+	audio file through a PC sound card on a Linux system.  This file
+	will not compile under any operating system that does not support
+	the Open Sound System API.
+*/
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/soundcard.h>
+
+#include <audiofile.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+	If it's not defined already, define the native audio hardware
+	byte order.
+*/
+
+#ifndef AFMT_S16_NE
+#ifdef WORDS_BIGENDIAN /* defined in config.h */
+#define AFMT_S16_NE AFMT_S16_BE
+#else
+#define AFMT_S16_NE AFMT_S16_LE
+#endif /* WORDS_BIGENDIAN */
+#endif /* AFMT_S16_NE */
+
+void setupdsp (int audiofd, int channelCount, int frequency);
+void usage (void);
+
+/* BUFFER_FRAMES represents the size of the buffer in frames. */
+#define BUFFER_FRAMES 4096
+
+int main (int argc, char **argv)
+{
+	if (argc != 2)
+		usage();
+
+	AFfilehandle file = afOpenFile(argv[1], "r", NULL);
+	AFframecount frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
+	printf("frame count: %jd\n", (intmax_t) frameCount);
+
+	int channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
+	int sampleFormat, sampleWidth;
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat,
+		&sampleWidth);
+	double frequency = afGetRate(file, AF_DEFAULT_TRACK);
+
+	float frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
+
+	printf("sample format: %d, sample width: %d, channels: %d\n",
+		sampleFormat, sampleWidth, channelCount);
+
+	if ((sampleFormat != AF_SAMPFMT_TWOSCOMP) &&
+		(sampleFormat != AF_SAMPFMT_UNSIGNED))
+	{
+		fprintf(stderr, "The audio file must contain integer data in two's complement or unsigned format.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if ((sampleWidth != 16) || (channelCount > 2))
+	{
+		fprintf(stderr, "The audio file must be of a 16-bit monophonic or stereophonic format.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	void *buffer = malloc(BUFFER_FRAMES * frameSize);
+
+	int audiofd = open("/dev/dsp", O_WRONLY);
+	if (audiofd < 0)
+	{
+		perror("open");
+		exit(EXIT_FAILURE);
+	}
+
+	setupdsp(audiofd, channelCount, frequency);
+
+	while (1)
+	{
+		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer,
+			BUFFER_FRAMES);
+		if (framesRead <= 0)
+			break;
+
+		printf("read %jd frames\n", (intmax_t) framesRead);
+
+		ssize_t bytesWritten = write(audiofd, buffer, framesRead * frameSize);
+		if (bytesWritten < 0)
+			break;
+	}
+
+	close(audiofd);
+	free(buffer);
+
+	return 0;
+}
+
+void setupdsp (int audiofd, int channelCount, int frequency)
+{
+	int format = AFMT_S16_NE;
+	if (ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) == -1)
+	{
+		perror("set format");
+		exit(EXIT_FAILURE);
+	}
+
+	if (format != AFMT_S16_NE)
+	{
+		fprintf(stderr, "format not correct.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &channelCount) == -1)
+	{
+		perror("set channels");
+		exit(EXIT_FAILURE);
+	}
+
+	if (ioctl(audiofd, SNDCTL_DSP_SPEED, &frequency) == -1)
+	{
+		perror("set frequency");
+		exit(EXIT_FAILURE);
+	}
+}
+
+void usage (void)
+{
+	fprintf(stderr, "usage: linuxtest file\n");
+	fprintf(stderr,
+		"where file refers to a 16-bit monophonic or stereophonic 44.1 kHz audio file\n");
+	exit(EXIT_FAILURE);
+}
diff --git a/examples/osxplay.c b/examples/osxplay.c
new file mode 100644
index 0000000..6c9b617
--- /dev/null
+++ b/examples/osxplay.c
@@ -0,0 +1,258 @@
+/*
+	Audio File Library
+
+	Copyright (c) 2003, Michael Pruett.  All rights reserved.
+
+	Redistribution and use in source and binary forms, with or
+	without modification, are permitted provided that the following
+	conditions are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above
+	copyright notice, this list of conditions and the following
+	disclaimer in the documentation and/or other materials provided
+	with the distribution.
+
+	3. The name of the author may not be used to endorse or promote
+	products derived from this software without specific prior
+	written permission.
+
+	THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+	WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+	DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	osxplay.c
+
+	This program demonstrates audio file playback using the Audio
+	File Library and Core Audio.
+*/
+
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <CoreServices/CoreServices.h>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudio.h>
+
+#define BUFFER_FRAME_COUNT 1024
+
+int isPlaying = 1;
+void *buffer = NULL;
+
+void getASBDForFile (AFfilehandle file, int track,
+	AudioStreamBasicDescription *asbd)
+{
+	int	sampleFormat, sampleWidth, channelCount;
+	double	rate;
+
+	afGetVirtualSampleFormat(file, track, &sampleFormat, &sampleWidth);
+	channelCount = afGetChannels(file, track);
+	rate = afGetRate(file, track);
+
+	asbd->mSampleRate = rate;
+	asbd->mFormatID = kAudioFormatLinearPCM;
+	switch (sampleFormat)
+	{
+		case AF_SAMPFMT_TWOSCOMP:
+			asbd->mFormatFlags = kAudioFormatFlagIsSignedInteger;
+			asbd->mBitsPerChannel = sampleWidth;
+			break;
+		case AF_SAMPFMT_UNSIGNED:
+			asbd->mFormatFlags = 0;
+			asbd->mBitsPerChannel = sampleWidth;
+			break;
+		case AF_SAMPFMT_FLOAT:
+			asbd->mFormatFlags = kAudioFormatFlagIsFloat;
+			asbd->mBitsPerChannel = 32;
+			break;
+		case AF_SAMPFMT_DOUBLE:
+			asbd->mFormatFlags = kAudioFormatFlagIsFloat;
+			asbd->mBitsPerChannel = 64;
+			break;
+	}
+
+	asbd->mChannelsPerFrame = channelCount;
+	asbd->mFramesPerPacket = 1;
+	asbd->mBytesPerFrame = ceilf(afGetVirtualFrameSize(file, track, 1));
+	asbd->mBytesPerPacket = asbd->mBytesPerFrame;
+
+	if (afGetVirtualByteOrder(file, track) == AF_BYTEORDER_BIGENDIAN)
+		asbd->mFormatFlags |= kAudioFormatFlagIsBigEndian;
+}
+
+OSStatus openOutput (AudioUnit *outputUnit)
+{
+	OSStatus		status = noErr;
+	ComponentDescription	description;
+	Component		component;
+
+	description.componentType = kAudioUnitType_Output;
+	description.componentSubType = kAudioUnitSubType_DefaultOutput;
+	description.componentManufacturer = kAudioUnitManufacturer_Apple;
+	description.componentFlags = 0;
+	description.componentFlagsMask = 0;
+
+	component = FindNextComponent(NULL, &description);
+	if (component == NULL)
+	{
+		fprintf(stderr, "Could not find audio output device.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	status = OpenAComponent(component, outputUnit);
+	if (status != noErr)
+	{
+		fprintf(stderr, "Could not open audio output device.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	status = AudioUnitInitialize(*outputUnit);
+	if (status != noErr)
+	{
+		fprintf(stderr, "Could not initialize audio output device.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	return status;
+}
+
+OSStatus fileRenderProc (void *inRefCon,
+	AudioUnitRenderActionFlags *inActionFlags,
+	const AudioTimeStamp *inTimeStamp,
+	UInt32 inBusNumber,
+	UInt32 inNumFrames,
+	AudioBufferList *ioData)
+{
+	AFfilehandle	file = (AFfilehandle) inRefCon;
+	AFframecount	framesToRead, framesRead;
+
+	framesToRead = inNumFrames;
+	if (framesToRead > BUFFER_FRAME_COUNT)
+		framesToRead = BUFFER_FRAME_COUNT;
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
+		buffer, framesToRead);
+	if (framesRead > 0)
+	{
+		ioData->mBuffers[0].mData = buffer;
+		ioData->mBuffers[0].mDataByteSize = framesRead *
+			afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
+	}
+	else
+		isPlaying = 0;
+
+	return noErr;
+}
+
+OSStatus setupOutput (AudioUnit *outputUnit, AFfilehandle file)
+{
+	OSStatus	status = noErr;
+	UInt32		size;
+	Boolean		outWritable;
+
+	AudioStreamBasicDescription	fileASBD, inputASBD, outputASBD;
+	AURenderCallbackStruct		renderCallback;
+
+	/* Set virtual sample format to single-precision floating-point. */
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
+
+	/* Get ASBD for virtual sample format. */ 
+	getASBDForFile(file, AF_DEFAULT_TRACK, &fileASBD);
+
+	status = AudioUnitGetPropertyInfo(*outputUnit,
+		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
+		0, &size, &outWritable);
+
+	status = AudioUnitGetProperty(*outputUnit,
+		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
+		0, &outputASBD, &size);
+
+	if (outWritable)
+	{
+		outputASBD = fileASBD;
+
+		status = AudioUnitSetProperty(*outputUnit,
+			kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
+			0, &outputASBD, size);
+	}
+
+	inputASBD = fileASBD;
+
+	status = AudioUnitSetProperty(*outputUnit,
+		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
+		0, &inputASBD, size);
+	if (status != noErr)
+	{
+		fprintf(stderr, "Could not set input stream format.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+		Set the render callback to a procedure which will
+		read from the file.
+	*/
+	renderCallback.inputProc = fileRenderProc;
+	renderCallback.inputProcRefCon = file;
+
+	status = AudioUnitSetProperty(*outputUnit,
+		kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0,
+		&renderCallback, sizeof (AURenderCallbackStruct));
+	if (status != noErr)
+	{
+		fprintf(stderr, "Could not set render callback.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	return status;
+}
+
+int main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	AudioUnit	outputUnit;
+
+	if (argc < 2)
+	{
+		fprintf(stderr, "usage: %s filename\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(argv[1], "r", AF_NULL_FILESETUP);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "Could not open file '%s' for reading.\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	openOutput(&outputUnit);
+	setupOutput(&outputUnit, file);
+	AudioOutputUnitStart(outputUnit);
+
+	buffer = malloc(BUFFER_FRAME_COUNT *
+		afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1));
+
+	while (isPlaying)
+		usleep(250000);
+
+	AudioOutputUnitStop(outputUnit);
+	AudioUnitUninitialize(outputUnit);
+	CloseComponent(outputUnit);
+
+	free(buffer);
+
+	afCloseFile(file);
+}
diff --git a/examples/power.c b/examples/power.c
new file mode 100644
index 0000000..ec789ac
--- /dev/null
+++ b/examples/power.c
@@ -0,0 +1,219 @@
+/*
+	This program is derived from Chris Vaill's normalize program
+	and has been modified to use the Audio File Library for file
+	reading and audio data conversion.
+
+	Copyright (C) 2001, Silicon Graphics, Inc.
+	Copyright (C) 1999-2001, Chris Vaill
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	power.c
+
+	Calculate the power and peak amplitudes of an audio file.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <audiofile.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct smooth
+{
+	double	*buf;
+	int	length, start, n;
+};
+
+static double get_smoothed_data (struct smooth *s)
+{
+	int i;
+	double smoothed;
+
+	smoothed = 0;
+	for (i = 0; i < s->n; i++)
+		smoothed += s->buf[i];
+	smoothed = smoothed / s->n;
+
+	return smoothed;
+}
+
+void print_power (char *filename);
+
+int main (int argc, char **argv)
+{
+	int	i;
+
+	if (argc < 2)
+	{
+		fprintf(stderr, "usage: %s filename [more filenames...]\n",
+			argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	for (i=1; i<argc; i++)
+		print_power(argv[i]);
+
+	return 0;
+}
+
+void print_power (char *filename)
+{
+	AFfilehandle	file;
+	double		*sums, *frames;
+	int		channelCount, windowSize, frameCount;
+	int		i, c;
+	struct smooth	*powsmooth;
+	int		winStart, winEnd;
+	int		lastWindow = FALSE;
+	double		pow, maxpow;
+
+	double		level, peak, minSample = 1, maxSample = -1;
+
+	file = afOpenFile(filename, "r", NULL);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "Could not open file %s.\n", filename);
+		return;
+	}
+
+	channelCount = afGetChannels(file, AF_DEFAULT_TRACK);
+	windowSize = afGetRate(file, AF_DEFAULT_TRACK) / 100;
+	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
+
+	sums = calloc(channelCount, sizeof (double));
+	for (c=0; c<channelCount; c++)
+		sums[c] = 0;
+
+	frames = calloc(channelCount * windowSize, sizeof (double));
+
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_DOUBLE,
+		sizeof (double));
+
+	powsmooth = calloc(channelCount, sizeof (struct smooth));
+	for (c=0; c<channelCount; c++)
+	{
+		/* Use a 100-element (1 second) window. */
+		powsmooth[c].length = 100;
+		powsmooth[c].buf = calloc(powsmooth[c].length, sizeof (double));
+		powsmooth[c].start = 0;
+		powsmooth[c].n = 0;
+	}
+
+	winStart = 0;
+	winEnd = 0;
+	lastWindow = FALSE;
+	maxpow = 0;
+
+	do
+	{
+		winEnd = winStart + windowSize;
+
+		if (winEnd >= frameCount)
+		{
+			winEnd = frameCount;
+			lastWindow = TRUE;
+		}
+
+		afReadFrames(file, AF_DEFAULT_TRACK, frames, windowSize);
+
+		for (c=0; c<channelCount; c++)
+		{
+			sums[c] = 0;
+
+			for (i=0; i < winEnd - winStart; i++)
+			{
+				double	sample;
+
+				sample = frames[i*channelCount + c];
+				sums[c] += sample*sample;
+
+				if (sample > maxSample)
+					maxSample = sample;
+				if (sample < minSample)
+					minSample = sample;
+			}
+		}
+
+		/* Compute power for each channel. */
+		for (c=0; c<channelCount; c++)
+		{
+			double pow;
+			int end;
+
+			pow = sums[c] / (winEnd - winStart);
+
+			end = (powsmooth[c].start + powsmooth[c].n) %
+				powsmooth[c].length;
+			powsmooth[c].buf[end] = pow;
+
+			if (powsmooth[c].n == powsmooth[c].length)
+			{
+				powsmooth[c].start = (powsmooth[c].start + 1) % powsmooth[c].length;
+				pow = get_smoothed_data(&powsmooth[c]);
+				if (pow > maxpow)
+					maxpow = pow;
+			}
+			else
+			{
+				powsmooth[c].n++;
+			}
+		}
+
+		winStart += windowSize;
+	} while (!lastWindow);
+
+	for (c = 0; c < channelCount; c++)
+	{
+		pow = get_smoothed_data(&powsmooth[c]);
+		if (pow > maxpow)
+			maxpow = pow;
+	}
+
+	free(sums);
+	free(frames);
+	for (c=0; c<channelCount; c++)
+		free(powsmooth[c].buf);
+	free(powsmooth);
+
+	level = sqrt(maxpow);
+
+	afCloseFile(file);
+
+	printf("file: %s\n", filename);
+
+	printf("level (dB): %f\n", 20 * log10(level));
+	printf("peak-: %f\n", minSample);
+	printf("peak+: %f\n", maxSample);
+
+	peak = fabs(minSample);
+	if (peak < fabs(maxSample))
+		peak = fabs(maxSample);
+
+	printf("peak (dB): %f\n", 20 * log10(peak));
+}
diff --git a/examples/sgi.c b/examples/sgi.c
new file mode 100644
index 0000000..d8b053d
--- /dev/null
+++ b/examples/sgi.c
@@ -0,0 +1,108 @@
+/*
+	Audio File Library
+
+	Copyright 1998-1999, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	sgi.c
+
+	These routines are used in SGI-specific test programs.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include <dmedia/audio.h>
+
+/*
+	Set the sample width of an audio configuration.
+*/
+void setwidth (ALconfig config, int sampleWidth)
+{
+	if (sampleWidth <= 8)
+	{
+		printf("setting width to 8\n");
+		alSetWidth(config, AL_SAMPLE_8);
+	}
+	else if (sampleWidth <= 16)
+	{
+		printf("setting width to 16\n");
+		alSetWidth(config, AL_SAMPLE_16);
+	}
+	else if (sampleWidth <= 24)
+	{
+		printf("setting width to 24\n");
+		alSetWidth(config, AL_SAMPLE_24);
+	}
+}
+
+/*
+	Set the sample format of an audio configuration.
+*/
+void setsampleformat (ALconfig config, int audioFileSampleFormat)
+{
+	if (audioFileSampleFormat == AF_SAMPFMT_TWOSCOMP)
+	{
+		printf("setting sample format to 2's complement\n");
+		alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP);
+	}
+	else if (audioFileSampleFormat == AF_SAMPFMT_FLOAT)
+	{
+		printf("setting sample format to float\n");
+		alSetSampFmt(config, AL_SAMPFMT_FLOAT);
+	}
+	else if (audioFileSampleFormat == AF_SAMPFMT_DOUBLE)
+	{
+		printf("setting sample format to double\n");
+		alSetSampFmt(config, AL_SAMPFMT_DOUBLE);
+	}
+}
+
+/*
+	Set the sample rate of an audio port.
+*/
+void setrate (ALport port, double rate)
+{
+	int		rv;
+	ALpv	params;
+
+	rv = alGetResource(port);
+
+	params.param = AL_RATE;
+	params.value.ll = alDoubleToFixed(rate);
+
+	if (alSetParams(rv, &params, 1) < 0)
+	{
+		printf("alSetParams failed: %s\n", alGetErrorString(oserror()));
+	}
+}
+
+/*
+	Wait until the audio port has no more samples to play.
+*/
+void waitport (ALport port)
+{
+	while (alGetFilled(port) > 0)
+		sginap(1);
+}
diff --git a/examples/sgi.h b/examples/sgi.h
new file mode 100644
index 0000000..3f66dbb
--- /dev/null
+++ b/examples/sgi.h
@@ -0,0 +1,52 @@
+/*
+	Audio File Library
+
+	Copyright 1998-1999, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	sgi.h
+
+	These routines are used in SGI-specific test programs.
+*/
+
+#ifndef SGI_H
+#define SGI_H
+
+#include <dmedia/audio.h>
+
+/*
+	Set the sample width of an audio configuration.
+*/
+void setwidth (ALconfig config, int width);
+
+/*
+	Set the sample format of an audio configuration.
+*/
+void setsampleformat (ALconfig config, int width);
+
+/*
+	Set the sample rate of an audio port.
+*/
+void setrate (ALport port, double rate);
+
+/*
+	Wait until the audio port has no more samples to play.
+*/
+void waitport (ALport port);
+
+#endif
diff --git a/gtest/Makefile.am b/gtest/Makefile.am
new file mode 100644
index 0000000..35f3948
--- /dev/null
+++ b/gtest/Makefile.am
@@ -0,0 +1,6 @@
+check_LTLIBRARIES = libgtest.la
+libgtest_la_SOURCES = gtest-all.cc gtest.h
+libgtest_la_LIBADD = -lpthread
+libgtest_la_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
+libgtest_la_CPPFLAGS = -I$(top_srcdir)
+EXTRA_DIST = README.audiofile
diff --git a/gtest/README.audiofile b/gtest/README.audiofile
new file mode 100644
index 0000000..9a0c63b
--- /dev/null
+++ b/gtest/README.audiofile
@@ -0,0 +1,4 @@
+This directory contains Google Test version 1.7.0. The fused-source
+implementation is used here for simplicity and compactness.
+
+http://code.google.com/p/googletest/
diff --git a/gtest/gtest-all.cc b/gtest/gtest-all.cc
new file mode 100644
index 0000000..a9a03b2
--- /dev/null
+++ b/gtest/gtest-all.cc
@@ -0,0 +1,9592 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include "gtest/gtest.h"
+
+// The following lines pull in the real gtest *.cc files.
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  // The two possible mocking modes of this object.
+  enum InterceptMode {
+    INTERCEPT_ONLY_CURRENT_THREAD,  // Intercepts only thread local failures.
+    INTERCEPT_ALL_THREADS           // Intercepts all failures.
+  };
+
+  // The c'tor sets this object as the test part result reporter used
+  // by Google Test.  The 'result' parameter specifies where to report the
+  // results. This reporter will only catch failures generated in the current
+  // thread. DEPRECATED
+  explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+  // Same as above, but you can choose the interception scope of this object.
+  ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+                                   TestPartResultArray* result);
+
+  // The d'tor restores the previous test part result reporter.
+  virtual ~ScopedFakeTestPartResultReporter();
+
+  // Appends the TestPartResult object to the TestPartResultArray
+  // received in the constructor.
+  //
+  // This method is from the TestPartResultReporterInterface
+  // interface.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+  void Init();
+
+  const InterceptMode intercept_mode_;
+  TestPartResultReporterInterface* old_reporter_;
+  TestPartResultArray* const result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE().  Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker {
+ public:
+  // The constructor remembers the arguments.
+  SingleFailureChecker(const TestPartResultArray* results,
+                       TestPartResult::Type type,
+                       const string& substr);
+  ~SingleFailureChecker();
+ private:
+  const TestPartResultArray* const results_;
+  const TestPartResult::Type type_;
+  const string substr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures.  It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - 'statement' cannot reference local non-static variables or
+//     non-static members of the current object.
+//   - 'statement' cannot return a value.
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ALL_THREADS, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures.  It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma.  The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+//   if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+//   GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+        (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      if (::testing::internal::AlwaysTrue()) { statement; }\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+        (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+          &gtest_failures);\
+      if (::testing::internal::AlwaysTrue()) { statement; }\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <limits>
+#include <ostream>  // NOLINT
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+# include <fcntl.h>  // NOLINT
+# include <limits.h>  // NOLINT
+# include <sched.h>  // NOLINT
+// Declares vsnprintf().  This header is not available on Windows.
+# include <strings.h>  // NOLINT
+# include <sys/mman.h>  // NOLINT
+# include <sys/time.h>  // NOLINT
+# include <unistd.h>  // NOLINT
+# include <string>
+
+#elif GTEST_OS_SYMBIAN
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h>  // NOLINT
+
+#elif GTEST_OS_ZOS
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h>  // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+# include <strings.h>  // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE  // We are on Windows CE.
+
+# include <windows.h>  // NOLINT
+
+#elif GTEST_OS_WINDOWS  // We are on Windows proper.
+
+# include <io.h>  // NOLINT
+# include <sys/timeb.h>  // NOLINT
+# include <sys/types.h>  // NOLINT
+# include <sys/stat.h>  // NOLINT
+
+# if GTEST_OS_WINDOWS_MINGW
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+//   gettimeofday().
+// TODO(kenton@google.com): There are other ways to get the time on
+//   Windows, like GetTickCount() or GetSystemTimeAsFileTime().  MinGW
+//   supports these.  consider using them instead.
+#  define GTEST_HAS_GETTIMEOFDAY_ 1
+#  include <sys/time.h>  // NOLINT
+# endif  // GTEST_OS_WINDOWS_MINGW
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <windows.h>  // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+//   gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <sys/time.h>  // NOLINT
+# include <unistd.h>  // NOLINT
+
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h>  // NOLINT
+# include <netdb.h>  // NOLINT
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation.  Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+# error "gtest-internal-inl.h is part of Google Test's internal implementation."
+# error "It must not be included except by Google Test itself."
+#endif  // GTEST_IMPLEMENTATION_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif  // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h>  // For strtoll/_strtoul64/malloc/free.
+#include <string.h>  // For memmove.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h>  // NOLINT
+# include <netdb.h>  // NOLINT
+#endif
+
+#if GTEST_OS_WINDOWS
+# include <windows.h>  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kStreamResultToFlag[] = "stream_result_to";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true iff Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Converts the given time in milliseconds to a date string in the ISO 8601
+// format, without the timezone information.  N.B.: due to the use the
+// non-reentrant localtime() function, this function is not thread safe.  Do
+// not use it in any code that can be called from multiple threads.
+GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+    const char* str, const char* flag, Int32* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
+  const unsigned int raw_seed = (random_seed_flag == 0) ?
+      static_cast<unsigned int>(GetTimeInMillis()) :
+      static_cast<unsigned int>(random_seed_flag);
+
+  // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+  // it's easy to type.
+  const int normalized_seed =
+      static_cast<int>((raw_seed - 1U) %
+                       static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+  return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'.  The behavior is
+// undefined if 'seed' is invalid.  The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed) {
+  GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+      << "Invalid random seed " << seed << " - must be in [1, "
+      << kMaxRandomSeed << "].";
+  const int next_seed = seed + 1;
+  return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+  // The c'tor.
+  GTestFlagSaver() {
+    also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+    break_on_failure_ = GTEST_FLAG(break_on_failure);
+    catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+    color_ = GTEST_FLAG(color);
+    death_test_style_ = GTEST_FLAG(death_test_style);
+    death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+    filter_ = GTEST_FLAG(filter);
+    internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+    list_tests_ = GTEST_FLAG(list_tests);
+    output_ = GTEST_FLAG(output);
+    print_time_ = GTEST_FLAG(print_time);
+    random_seed_ = GTEST_FLAG(random_seed);
+    repeat_ = GTEST_FLAG(repeat);
+    shuffle_ = GTEST_FLAG(shuffle);
+    stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+    stream_result_to_ = GTEST_FLAG(stream_result_to);
+    throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+  }
+
+  // The d'tor is not virtual.  DO NOT INHERIT FROM THIS CLASS.
+  ~GTestFlagSaver() {
+    GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+    GTEST_FLAG(break_on_failure) = break_on_failure_;
+    GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+    GTEST_FLAG(color) = color_;
+    GTEST_FLAG(death_test_style) = death_test_style_;
+    GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+    GTEST_FLAG(filter) = filter_;
+    GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+    GTEST_FLAG(list_tests) = list_tests_;
+    GTEST_FLAG(output) = output_;
+    GTEST_FLAG(print_time) = print_time_;
+    GTEST_FLAG(random_seed) = random_seed_;
+    GTEST_FLAG(repeat) = repeat_;
+    GTEST_FLAG(shuffle) = shuffle_;
+    GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+    GTEST_FLAG(stream_result_to) = stream_result_to_;
+    GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+  }
+
+ private:
+  // Fields for saving the original values of flags.
+  bool also_run_disabled_tests_;
+  bool break_on_failure_;
+  bool catch_exceptions_;
+  std::string color_;
+  std::string death_test_style_;
+  bool death_test_use_fork_;
+  std::string filter_;
+  std::string internal_run_death_test_;
+  bool list_tests_;
+  std::string output_;
+  bool print_time_;
+  internal::Int32 random_seed_;
+  internal::Int32 repeat_;
+  bool shuffle_;
+  internal::Int32 stack_trace_depth_;
+  std::string stream_result_to_;
+  bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+                            const char* shard_index_str,
+                            bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+    int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate) {
+  // Implemented as an explicit loop since std::count_if() in libCstd on
+  // Solaris has a non-standard signature.
+  int count = 0;
+  for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
+    if (predicate(*it))
+      ++count;
+  }
+  return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor) {
+  std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+  return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+                  std::vector<E>* v) {
+  const int size = static_cast<int>(v->size());
+  GTEST_CHECK_(0 <= begin && begin <= size)
+      << "Invalid shuffle range start " << begin << ": must be in range [0, "
+      << size << "].";
+  GTEST_CHECK_(begin <= end && end <= size)
+      << "Invalid shuffle range finish " << end << ": must be in range ["
+      << begin << ", " << size << "].";
+
+  // Fisher-Yates shuffle, from
+  // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+  for (int range_width = end - begin; range_width >= 2; range_width--) {
+    const int last_in_range = begin + range_width - 1;
+    const int selected = begin + random->Generate(range_width);
+    std::swap((*v)[selected], (*v)[last_in_range]);
+  }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+  ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object.  Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x) {
+  delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+  // Constructor.
+  //
+  // TestPropertyKeyIs has NO default constructor.
+  explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
+
+  // Returns true iff the test name of test property matches on key_.
+  bool operator()(const TestProperty& test_property) const {
+    return test_property.key() == key_;
+  }
+
+ private:
+  std::string key_;
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests.  It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag.  E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter.  If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions {
+ public:
+  // Functions for processing the gtest_output flag.
+
+  // Returns the output format, or "" for normal printed output.
+  static std::string GetOutputFormat();
+
+  // Returns the absolute path of the requested output file, or the
+  // default (test_detail.xml in the original working directory) if
+  // none was explicitly specified.
+  static std::string GetAbsolutePathToOutputFile();
+
+  // Functions for processing the gtest_filter flag.
+
+  // Returns true iff the wildcard pattern matches the string.  The
+  // first ':' or '\0' character in pattern marks the end of it.
+  //
+  // This recursive algorithm isn't very efficient, but is clear and
+  // works well enough for matching test names, which are short.
+  static bool PatternMatchesString(const char *pattern, const char *str);
+
+  // Returns true iff the user-specified filter matches the test case
+  // name and the test name.
+  static bool FilterMatchesTest(const std::string &test_case_name,
+                                const std::string &test_name);
+
+#if GTEST_OS_WINDOWS
+  // Function for supporting the gtest_catch_exception flag.
+
+  // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+  // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+  // This function is useful as an __except condition.
+  static int GTestShouldProcessSEH(DWORD exception_code);
+#endif  // GTEST_OS_WINDOWS
+
+  // Returns true if "name" matches the ':' separated list of glob-style
+  // filters in "filter".
+  static bool MatchesFilter(const std::string& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present.  Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetterInterface() {}
+  virtual ~OsStackTraceGetterInterface() {}
+
+  // Returns the current OS stack trace as an std::string.  Parameters:
+  //
+  //   max_depth  - the maximum number of stack frames to be included
+  //                in the trace.
+  //   skip_count - the number of top frames to be skipped; doesn't count
+  //                against max_depth.
+  virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+  // UponLeavingGTest() should be called immediately before Google Test calls
+  // user code. It saves some information about the current stack that
+  // CurrentStackTrace() will use to find and hide Google Test stack frames.
+  virtual void UponLeavingGTest() = 0;
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetter() : caller_frame_(NULL) {}
+
+  virtual string CurrentStackTrace(int max_depth, int skip_count)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // This string is inserted in place of stack frames that are part of
+  // Google Test's implementation.
+  static const char* const kElidedFramesMarker;
+
+ private:
+  Mutex mutex_;  // protects all internal state
+
+  // We save the stack frame below the frame that calls user code.
+  // We do this because the address of the frame immediately below
+  // the user code changes between the call to UponLeavingGTest()
+  // and any calls to CurrentStackTrace() from within the user code.
+  void* caller_frame_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+  const char* file;
+  int line;
+  std::string message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+  : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. Reports the test part
+  // result in the current test.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. The implementation just
+  // delegates to the current global test part result reporter of *unit_test_.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class.  We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl {
+ public:
+  explicit UnitTestImpl(UnitTest* parent);
+  virtual ~UnitTestImpl();
+
+  // There are two different ways to register your own TestPartResultReporter.
+  // You can register your own repoter to listen either only for test results
+  // from the current thread or for results from all threads.
+  // By default, each per-thread test result repoter just passes a new
+  // TestPartResult to the global test result reporter, which registers the
+  // test part result for the currently running test.
+
+  // Returns the global test part result reporter.
+  TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+  // Sets the global test part result reporter.
+  void SetGlobalTestPartResultReporter(
+      TestPartResultReporterInterface* reporter);
+
+  // Returns the test part result reporter for the current thread.
+  TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+  // Sets the test part result reporter for the current thread.
+  void SetTestPartResultReporterForCurrentThread(
+      TestPartResultReporterInterface* reporter);
+
+  // Gets the number of successful test cases.
+  int successful_test_case_count() const;
+
+  // Gets the number of failed test cases.
+  int failed_test_case_count() const;
+
+  // Gets the number of all test cases.
+  int total_test_case_count() const;
+
+  // Gets the number of all test cases that contain at least one test
+  // that should run.
+  int test_case_to_run_count() const;
+
+  // Gets the number of successful tests.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Gets the number of all tests.
+  int total_test_count() const;
+
+  // Gets the number of tests that should run.
+  int test_to_run_count() const;
+
+  // Gets the time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+  // Gets the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns true iff the unit test passed (i.e. all test cases passed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the unit test failed (i.e. some test case failed
+  // or something outside of all tests failed).
+  bool Failed() const {
+    return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+  }
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  const TestCase* GetTestCase(int i) const {
+    const int index = GetElementOr(test_case_indices_, i, -1);
+    return index < 0 ? NULL : test_cases_[i];
+  }
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  TestCase* GetMutableTestCase(int i) {
+    const int index = GetElementOr(test_case_indices_, i, -1);
+    return index < 0 ? NULL : test_cases_[index];
+  }
+
+  // Provides access to the event listener list.
+  TestEventListeners* listeners() { return &listeners_; }
+
+  // Returns the TestResult for the test that's currently running, or
+  // the TestResult for the ad hoc test if no test is running.
+  TestResult* current_test_result();
+
+  // Returns the TestResult for the ad hoc test.
+  const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+  // Sets the OS stack trace getter.
+  //
+  // Does nothing if the input and the current OS stack trace getter
+  // are the same; otherwise, deletes the old getter and makes the
+  // input the current getter.
+  void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+  // Returns the current OS stack trace getter if it is not NULL;
+  // otherwise, creates an OsStackTraceGetter, makes it the current
+  // getter, and returns it.
+  OsStackTraceGetterInterface* os_stack_trace_getter();
+
+  // Returns the current OS stack trace as an std::string.
+  //
+  // The maximum number of stack frames to be included is specified by
+  // the gtest_stack_trace_depth flag.  The skip_count parameter
+  // specifies the number of top frames to be skipped, which doesn't
+  // count against the number of frames to be included.
+  //
+  // For example, if Foo() calls Bar(), which in turn calls
+  // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+  // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+  std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
+
+  // Finds and returns a TestCase with the given name.  If one doesn't
+  // exist, creates one and returns it.
+  //
+  // Arguments:
+  //
+  //   test_case_name: name of the test case
+  //   type_param:     the name of the test's type parameter, or NULL if
+  //                   this is not a typed or a type-parameterized test.
+  //   set_up_tc:      pointer to the function that sets up the test case
+  //   tear_down_tc:   pointer to the function that tears down the test case
+  TestCase* GetTestCase(const char* test_case_name,
+                        const char* type_param,
+                        Test::SetUpTestCaseFunc set_up_tc,
+                        Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Adds a TestInfo to the unit test.
+  //
+  // Arguments:
+  //
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  //   test_info:    the TestInfo object
+  void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc,
+                   TestInfo* test_info) {
+    // In order to support thread-safe death tests, we need to
+    // remember the original working directory when the test program
+    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
+    // the user may have changed the current directory before calling
+    // RUN_ALL_TESTS().  Therefore we capture the current directory in
+    // AddTestInfo(), which is called to register a TEST or TEST_F
+    // before main() is reached.
+    if (original_working_dir_.IsEmpty()) {
+      original_working_dir_.Set(FilePath::GetCurrentDir());
+      GTEST_CHECK_(!original_working_dir_.IsEmpty())
+          << "Failed to get the current working directory.";
+    }
+
+    GetTestCase(test_info->test_case_name(),
+                test_info->type_param(),
+                set_up_tc,
+                tear_down_tc)->AddTestInfo(test_info);
+  }
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+    return parameterized_test_registry_;
+  }
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Sets the TestCase object for the test that's currently running.
+  void set_current_test_case(TestCase* a_current_test_case) {
+    current_test_case_ = a_current_test_case;
+  }
+
+  // Sets the TestInfo object for the test that's currently running.  If
+  // current_test_info is NULL, the assertion results will be stored in
+  // ad_hoc_test_result_.
+  void set_current_test_info(TestInfo* a_current_test_info) {
+    current_test_info_ = a_current_test_info;
+  }
+
+  // Registers all parameterized tests defined using TEST_P and
+  // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+  // combination. This method can be called more then once; it has guards
+  // protecting from registering the tests more then once.  If
+  // value-parameterized tests are disabled, RegisterParameterizedTests is
+  // present but does nothing.
+  void RegisterParameterizedTests();
+
+  // Runs all tests in this UnitTest object, prints the result, and
+  // returns true if all tests are successful.  If any exception is
+  // thrown during a test, this test is considered to be failed, but
+  // the rest of the tests will still be run.
+  bool RunAllTests();
+
+  // Clears the results of all tests, except the ad hoc tests.
+  void ClearNonAdHocTestResult() {
+    ForEach(test_cases_, TestCase::ClearTestCaseResult);
+  }
+
+  // Clears the results of ad-hoc test assertions.
+  void ClearAdHocTestResult() {
+    ad_hoc_test_result_.Clear();
+  }
+
+  // Adds a TestProperty to the current TestResult object when invoked in a
+  // context of a test or a test case, or to the global property set. If the
+  // result already contains a property with the same key, the value will be
+  // updated.
+  void RecordProperty(const TestProperty& test_property);
+
+  enum ReactionToSharding {
+    HONOR_SHARDING_PROTOCOL,
+    IGNORE_SHARDING_PROTOCOL
+  };
+
+  // Matches the full name of each test against the user-specified
+  // filter to decide whether the test should run, then records the
+  // result in each TestCase and TestInfo object.
+  // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+  // based on sharding variables in the environment.
+  // Returns the number of tests that should run.
+  int FilterTests(ReactionToSharding shard_tests);
+
+  // Prints the names of the tests matching the user-specified filter flag.
+  void ListTestsMatchingFilter();
+
+  const TestCase* current_test_case() const { return current_test_case_; }
+  TestInfo* current_test_info() { return current_test_info_; }
+  const TestInfo* current_test_info() const { return current_test_info_; }
+
+  // Returns the vector of environments that need to be set-up/torn-down
+  // before/after the tests are run.
+  std::vector<Environment*>& environments() { return environments_; }
+
+  // Getters for the per-thread Google Test trace stack.
+  std::vector<TraceInfo>& gtest_trace_stack() {
+    return *(gtest_trace_stack_.pointer());
+  }
+  const std::vector<TraceInfo>& gtest_trace_stack() const {
+    return gtest_trace_stack_.get();
+  }
+
+#if GTEST_HAS_DEATH_TEST
+  void InitDeathTestSubprocessControlInfo() {
+    internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+  }
+  // Returns a pointer to the parsed --gtest_internal_run_death_test
+  // flag, or NULL if that flag was not specified.
+  // This information is useful only in a death test child process.
+  // Must not be called before a call to InitGoogleTest.
+  const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+    return internal_run_death_test_flag_.get();
+  }
+
+  // Returns a pointer to the current death test factory.
+  internal::DeathTestFactory* death_test_factory() {
+    return death_test_factory_.get();
+  }
+
+  void SuppressTestEventsIfInSubprocess();
+
+  friend class ReplaceDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+
+  // Initializes the event listener performing XML output as specified by
+  // UnitTestOptions. Must not be called before InitGoogleTest.
+  void ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+  // Initializes the event listener for streaming test results to a socket.
+  // Must not be called before InitGoogleTest.
+  void ConfigureStreamingOutput();
+#endif
+
+  // Performs initialization dependent upon flag values obtained in
+  // ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
+  // ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
+  // this function is also called from RunAllTests.  Since this function can be
+  // called more than once, it has to be idempotent.
+  void PostFlagParsingInit();
+
+  // Gets the random seed used at the start of the current test iteration.
+  int random_seed() const { return random_seed_; }
+
+  // Gets the random number generator.
+  internal::Random* random() { return &random_; }
+
+  // Shuffles all test cases, and the tests within each test case,
+  // making sure that death tests are still run first.
+  void ShuffleTests();
+
+  // Restores the test cases and tests to their order before the first shuffle.
+  void UnshuffleTests();
+
+  // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
+  // UnitTest::Run() starts.
+  bool catch_exceptions() const { return catch_exceptions_; }
+
+ private:
+  friend class ::testing::UnitTest;
+
+  // Used by UnitTest::Run() to capture the state of
+  // GTEST_FLAG(catch_exceptions) at the moment it starts.
+  void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
+
+  // The UnitTest object that owns this implementation object.
+  UnitTest* const parent_;
+
+  // The working directory when the first TEST() or TEST_F() was
+  // executed.
+  internal::FilePath original_working_dir_;
+
+  // The default test part result reporters.
+  DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+  DefaultPerThreadTestPartResultReporter
+      default_per_thread_test_part_result_reporter_;
+
+  // Points to (but doesn't own) the global test part result reporter.
+  TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+  // Protects read and write access to global_test_part_result_reporter_.
+  internal::Mutex global_test_part_result_reporter_mutex_;
+
+  // Points to (but doesn't own) the per-thread test part result reporter.
+  internal::ThreadLocal<TestPartResultReporterInterface*>
+      per_thread_test_part_result_reporter_;
+
+  // The vector of environments that need to be set-up/torn-down
+  // before/after the tests are run.
+  std::vector<Environment*> environments_;
+
+  // The vector of TestCases in their original order.  It owns the
+  // elements in the vector.
+  std::vector<TestCase*> test_cases_;
+
+  // Provides a level of indirection for the test case list to allow
+  // easy shuffling and restoring the test case order.  The i-th
+  // element of this vector is the index of the i-th test case in the
+  // shuffled order.
+  std::vector<int> test_case_indices_;
+
+#if GTEST_HAS_PARAM_TEST
+  // ParameterizedTestRegistry object used to register value-parameterized
+  // tests.
+  internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+  // Indicates whether RegisterParameterizedTests() has been called already.
+  bool parameterized_tests_registered_;
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Index of the last death test case registered.  Initially -1.
+  int last_death_test_case_;
+
+  // This points to the TestCase for the currently running test.  It
+  // changes as Google Test goes through one test case after another.
+  // When no test is running, this is set to NULL and Google Test
+  // stores assertion results in ad_hoc_test_result_.  Initially NULL.
+  TestCase* current_test_case_;
+
+  // This points to the TestInfo for the currently running test.  It
+  // changes as Google Test goes through one test after another.  When
+  // no test is running, this is set to NULL and Google Test stores
+  // assertion results in ad_hoc_test_result_.  Initially NULL.
+  TestInfo* current_test_info_;
+
+  // Normally, a user only writes assertions inside a TEST or TEST_F,
+  // or inside a function called by a TEST or TEST_F.  Since Google
+  // Test keeps track of which test is current running, it can
+  // associate such an assertion with the test it belongs to.
+  //
+  // If an assertion is encountered when no TEST or TEST_F is running,
+  // Google Test attributes the assertion result to an imaginary "ad hoc"
+  // test, and records the result in ad_hoc_test_result_.
+  TestResult ad_hoc_test_result_;
+
+  // The list of event listeners that can be used to track events inside
+  // Google Test.
+  TestEventListeners listeners_;
+
+  // The OS stack trace getter.  Will be deleted when the UnitTest
+  // object is destructed.  By default, an OsStackTraceGetter is used,
+  // but the user can set this field to use a custom getter if that is
+  // desired.
+  OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+  // True iff PostFlagParsingInit() has been called.
+  bool post_flag_parse_init_performed_;
+
+  // The random number seed used at the beginning of the test run.
+  int random_seed_;
+
+  // Our random number generator.
+  internal::Random random_;
+
+  // The time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp_;
+
+  // How long the test took to run, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+  // The decomposed components of the gtest_internal_run_death_test flag,
+  // parsed when RUN_ALL_TESTS is called.
+  internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+  internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif  // GTEST_HAS_DEATH_TEST
+
+  // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+  internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+  // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+  // starts.
+  bool catch_exceptions_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+};  // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+  return UnitTest::GetInstance()->impl();
+}
+
+#if GTEST_USES_SIMPLE_RE
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsAsciiDigit(char ch);
+GTEST_API_ bool IsAsciiPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsAsciiWhiteSpace(char ch);
+GTEST_API_ bool IsAsciiWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+#endif  // GTEST_USES_SIMPLE_RE
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+GTEST_API_ std::string GetLastErrnoDescription();
+
+# if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle {
+ public:
+  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+  explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+  ~AutoHandle() { Reset(); }
+
+  HANDLE Get() const { return handle_; }
+  void Reset() { Reset(INVALID_HANDLE_VALUE); }
+  void Reset(HANDLE handle) {
+    if (handle != handle_) {
+      if (handle_ != INVALID_HANDLE_VALUE)
+        ::CloseHandle(handle_);
+      handle_ = handle;
+    }
+  }
+
+ private:
+  HANDLE handle_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+# endif  // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter.  Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+  // Fail fast if the given string does not begin with a digit;
+  // this bypasses strtoXXX's "optional leading whitespace and plus
+  // or minus sign" semantics, which are undesirable here.
+  if (str.empty() || !IsDigit(str[0])) {
+    return false;
+  }
+  errno = 0;
+
+  char* end;
+  // BiggestConvertible is the largest integer type that system-provided
+  // string-to-number conversion routines can return.
+
+# if GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+  // MSVC and C++ Builder define __int64 instead of the standard long long.
+  typedef unsigned __int64 BiggestConvertible;
+  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+
+# else
+
+  typedef unsigned long long BiggestConvertible;  // NOLINT
+  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+
+# endif  // GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+  const bool parse_success = *end == '\0' && errno == 0;
+
+  // TODO(vladl@google.com): Convert this to compile time assertion when it is
+  // available.
+  GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+  const Integer result = static_cast<Integer>(parsed);
+  if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+    *number = result;
+    return true;
+  }
+  return false;
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor {
+ public:
+  static void RecordProperty(TestResult* test_result,
+                             const std::string& xml_element,
+                             const TestProperty& property) {
+    test_result->RecordProperty(xml_element, property);
+  }
+
+  static void ClearTestPartResults(TestResult* test_result) {
+    test_result->ClearTestPartResults();
+  }
+
+  static const std::vector<testing::TestPartResult>& test_part_results(
+      const TestResult& test_result) {
+    return test_result.test_part_results();
+  }
+};
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener {
+ public:
+  // Abstract base class for writing strings to a socket.
+  class AbstractSocketWriter {
+   public:
+    virtual ~AbstractSocketWriter() {}
+
+    // Sends a string to the socket.
+    virtual void Send(const string& message) = 0;
+
+    // Closes the socket.
+    virtual void CloseConnection() {}
+
+    // Sends a string and a newline to the socket.
+    void SendLn(const string& message) {
+      Send(message + "\n");
+    }
+  };
+
+  // Concrete class for actually writing strings to a socket.
+  class SocketWriter : public AbstractSocketWriter {
+   public:
+    SocketWriter(const string& host, const string& port)
+        : sockfd_(-1), host_name_(host), port_num_(port) {
+      MakeConnection();
+    }
+
+    virtual ~SocketWriter() {
+      if (sockfd_ != -1)
+        CloseConnection();
+    }
+
+    // Sends a string to the socket.
+    virtual void Send(const string& message) {
+      GTEST_CHECK_(sockfd_ != -1)
+          << "Send() can be called only when there is a connection.";
+
+      const int len = static_cast<int>(message.length());
+      if (write(sockfd_, message.c_str(), len) != len) {
+        GTEST_LOG_(WARNING)
+            << "stream_result_to: failed to stream to "
+            << host_name_ << ":" << port_num_;
+      }
+    }
+
+   private:
+    // Creates a client socket and connects to the server.
+    void MakeConnection();
+
+    // Closes the socket.
+    void CloseConnection() {
+      GTEST_CHECK_(sockfd_ != -1)
+          << "CloseConnection() can be called only when there is a connection.";
+
+      close(sockfd_);
+      sockfd_ = -1;
+    }
+
+    int sockfd_;  // socket file descriptor
+    const string host_name_;
+    const string port_num_;
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
+  };  // class SocketWriter
+
+  // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+  static string UrlEncode(const char* str);
+
+  StreamingListener(const string& host, const string& port)
+      : socket_writer_(new SocketWriter(host, port)) { Start(); }
+
+  explicit StreamingListener(AbstractSocketWriter* socket_writer)
+      : socket_writer_(socket_writer) { Start(); }
+
+  void OnTestProgramStart(const UnitTest& /* unit_test */) {
+    SendLn("event=TestProgramStart");
+  }
+
+  void OnTestProgramEnd(const UnitTest& unit_test) {
+    // Note that Google Test current only report elapsed time for each
+    // test iteration, not for the entire test program.
+    SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
+
+    // Notify the streaming server to stop.
+    socket_writer_->CloseConnection();
+  }
+
+  void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
+    SendLn("event=TestIterationStart&iteration=" +
+           StreamableToString(iteration));
+  }
+
+  void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
+    SendLn("event=TestIterationEnd&passed=" +
+           FormatBool(unit_test.Passed()) + "&elapsed_time=" +
+           StreamableToString(unit_test.elapsed_time()) + "ms");
+  }
+
+  void OnTestCaseStart(const TestCase& test_case) {
+    SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
+  }
+
+  void OnTestCaseEnd(const TestCase& test_case) {
+    SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
+           + "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
+           + "ms");
+  }
+
+  void OnTestStart(const TestInfo& test_info) {
+    SendLn(std::string("event=TestStart&name=") + test_info.name());
+  }
+
+  void OnTestEnd(const TestInfo& test_info) {
+    SendLn("event=TestEnd&passed=" +
+           FormatBool((test_info.result())->Passed()) +
+           "&elapsed_time=" +
+           StreamableToString((test_info.result())->elapsed_time()) + "ms");
+  }
+
+  void OnTestPartResult(const TestPartResult& test_part_result) {
+    const char* file_name = test_part_result.file_name();
+    if (file_name == NULL)
+      file_name = "";
+    SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
+           "&line=" + StreamableToString(test_part_result.line_number()) +
+           "&message=" + UrlEncode(test_part_result.message()));
+  }
+
+ private:
+  // Sends the given message and a newline to the socket.
+  void SendLn(const string& message) { socket_writer_->SendLn(message); }
+
+  // Called at the start of streaming to notify the receiver what
+  // protocol we are using.
+  void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
+
+  string FormatBool(bool value) { return value ? "1" : "0"; }
+
+  const scoped_ptr<AbstractSocketWriter> socket_writer_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
+};  // class StreamingListener
+
+#endif  // GTEST_CAN_STREAM_RESULTS_
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+# define vsnprintf _vsnprintf
+#endif  // GTEST_OS_WINDOWS
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+bool g_help_flag = false;
+
+}  // namespace internal
+
+static const char* GetDefaultFilter() {
+  return kUniversalFilter;
+}
+
+GTEST_DEFINE_bool_(
+    also_run_disabled_tests,
+    internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+    "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+    break_on_failure,
+    internal::BoolFromGTestEnv("break_on_failure", false),
+    "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+    catch_exceptions,
+    internal::BoolFromGTestEnv("catch_exceptions", true),
+    "True iff " GTEST_NAME_
+    " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+    color,
+    internal::StringFromGTestEnv("color", "auto"),
+    "Whether to use colors in the output.  Valid values: yes, no, "
+    "and auto.  'auto' means to use colors if the output is "
+    "being sent to a terminal and the TERM environment variable "
+    "is set to a terminal type that supports colors.");
+
+GTEST_DEFINE_string_(
+    filter,
+    internal::StringFromGTestEnv("filter", GetDefaultFilter()),
+    "A colon-separated list of glob (not regex) patterns "
+    "for filtering the tests to run, optionally followed by a "
+    "'-' and a : separated list of negative patterns (tests to "
+    "exclude).  A test is run if it matches one of the positive "
+    "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+                   "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+    output,
+    internal::StringFromGTestEnv("output", ""),
+    "A format (currently must be \"xml\"), optionally followed "
+    "by a colon and an output file name or directory. A directory "
+    "is indicated by a trailing pathname separator. "
+    "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+    "If a directory is specified, output files will be created "
+    "within that directory, with file-names based on the test "
+    "executable's name and, if necessary, made unique by adding "
+    "digits.");
+
+GTEST_DEFINE_bool_(
+    print_time,
+    internal::BoolFromGTestEnv("print_time", true),
+    "True iff " GTEST_NAME_
+    " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+    random_seed,
+    internal::Int32FromGTestEnv("random_seed", 0),
+    "Random number seed to use when shuffling test orders.  Must be in range "
+    "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+    repeat,
+    internal::Int32FromGTestEnv("repeat", 1),
+    "How many times to repeat each test.  Specify a negative number "
+    "for repeating forever.  Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(
+    show_internal_stack_frames, false,
+    "True iff " GTEST_NAME_ " should include internal stack frames when "
+    "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+    shuffle,
+    internal::BoolFromGTestEnv("shuffle", false),
+    "True iff " GTEST_NAME_
+    " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+    stack_trace_depth,
+    internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+    "The maximum number of stack frames to print when an "
+    "assertion fails.  The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_string_(
+    stream_result_to,
+    internal::StringFromGTestEnv("stream_result_to", ""),
+    "This flag specifies the host name and the port number on which to stream "
+    "test results. Example: \"localhost:555\". The flag is effective only on "
+    "Linux.");
+
+GTEST_DEFINE_bool_(
+    throw_on_failure,
+    internal::BoolFromGTestEnv("throw_on_failure", false),
+    "When this flag is specified, a failed assertion will throw an exception "
+    "if exceptions are enabled or exit the program with a non-zero code "
+    "otherwise.");
+
+namespace internal {
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG).  Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range) {
+  // These constants are the same as are used in glibc's rand(3).
+  state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+  GTEST_CHECK_(range > 0)
+      << "Cannot generate a number in the range [0, 0).";
+  GTEST_CHECK_(range <= kMaxRange)
+      << "Generation of a number in [0, " << range << ") was requested, "
+      << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+  // Converting via modulus introduces a bit of downward bias, but
+  // it's simple, and a linear congruential generator isn't too good
+  // to begin with.
+  return state_ % range;
+}
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test.  Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test.  g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called.  We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+GTEST_API_ int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a vector of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
+                               int (TestCase::*method)() const) {
+  int sum = 0;
+  for (size_t i = 0; i < case_list.size(); i++) {
+    sum += (case_list[i]->*method)();
+  }
+  return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+  return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+                           const char* file,
+                           int line,
+                           const char* message)
+    : data_(new AssertHelperData(type, file, line, message)) {
+}
+
+AssertHelper::~AssertHelper() {
+  delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+  UnitTest::GetInstance()->
+    AddTestPartResult(data_->type, data_->file, data_->line,
+                      AppendUserMessage(data_->message, message),
+                      UnitTest::GetInstance()->impl()
+                      ->CurrentOsStackTraceExceptTop(1)
+                      // Skips the stack frame for this function itself.
+                      );  // NOLINT
+}
+
+// Mutex for linked pointers.
+GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// Application pathname gotten in InitGoogleTest.
+std::string g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+  FilePath result;
+
+#if GTEST_OS_WINDOWS
+  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+  result.Set(FilePath(g_executable_path));
+#endif  // GTEST_OS_WINDOWS
+
+  return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+std::string UnitTestOptions::GetOutputFormat() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL) return std::string("");
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  return (colon == NULL) ?
+      std::string(gtest_output_flag) :
+      std::string(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL)
+    return "";
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  if (colon == NULL)
+    return internal::FilePath::ConcatPaths(
+        internal::FilePath(
+            UnitTest::GetInstance()->original_working_dir()),
+        internal::FilePath(kDefaultOutputFile)).string();
+
+  internal::FilePath output_name(colon + 1);
+  if (!output_name.IsAbsolutePath())
+    // TODO(wan@google.com): on Windows \some\path is not an absolute
+    // path (as its meaning depends on the current drive), yet the
+    // following logic for turning it into an absolute path is wrong.
+    // Fix it.
+    output_name = internal::FilePath::ConcatPaths(
+        internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+        internal::FilePath(colon + 1));
+
+  if (!output_name.IsDirectory())
+    return output_name.string();
+
+  internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+      output_name, internal::GetCurrentExecutableName(),
+      GetOutputFormat().c_str()));
+  return result.string();
+}
+
+// Returns true iff the wildcard pattern matches the string.  The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+                                           const char *str) {
+  switch (*pattern) {
+    case '\0':
+    case ':':  // Either ':' or '\0' marks the end of the pattern.
+      return *str == '\0';
+    case '?':  // Matches any single character.
+      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+    case '*':  // Matches any string (possibly empty) of characters.
+      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+          PatternMatchesString(pattern + 1, str);
+    default:  // Non-special character.  Matches itself.
+      return *pattern == *str &&
+          PatternMatchesString(pattern + 1, str + 1);
+  }
+}
+
+bool UnitTestOptions::MatchesFilter(
+    const std::string& name, const char* filter) {
+  const char *cur_pattern = filter;
+  for (;;) {
+    if (PatternMatchesString(cur_pattern, name.c_str())) {
+      return true;
+    }
+
+    // Finds the next pattern in the filter.
+    cur_pattern = strchr(cur_pattern, ':');
+
+    // Returns if no more pattern can be found.
+    if (cur_pattern == NULL) {
+      return false;
+    }
+
+    // Skips the pattern separater (the ':' character).
+    cur_pattern++;
+  }
+}
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name,
+                                        const std::string &test_name) {
+  const std::string& full_name = test_case_name + "." + test_name.c_str();
+
+  // Split --gtest_filter at '-', if there is one, to separate into
+  // positive filter and negative filter portions
+  const char* const p = GTEST_FLAG(filter).c_str();
+  const char* const dash = strchr(p, '-');
+  std::string positive;
+  std::string negative;
+  if (dash == NULL) {
+    positive = GTEST_FLAG(filter).c_str();  // Whole string is a positive filter
+    negative = "";
+  } else {
+    positive = std::string(p, dash);   // Everything up to the dash
+    negative = std::string(dash + 1);  // Everything after the dash
+    if (positive.empty()) {
+      // Treat '-test1' as the same as '*-test1'
+      positive = kUniversalFilter;
+    }
+  }
+
+  // A filter is a colon-separated list of patterns.  It matches a
+  // test if any pattern in it matches the test.
+  return (MatchesFilter(full_name, positive.c_str()) &&
+          !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_HAS_SEH
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+  // Google Test should handle a SEH exception if:
+  //   1. the user wants it to, AND
+  //   2. this is not a breakpoint exception, AND
+  //   3. this is not a C++ exception (VC++ implements them via SEH,
+  //      apparently).
+  //
+  // SEH exception code for C++ exceptions.
+  // (see http://support.microsoft.com/kb/185294 for more information).
+  const DWORD kCxxExceptionCode = 0xe06d7363;
+
+  bool should_handle = true;
+
+  if (!GTEST_FLAG(catch_exceptions))
+    should_handle = false;
+  else if (exception_code == EXCEPTION_BREAKPOINT)
+    should_handle = false;
+  else if (exception_code == kCxxExceptionCode)
+    should_handle = false;
+
+  return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+#endif  // GTEST_HAS_SEH
+
+}  // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    TestPartResultArray* result)
+    : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+      result_(result) {
+  Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    InterceptMode intercept_mode, TestPartResultArray* result)
+    : intercept_mode_(intercept_mode),
+      result_(result) {
+  Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    old_reporter_ = impl->GetGlobalTestPartResultReporter();
+    impl->SetGlobalTestPartResultReporter(this);
+  } else {
+    old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+    impl->SetTestPartResultReporterForCurrentThread(this);
+  }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    impl->SetGlobalTestPartResultReporter(old_reporter_);
+  } else {
+    impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+  }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test.  We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test.  This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X.  The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code.  GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+  return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+                              const char* /* type_expr */,
+                              const char* /* substr_expr */,
+                              const TestPartResultArray& results,
+                              TestPartResult::Type type,
+                              const string& substr) {
+  const std::string expected(type == TestPartResult::kFatalFailure ?
+                        "1 fatal failure" :
+                        "1 non-fatal failure");
+  Message msg;
+  if (results.size() != 1) {
+    msg << "Expected: " << expected << "\n"
+        << "  Actual: " << results.size() << " failures";
+    for (int i = 0; i < results.size(); i++) {
+      msg << "\n" << results.GetTestPartResult(i);
+    }
+    return AssertionFailure() << msg;
+  }
+
+  const TestPartResult& r = results.GetTestPartResult(0);
+  if (r.type() != type) {
+    return AssertionFailure() << "Expected: " << expected << "\n"
+                              << "  Actual:\n"
+                              << r;
+  }
+
+  if (strstr(r.message(), substr.c_str()) == NULL) {
+    return AssertionFailure() << "Expected: " << expected << " containing \""
+                              << substr << "\"\n"
+                              << "  Actual:\n"
+                              << r;
+  }
+
+  return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+    const TestPartResultArray* results,
+    TestPartResult::Type type,
+    const string& substr)
+    : results_(results),
+      type_(type),
+      substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+  EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->current_test_result()->AddTestPartResult(result);
+  unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+    TestPartResultReporterInterface* reporter) {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+  return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+    TestPartResultReporterInterface* reporter) {
+  per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+  return CountIf(test_cases_, TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+  return CountIf(test_cases_, TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+  return static_cast<int>(test_cases_.size());
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+  return CountIf(test_cases_, ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const {
+  return SumOverTestCaseList(test_cases_,
+                             &TestCase::reportable_disabled_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+  (void)skip_count;
+  return "";
+}
+
+// Returns the current time in milliseconds.
+TimeInMillis GetTimeInMillis() {
+#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
+  // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
+  // http://analogous.blogspot.com/2005/04/epoch.html
+  const TimeInMillis kJavaEpochToWinFileTimeDelta =
+    static_cast<TimeInMillis>(116444736UL) * 100000UL;
+  const DWORD kTenthMicrosInMilliSecond = 10000;
+
+  SYSTEMTIME now_systime;
+  FILETIME now_filetime;
+  ULARGE_INTEGER now_int64;
+  // TODO(kenton@google.com): Shouldn't this just use
+  //   GetSystemTimeAsFileTime()?
+  GetSystemTime(&now_systime);
+  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+    now_int64.LowPart = now_filetime.dwLowDateTime;
+    now_int64.HighPart = now_filetime.dwHighDateTime;
+    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+      kJavaEpochToWinFileTimeDelta;
+    return now_int64.QuadPart;
+  }
+  return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+  __timeb64 now;
+
+# ifdef _MSC_VER
+
+  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+  // (deprecated function) there.
+  // TODO(kenton@google.com): Use GetTickCount()?  Or use
+  //   SystemTimeToFileTime()
+#  pragma warning(push)          // Saves the current warning state.
+#  pragma warning(disable:4996)  // Temporarily disables warning 4996.
+  _ftime64(&now);
+#  pragma warning(pop)           // Restores the warning state.
+# else
+
+  _ftime64(&now);
+
+# endif  // _MSC_VER
+
+  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+# error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String.
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+  if (!ansi) return NULL;
+  const int length = strlen(ansi);
+  const int unicode_length =
+      MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                          NULL, 0);
+  WCHAR* unicode = new WCHAR[unicode_length + 1];
+  MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                      unicode, unicode_length);
+  unicode[unicode_length] = 0;
+  return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str)  {
+  if (!utf16_str) return NULL;
+  const int ansi_length =
+      WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                          NULL, 0, NULL, NULL);
+  char* ansi = new char[ansi_length + 1];
+  WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                      ansi, ansi_length, NULL, NULL);
+  ansi[ansi_length] = 0;
+  return ansi;
+}
+
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings.  Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+  if ( lhs == NULL ) return rhs == NULL;
+
+  if ( rhs == NULL ) return false;
+
+  return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+                                     Message* msg) {
+  for (size_t i = 0; i != length; ) {  // NOLINT
+    if (wstr[i] != L'\0') {
+      *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+      while (i != length && wstr[i] != L'\0')
+        i++;
+    } else {
+      *msg << '\0';
+      i++;
+    }
+  }
+}
+
+#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+}  // namespace internal
+
+// Constructs an empty Message.
+// We allocate the stringstream separately because otherwise each use of
+// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+// stack frame leading to huge stack frames in some cases; gcc does not reuse
+// the stack space.
+Message::Message() : ss_(new ::std::stringstream) {
+  // By default, we want there to be enough precision when printing
+  // a double to a Message.
+  *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+}
+
+// These two overloads allow streaming a wide C string to a Message
+// using the UTF-8 encoding.
+Message& Message::operator <<(const wchar_t* wide_c_str) {
+  return *this << internal::String::ShowWideCString(wide_c_str);
+}
+Message& Message::operator <<(wchar_t* wide_c_str) {
+  return *this << internal::String::ShowWideCString(wide_c_str);
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// Gets the text streamed to this object so far as an std::string.
+// Each '\0' character in the buffer is replaced with "\\0".
+std::string Message::GetString() const {
+  return internal::StringStreamToString(ss_.get());
+}
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+    : success_(other.success_),
+      message_(other.message_.get() != NULL ?
+               new ::std::string(*other.message_) :
+               static_cast< ::std::string*>(NULL)) {
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+  AssertionResult negation(!success_);
+  if (message_.get() != NULL)
+    negation << *message_;
+  return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+  return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure() {
+  return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message) {
+  return AssertionFailure() << message;
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+                          const char* actual_expression,
+                          const std::string& expected_value,
+                          const std::string& actual_value,
+                          bool ignoring_case) {
+  Message msg;
+  msg << "Value of: " << actual_expression;
+  if (actual_value != actual_expression) {
+    msg << "\n  Actual: " << actual_value;
+  }
+
+  msg << "\nExpected: " << expected_expression;
+  if (ignoring_case) {
+    msg << " (ignoring case)";
+  }
+  if (expected_value != expected_expression) {
+    msg << "\nWhich is: " << expected_value;
+  }
+
+  return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+std::string GetBoolAssertionFailureMessage(
+    const AssertionResult& assertion_result,
+    const char* expression_text,
+    const char* actual_predicate_value,
+    const char* expected_predicate_value) {
+  const char* actual_message = assertion_result.message();
+  Message msg;
+  msg << "Value of: " << expression_text
+      << "\n  Actual: " << actual_predicate_value;
+  if (actual_message[0] != '\0')
+    msg << " (" << actual_message << ")";
+  msg << "\nExpected: " << expected_predicate_value;
+  return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+                                     const char* expr2,
+                                     const char* abs_error_expr,
+                                     double val1,
+                                     double val2,
+                                     double abs_error) {
+  const double diff = fabs(val1 - val2);
+  if (diff <= abs_error) return AssertionSuccess();
+
+  // TODO(wan): do not print the value of an expression if it's
+  // already a literal.
+  return AssertionFailure()
+      << "The difference between " << expr1 << " and " << expr2
+      << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+      << expr1 << " evaluates to " << val1 << ",\n"
+      << expr2 << " evaluates to " << val2 << ", and\n"
+      << abs_error_expr << " evaluates to " << abs_error << ".";
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+                                const char* expr2,
+                                RawType val1,
+                                RawType val2) {
+  // Returns success if val1 is less than val2,
+  if (val1 < val2) {
+    return AssertionSuccess();
+  }
+
+  // or if val1 is almost equal to val2.
+  const FloatingPoint<RawType> lhs(val1), rhs(val2);
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  // Note that the above two checks will both fail if either val1 or
+  // val2 is NaN, as the IEEE floating-point standard requires that
+  // any predicate involving a NaN must return false.
+
+  ::std::stringstream val1_ss;
+  val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val1;
+
+  ::std::stringstream val2_ss;
+  val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val2;
+
+  return AssertionFailure()
+      << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+      << "  Actual: " << StringStreamToString(&val1_ss) << " vs "
+      << StringStreamToString(&val2_ss);
+}
+
+}  // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+                        float val1, float val2) {
+  return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                         double val1, double val2) {
+  return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            BiggestInt expected,
+                            BiggestInt actual) {
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   BiggestInt val1, BiggestInt val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    return AssertionFailure() \
+        << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+  }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const char* expected,
+                               const char* actual) {
+  if (String::CStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                   const char* actual_expression,
+                                   const char* expected,
+                                   const char* actual) {
+  if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const char* s1,
+                               const char* s2) {
+  if (!String::CStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+                              << s2_expression << "), actual: \""
+                              << s1 << "\" vs \"" << s2 << "\"";
+  }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                   const char* s2_expression,
+                                   const char* s1,
+                                   const char* s2) {
+  if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    return AssertionFailure()
+        << "Expected: (" << s1_expression << ") != ("
+        << s2_expression << ") (ignoring case), actual: \""
+        << s1 << "\" vs \"" << s2 << "\"";
+  }
+}
+
+}  // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack.  NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+                     const StringType& haystack) {
+  return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+    bool expected_to_be_substring,
+    const char* needle_expr, const char* haystack_expr,
+    const StringType& needle, const StringType& haystack) {
+  if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+    return AssertionSuccess();
+
+  const bool is_wide_string = sizeof(needle[0]) > 1;
+  const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+  return AssertionFailure()
+      << "Value of: " << needle_expr << "\n"
+      << "  Actual: " << begin_string_quote << needle << "\"\n"
+      << "Expected: " << (expected_to_be_substring ? "" : "not ")
+      << "a substring of " << haystack_expr << "\n"
+      << "Which is: " << begin_string_quote << haystack << "\"";
+}
+
+}  // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+                                     const char* expected,
+                                     long hr) {  // NOLINT
+# if GTEST_OS_WINDOWS_MOBILE
+
+  // Windows CE doesn't support FormatMessage.
+  const char error_text[] = "";
+
+# else
+
+  // Looks up the human-readable system message for the HRESULT code
+  // and since we're not passing any params to FormatMessage, we don't
+  // want inserts expanded.
+  const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS;
+  const DWORD kBufSize = 4096;
+  // Gets the system's human readable message string for this HRESULT.
+  char error_text[kBufSize] = { '\0' };
+  DWORD message_length = ::FormatMessageA(kFlags,
+                                          0,  // no source, we're asking system
+                                          hr,  // the error
+                                          0,  // no line width restrictions
+                                          error_text,  // output buffer
+                                          kBufSize,  // buf size
+                                          NULL);  // no arguments for inserts
+  // Trims tailing white space (FormatMessage leaves a trailing CR-LF)
+  for (; message_length && IsSpace(error_text[message_length - 1]);
+          --message_length) {
+    error_text[message_length - 1] = '\0';
+  }
+
+# endif  // GTEST_OS_WINDOWS_MOBILE
+
+  const std::string error_hex("0x" + String::FormatHexInt(hr));
+  return ::testing::AssertionFailure()
+      << "Expected: " << expr << " " << expected << ".\n"
+      << "  Actual: " << error_hex << " " << error_text << "\n";
+}
+
+}  // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) {  // NOLINT
+  if (SUCCEEDED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) {  // NOLINT
+  if (FAILED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif  // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length   Encoding
+//   0 -  7 bits       0xxxxxxx
+//   8 - 11 bits       110xxxxx 10xxxxxx
+//  12 - 16 bits       1110xxxx 10xxxxxx 10xxxxxx
+//  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern.  Returns the n
+// lowest bits.  As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+  *bits >>= n;
+  return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+std::string CodePointToUtf8(UInt32 code_point) {
+  if (code_point > kMaxCodePoint4) {
+    return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
+  }
+
+  char str[5];  // Big enough for the largest valid code point.
+  if (code_point <= kMaxCodePoint1) {
+    str[1] = '\0';
+    str[0] = static_cast<char>(code_point);                          // 0xxxxxxx
+  } else if (code_point <= kMaxCodePoint2) {
+    str[2] = '\0';
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xC0 | code_point);                   // 110xxxxx
+  } else if (code_point <= kMaxCodePoint3) {
+    str[3] = '\0';
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xE0 | code_point);                   // 1110xxxx
+  } else {  // code_point <= kMaxCodePoint4
+    str[4] = '\0';
+    str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xF0 | code_point);                   // 11110xxx
+  }
+  return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+  return sizeof(wchar_t) == 2 &&
+      (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+                                                    wchar_t second) {
+  const UInt32 mask = (1 << 10) - 1;
+  return (sizeof(wchar_t) == 2) ?
+      (((first & mask) << 10) | (second & mask)) + 0x10000 :
+      // This function should not be called when the condition is
+      // false, but we provide a sensible default in case it is.
+      static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
+  if (num_chars == -1)
+    num_chars = static_cast<int>(wcslen(str));
+
+  ::std::stringstream stream;
+  for (int i = 0; i < num_chars; ++i) {
+    UInt32 unicode_code_point;
+
+    if (str[i] == L'\0') {
+      break;
+    } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+      unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+                                                                 str[i + 1]);
+      i++;
+    } else {
+      unicode_code_point = static_cast<UInt32>(str[i]);
+    }
+
+    stream << CodePointToUtf8(unicode_code_point);
+  }
+  return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to an std::string using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+std::string String::ShowWideCString(const wchar_t * wide_c_str) {
+  if (wide_c_str == NULL)  return "(null)";
+
+  return internal::WideStringToUtf8(wide_c_str, -1);
+}
+
+// Compares two wide C strings.  Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+  if (lhs == NULL) return rhs == NULL;
+
+  if (rhs == NULL) return false;
+
+  return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const wchar_t* expected,
+                               const wchar_t* actual) {
+  if (String::WideCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const wchar_t* s1,
+                               const wchar_t* s2) {
+  if (!String::WideCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  }
+
+  return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+                            << s2_expression << "), actual: "
+                            << PrintToString(s1)
+                            << " vs " << PrintToString(s2);
+}
+
+// Compares two C strings, ignoring case.  Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s).  A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+  if (lhs == NULL)
+    return rhs == NULL;
+  if (rhs == NULL)
+    return false;
+  return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                              const wchar_t* rhs) {
+  if (lhs == NULL) return rhs == NULL;
+
+  if (rhs == NULL) return false;
+
+#if GTEST_OS_WINDOWS
+  return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
+  return wcscasecmp(lhs, rhs) == 0;
+#else
+  // Android, Mac OS X and Cygwin don't define wcscasecmp.
+  // Other unknown OSes may not define it either.
+  wint_t left, right;
+  do {
+    left = towlower(*lhs++);
+    right = towlower(*rhs++);
+  } while (left && left == right);
+  return left == right;
+#endif  // OS selector
+}
+
+// Returns true iff str ends with the given suffix, ignoring case.
+// Any string is considered to end with an empty suffix.
+bool String::EndsWithCaseInsensitive(
+    const std::string& str, const std::string& suffix) {
+  const size_t str_len = str.length();
+  const size_t suffix_len = suffix.length();
+  return (str_len >= suffix_len) &&
+         CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
+                                      suffix.c_str());
+}
+
+// Formats an int value as "%02d".
+std::string String::FormatIntWidth2(int value) {
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << value;
+  return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value) {
+  std::stringstream ss;
+  ss << std::hex << std::uppercase << value;
+  return ss.str();
+}
+
+// Formats a byte as "%02X".
+std::string String::FormatByte(unsigned char value) {
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
+     << static_cast<unsigned int>(value);
+  return ss.str();
+}
+
+// Converts the buffer in a stringstream to an std::string, converting NUL
+// bytes to "\\0" along the way.
+std::string StringStreamToString(::std::stringstream* ss) {
+  const ::std::string& str = ss->str();
+  const char* const start = str.c_str();
+  const char* const end = start + str.length();
+
+  std::string result;
+  result.reserve(2 * (end - start));
+  for (const char* ch = start; ch != end; ++ch) {
+    if (*ch == '\0') {
+      result += "\\0";  // Replaces NUL with "\\0";
+    } else {
+      result += *ch;
+    }
+  }
+
+  return result;
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+std::string AppendUserMessage(const std::string& gtest_msg,
+                              const Message& user_msg) {
+  // Appends the user message if it's non-empty.
+  const std::string user_msg_string = user_msg.GetString();
+  if (user_msg_string.empty()) {
+    return gtest_msg;
+  }
+
+  return gtest_msg + "\n" + user_msg_string;
+}
+
+}  // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+    : death_test_count_(0),
+      elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const {
+  if (i < 0 || i >= total_part_count())
+    internal::posix::Abort();
+  return test_part_results_.at(i);
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const {
+  if (i < 0 || i >= test_property_count())
+    internal::posix::Abort();
+  return test_properties_.at(i);
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults() {
+  test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+  test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const std::string& xml_element,
+                                const TestProperty& test_property) {
+  if (!ValidateTestProperty(xml_element, test_property)) {
+    return;
+  }
+  internal::MutexLock lock(&test_properites_mutex_);
+  const std::vector<TestProperty>::iterator property_with_matching_key =
+      std::find_if(test_properties_.begin(), test_properties_.end(),
+                   internal::TestPropertyKeyIs(test_property.key()));
+  if (property_with_matching_key == test_properties_.end()) {
+    test_properties_.push_back(test_property);
+    return;
+  }
+  property_with_matching_key->SetValue(test_property.value());
+}
+
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+  "disabled",
+  "errors",
+  "failures",
+  "name",
+  "random_seed",
+  "tests",
+  "time",
+  "timestamp"
+};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+  "disabled",
+  "errors",
+  "failures",
+  "name",
+  "tests",
+  "time"
+};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+  "classname",
+  "name",
+  "status",
+  "time",
+  "type_param",
+  "value_param"
+};
+
+template <int kSize>
+std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
+  return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+    const std::string& xml_element) {
+  if (xml_element == "testsuites") {
+    return ArrayAsVector(kReservedTestSuitesAttributes);
+  } else if (xml_element == "testsuite") {
+    return ArrayAsVector(kReservedTestSuiteAttributes);
+  } else if (xml_element == "testcase") {
+    return ArrayAsVector(kReservedTestCaseAttributes);
+  } else {
+    GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+  }
+  // This code is unreachable but some compilers may not realizes that.
+  return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words) {
+  Message word_list;
+  for (size_t i = 0; i < words.size(); ++i) {
+    if (i > 0 && words.size() > 2) {
+      word_list << ", ";
+    }
+    if (i == words.size() - 1) {
+      word_list << "and ";
+    }
+    word_list << "'" << words[i] << "'";
+  }
+  return word_list.GetString();
+}
+
+bool ValidateTestPropertyName(const std::string& property_name,
+                              const std::vector<std::string>& reserved_names) {
+  if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+          reserved_names.end()) {
+    ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+                  << " (" << FormatWordList(reserved_names)
+                  << " are reserved by " << GTEST_NAME_ << ")";
+    return false;
+  }
+  return true;
+}
+
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element.  Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+                                      const TestProperty& test_property) {
+  return ValidateTestPropertyName(test_property.key(),
+                                  GetReservedAttributesForElement(xml_element));
+}
+
+// Clears the object.
+void TestResult::Clear() {
+  test_part_results_.clear();
+  test_properties_.clear();
+  death_test_count_ = 0;
+  elapsed_time_ = 0;
+}
+
+// Returns true iff the test failed.
+bool TestResult::Failed() const {
+  for (int i = 0; i < total_part_count(); ++i) {
+    if (GetTestPartResult(i).failed())
+      return true;
+  }
+  return false;
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+  return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+  return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+  return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+  return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts.  This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+  return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+  return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+    : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+  delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, const std::string& value) {
+  UnitTest::GetInstance()->RecordProperty(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, int value) {
+  Message value_message;
+  value_message << value;
+  RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal {
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+                                    const std::string& message) {
+  // This function is a friend of UnitTest and as such has access to
+  // AddTestPartResult.
+  UnitTest::GetInstance()->AddTestPartResult(
+      result_type,
+      NULL,  // No info about the source file where the exception occurred.
+      -1,    // We have no info on which line caused the exception.
+      message,
+      "");   // No stack trace, either.
+}
+
+}  // namespace internal
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class.  This function checks if the current test has the
+// same fixture class as the first test in the current test case.  If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  const TestCase* const test_case = impl->current_test_case();
+
+  // Info about the first test in the current test case.
+  const TestInfo* const first_test_info = test_case->test_info_list()[0];
+  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
+  const char* const first_test_name = first_test_info->name();
+
+  // Info about the current test.
+  const TestInfo* const this_test_info = impl->current_test_info();
+  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
+  const char* const this_test_name = this_test_info->name();
+
+  if (this_fixture_id != first_fixture_id) {
+    // Is the first test defined using TEST?
+    const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+    // Is this test defined using TEST?
+    const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+    if (first_is_TEST || this_is_TEST) {
+      // The user mixed TEST and TEST_F in this test case - we'll tell
+      // him/her how to fix it.
+
+      // Gets the name of the TEST and the name of the TEST_F.  Note
+      // that first_is_TEST and this_is_TEST cannot both be true, as
+      // the fixture IDs are different for the two tests.
+      const char* const TEST_name =
+          first_is_TEST ? first_test_name : this_test_name;
+      const char* const TEST_F_name =
+          first_is_TEST ? this_test_name : first_test_name;
+
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class, so mixing TEST_F and TEST in the same test case is\n"
+          << "illegal.  In test case " << this_test_info->test_case_name()
+          << ",\n"
+          << "test " << TEST_F_name << " is defined using TEST_F but\n"
+          << "test " << TEST_name << " is defined using TEST.  You probably\n"
+          << "want to change the TEST to TEST_F or move it to another test\n"
+          << "case.";
+    } else {
+      // The user defined two fixture classes with the same name in
+      // two namespaces - we'll tell him/her how to fix it.
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class.  However, in test case "
+          << this_test_info->test_case_name() << ",\n"
+          << "you defined test " << first_test_name
+          << " and test " << this_test_name << "\n"
+          << "using two different test fixture classes.  This can happen if\n"
+          << "the two classes are from different namespaces or translation\n"
+          << "units and have the same name.  You should probably rename one\n"
+          << "of the classes to put the tests into different test cases.";
+    }
+    return false;
+  }
+
+  return true;
+}
+
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test.  This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static std::string* FormatSehExceptionMessage(DWORD exception_code,
+                                              const char* location) {
+  Message message;
+  message << "SEH exception with code 0x" << std::setbase(16) <<
+    exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+  return new std::string(message.GetString());
+}
+
+#endif  // GTEST_HAS_SEH
+
+namespace internal {
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static std::string FormatCxxExceptionMessage(const char* description,
+                                             const char* location) {
+  Message message;
+  if (description != NULL) {
+    message << "C++ exception with description \"" << description << "\"";
+  } else {
+    message << "Unknown C++ exception";
+  }
+  message << " thrown in " << location << ".";
+
+  return message.GetString();
+}
+
+static std::string PrintTestPartResultToString(
+    const TestPartResult& test_part_result);
+
+GoogleTestFailureException::GoogleTestFailureException(
+    const TestPartResult& failure)
+    : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+// We put these helper functions in the internal namespace as IBM's xlC
+// compiler rejects the code if they were declared static.
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception.  (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function.  Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+Result HandleSehExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_SEH
+  __try {
+    return (object->*method)();
+  } __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINT
+      GetExceptionCode())) {
+    // We create the exception message on the heap because VC++ prohibits
+    // creation of objects with destructors on stack in functions using __try
+    // (see error C2712).
+    std::string* exception_message = FormatSehExceptionMessage(
+        GetExceptionCode(), location);
+    internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+                                             *exception_message);
+    delete exception_message;
+    return static_cast<Result>(0);
+  }
+#else
+  (void)location;
+  return (object->*method)();
+#endif  // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+Result HandleExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+  // NOTE: The user code can affect the way in which Google Test handles
+  // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
+  // RUN_ALL_TESTS() starts. It is technically possible to check the flag
+  // after the exception is caught and either report or re-throw the
+  // exception based on the flag's value:
+  //
+  // try {
+  //   // Perform the test method.
+  // } catch (...) {
+  //   if (GTEST_FLAG(catch_exceptions))
+  //     // Report the exception as failure.
+  //   else
+  //     throw;  // Re-throws the original exception.
+  // }
+  //
+  // However, the purpose of this flag is to allow the program to drop into
+  // the debugger when the exception is thrown. On most platforms, once the
+  // control enters the catch block, the exception origin information is
+  // lost and the debugger will stop the program at the point of the
+  // re-throw in this function -- instead of at the point of the original
+  // throw statement in the code under test.  For this reason, we perform
+  // the check early, sacrificing the ability to affect Google Test's
+  // exception handling in the method where the exception is thrown.
+  if (internal::GetUnitTestImpl()->catch_exceptions()) {
+#if GTEST_HAS_EXCEPTIONS
+    try {
+      return HandleSehExceptionsInMethodIfSupported(object, method, location);
+    } catch (const internal::GoogleTestFailureException&) {  // NOLINT
+      // This exception type can only be thrown by a failed Google
+      // Test assertion with the intention of letting another testing
+      // framework catch it.  Therefore we just re-throw it.
+      throw;
+    } catch (const std::exception& e) {  // NOLINT
+      internal::ReportFailureInUnknownLocation(
+          TestPartResult::kFatalFailure,
+          FormatCxxExceptionMessage(e.what(), location));
+    } catch (...) {  // NOLINT
+      internal::ReportFailureInUnknownLocation(
+          TestPartResult::kFatalFailure,
+          FormatCxxExceptionMessage(NULL, location));
+    }
+    return static_cast<Result>(0);
+#else
+    return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif  // GTEST_HAS_EXCEPTIONS
+  } else {
+    return (object->*method)();
+  }
+}
+
+}  // namespace internal
+
+// Runs the test and updates the test result.
+void Test::Run() {
+  if (!HasSameFixtureClass()) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
+  // We will run the test only if SetUp() was successful.
+  if (!HasFatalFailure()) {
+    impl->os_stack_trace_getter()->UponLeavingGTest();
+    internal::HandleExceptionsInMethodIfSupported(
+        this, &Test::TestBody, "the test body");
+  }
+
+  // However, we want to clean up as much as possible.  Hence we will
+  // always call TearDown(), even if SetUp() or the test body has
+  // failed.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &Test::TearDown, "TearDown()");
+}
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->
+      HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+TestInfo::TestInfo(const std::string& a_test_case_name,
+                   const std::string& a_name,
+                   const char* a_type_param,
+                   const char* a_value_param,
+                   internal::TypeId fixture_class_id,
+                   internal::TestFactoryBase* factory)
+    : test_case_name_(a_test_case_name),
+      name_(a_name),
+      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+      value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+      fixture_class_id_(fixture_class_id),
+      should_run_(false),
+      is_disabled_(false),
+      matches_filter_(false),
+      factory_(factory),
+      result_() {}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() { delete factory_; }
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   type_param:       the name of the test's type parameter, or NULL if
+//                     this is not a typed or a type-parameterized test.
+//   value_param:      text representation of the test's value parameter,
+//                     or NULL if this is not a value-parameterized test.
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name,
+    const char* name,
+    const char* type_param,
+    const char* value_param,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory) {
+  TestInfo* const test_info =
+      new TestInfo(test_case_name, name, type_param, value_param,
+                   fixture_class_id, factory);
+  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+  return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+                               const char* file, int line) {
+  Message errors;
+  errors
+      << "Attempted redefinition of test case " << test_case_name << ".\n"
+      << "All tests in the same test case must use the same test fixture\n"
+      << "class.  However, in test case " << test_case_name << ", you tried\n"
+      << "to define a test using a fixture class different from the one\n"
+      << "used earlier. This can happen if the two fixture classes are\n"
+      << "from different namespaces and have the same name. You should\n"
+      << "probably rename one of the classes to put the tests into different\n"
+      << "test cases.";
+
+  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+          errors.GetString().c_str());
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+}  // namespace internal
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+  // Constructor.
+  //
+  // TestNameIs has NO default constructor.
+  explicit TestNameIs(const char* name)
+      : name_(name) {}
+
+  // Returns true iff the test name of test_info matches name_.
+  bool operator()(const TestInfo * test_info) const {
+    return test_info && test_info->name() == name_;
+  }
+
+ private:
+  std::string name_;
+};
+
+}  // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#if GTEST_HAS_PARAM_TEST
+  if (!parameterized_tests_registered_) {
+    parameterized_test_registry_.RegisterTests();
+    parameterized_tests_registered_ = true;
+  }
+#endif
+}
+
+}  // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run() {
+  if (!should_run_) return;
+
+  // Tells UnitTest where to store test result.
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_info(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  // Notifies the unit test event listeners that a test is about to start.
+  repeater->OnTestStart(*this);
+
+  const TimeInMillis start = internal::GetTimeInMillis();
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+
+  // Creates the test object.
+  Test* const test = internal::HandleExceptionsInMethodIfSupported(
+      factory_, &internal::TestFactoryBase::CreateTest,
+      "the test fixture's constructor");
+
+  // Runs the test only if the test object was created and its
+  // constructor didn't generate a fatal failure.
+  if ((test != NULL) && !Test::HasFatalFailure()) {
+    // This doesn't throw as all user code that can throw are wrapped into
+    // exception handling code.
+    test->Run();
+  }
+
+  // Deletes the test object.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      test, &Test::DeleteSelf_, "the test fixture's destructor");
+
+  result_.set_elapsed_time(internal::GetTimeInMillis() - start);
+
+  // Notifies the unit test event listener that a test has just finished.
+  repeater->OnTestEnd(*this);
+
+  // Tells UnitTest to stop associating assertion results to this
+  // test.
+  impl->set_current_test_info(NULL);
+}
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+  return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+  return CountIf(test_info_list_, TestFailed);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestCase::reportable_disabled_test_count() const {
+  return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test case.
+int TestCase::disabled_test_count() const {
+  return CountIf(test_info_list_, TestDisabled);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int TestCase::reportable_test_count() const {
+  return CountIf(test_info_list_, TestReportable);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+  return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+  return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+//   name:         name of the test case
+//   a_type_param: the name of the test case's type parameter, or NULL if
+//                 this is not a typed or a type-parameterized test case.
+//   set_up_tc:    pointer to the function that sets up the test case
+//   tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* a_name, const char* a_type_param,
+                   Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc)
+    : name_(a_name),
+      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+      set_up_tc_(set_up_tc),
+      tear_down_tc_(tear_down_tc),
+      should_run_(false),
+      elapsed_time_(0) {
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+  // Deletes every Test in the collection.
+  ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestCase::GetTestInfo(int i) const {
+  const int index = GetElementOr(test_indices_, i, -1);
+  return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestCase::GetMutableTestInfo(int i) {
+  const int index = GetElementOr(test_indices_, i, -1);
+  return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Adds a test to this test case.  Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+  test_info_list_.push_back(test_info);
+  test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+  if (!should_run_) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_case(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  repeater->OnTestCaseStart(*this);
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
+
+  const internal::TimeInMillis start = internal::GetTimeInMillis();
+  for (int i = 0; i < total_test_count(); i++) {
+    GetMutableTestInfo(i)->Run();
+  }
+  elapsed_time_ = internal::GetTimeInMillis() - start;
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+
+  repeater->OnTestCaseEnd(*this);
+  impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+  ad_hoc_test_result_.Clear();
+  ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test case.
+void TestCase::ShuffleTests(internal::Random* random) {
+  Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestCase::UnshuffleTests() {
+  for (size_t i = 0; i < test_indices_.size(); i++) {
+    test_indices_[i] = static_cast<int>(i);
+  }
+}
+
+// Formats a countable noun.  Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static std::string FormatCountableNoun(int count,
+                                       const char * singular_form,
+                                       const char * plural_form) {
+  return internal::StreamableToString(count) + " " +
+      (count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static std::string FormatTestCount(int test_count) {
+  return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static std::string FormatTestCaseCount(int test_case_count) {
+  return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation.  Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResult::Type type) {
+  switch (type) {
+    case TestPartResult::kSuccess:
+      return "Success";
+
+    case TestPartResult::kNonFatalFailure:
+    case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+      return "error: ";
+#else
+      return "Failure\n";
+#endif
+    default:
+      return "Unknown result type";
+  }
+}
+
+namespace internal {
+
+// Prints a TestPartResult to an std::string.
+static std::string PrintTestPartResultToString(
+    const TestPartResult& test_part_result) {
+  return (Message()
+          << internal::FormatFileLocation(test_part_result.file_name(),
+                                          test_part_result.line_number())
+          << " " << TestPartResultTypeToString(test_part_result.type())
+          << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result) {
+  const std::string& result =
+      PrintTestPartResultToString(test_part_result);
+  printf("%s\n", result.c_str());
+  fflush(stdout);
+  // If the test program runs in Visual Studio or a debugger, the
+  // following statements add the test part result message to the Output
+  // window such that the user can double-click on it to jump to the
+  // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  // We don't call OutputDebugString*() on Windows Mobile, as printing
+  // to stdout is done by OutputDebugString() there already - we don't
+  // want the same message printed twice.
+  ::OutputDebugStringA(result.c_str());
+  ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+
+enum GTestColor {
+  COLOR_DEFAULT,
+  COLOR_RED,
+  COLOR_GREEN,
+  COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:    return FOREGROUND_RED;
+    case COLOR_GREEN:  return FOREGROUND_GREEN;
+    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+    default:           return 0;
+  }
+}
+
+#else
+
+// Returns the ANSI color code for the given color.  COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:     return "1";
+    case COLOR_GREEN:   return "2";
+    case COLOR_YELLOW:  return "3";
+    default:            return NULL;
+  };
+}
+
+#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+  const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+  if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+    // On Windows the TERM variable is usually not set, but the
+    // console there does support colors.
+    return stdout_is_tty;
+#else
+    // On non-Windows platforms, we rely on the TERM variable.
+    const char* const term = posix::GetEnv("TERM");
+    const bool term_supports_color =
+        String::CStringEquals(term, "xterm") ||
+        String::CStringEquals(term, "xterm-color") ||
+        String::CStringEquals(term, "xterm-256color") ||
+        String::CStringEquals(term, "screen") ||
+        String::CStringEquals(term, "screen-256color") ||
+        String::CStringEquals(term, "linux") ||
+        String::CStringEquals(term, "cygwin");
+    return stdout_is_tty && term_supports_color;
+#endif  // GTEST_OS_WINDOWS
+  }
+
+  return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+      String::CStringEquals(gtest_color, "1");
+  // We take "yes", "true", "t", and "1" as meaning "yes".  If the
+  // value is neither one of these nor "auto", we treat it as "no" to
+  // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
+  const bool use_color = false;
+#else
+  static const bool in_color_mode =
+      ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif  // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+  // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+  if (!use_color) {
+    vprintf(fmt, args);
+    va_end(args);
+    return;
+  }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+  // Gets the current text color.
+  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+  const WORD old_color_attrs = buffer_info.wAttributes;
+
+  // We need to flush the stream buffers into the console before each
+  // SetConsoleTextAttribute call lest it affect the text that is already
+  // printed but has not yet reached the console.
+  fflush(stdout);
+  SetConsoleTextAttribute(stdout_handle,
+                          GetColorAttribute(color) | FOREGROUND_INTENSITY);
+  vprintf(fmt, args);
+
+  fflush(stdout);
+  // Restores the text color.
+  SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+  printf("\033[0;3%sm", GetAnsiColorCode(color));
+  vprintf(fmt, args);
+  printf("\033[m");  // Resets the terminal to default.
+#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  va_end(args);
+}
+
+// Text printed in Google Test's text output and --gunit_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
+void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+  const char* const type_param = test_info.type_param();
+  const char* const value_param = test_info.value_param();
+
+  if (type_param != NULL || value_param != NULL) {
+    printf(", where ");
+    if (type_param != NULL) {
+      printf("%s = %s", kTypeParamLabel, type_param);
+      if (value_param != NULL)
+        printf(" and ");
+    }
+    if (value_param != NULL) {
+      printf("%s = %s", kValueParamLabel, value_param);
+    }
+  }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+  PrettyUnitTestResultPrinter() {}
+  static void PrintTestName(const char * test_case, const char * test) {
+    printf("%s.%s", test_case, test);
+  }
+
+  // The following methods override what's in the TestEventListener class.
+  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestCaseStart(const TestCase& test_case);
+  virtual void OnTestStart(const TestInfo& test_info);
+  virtual void OnTestPartResult(const TestPartResult& result);
+  virtual void OnTestEnd(const TestInfo& test_info);
+  virtual void OnTestCaseEnd(const TestCase& test_case);
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+
+ private:
+  static void PrintFailedTests(const UnitTest& unit_test);
+};
+
+  // Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+    const UnitTest& unit_test, int iteration) {
+  if (GTEST_FLAG(repeat) != 1)
+    printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+  const char* const filter = GTEST_FLAG(filter).c_str();
+
+  // Prints the filter if it's not *.  This reminds the user that some
+  // tests may be skipped.
+  if (!String::CStringEquals(filter, kUniversalFilter)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: %s filter = %s\n", GTEST_NAME_, filter);
+  }
+
+  if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+    const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: This is test shard %d of %s.\n",
+                  static_cast<int>(shard_index) + 1,
+                  internal::posix::GetEnv(kTestTotalShards));
+  }
+
+  if (GTEST_FLAG(shuffle)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: Randomizing tests' orders with a seed of %d .\n",
+                  unit_test.random_seed());
+  }
+
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("Running %s from %s.\n",
+         FormatTestCount(unit_test.test_to_run_count()).c_str(),
+         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+    const UnitTest& /*unit_test*/) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment set-up.\n");
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s", counts.c_str(), test_case.name());
+  if (test_case.type_param() == NULL) {
+    printf("\n");
+  } else {
+    printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");
+  PrintTestName(test_info.test_case_name(), test_info.name());
+  printf("\n");
+  fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+    const TestPartResult& result) {
+  // If the test part succeeded, we don't need to do anything.
+  if (result.type() == TestPartResult::kSuccess)
+    return;
+
+  // Print failure message from the assertion (e.g. expected this and got that).
+  PrintTestPartResult(result);
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+  if (test_info.result()->Passed()) {
+    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
+  } else {
+    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+  }
+  PrintTestName(test_info.test_case_name(), test_info.name());
+  if (test_info.result()->Failed())
+    PrintFullTestCommentIfPresent(test_info);
+
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms)\n", internal::StreamableToString(
+           test_info.result()->elapsed_time()).c_str());
+  } else {
+    printf("\n");
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+  if (!GTEST_FLAG(print_time)) return;
+
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s (%s ms total)\n\n",
+         counts.c_str(), test_case.name(),
+         internal::StreamableToString(test_case.elapsed_time()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+    const UnitTest& /*unit_test*/) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment tear-down\n");
+  fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
+  const int failed_test_count = unit_test.failed_test_count();
+  if (failed_test_count == 0) {
+    return;
+  }
+
+  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+    const TestCase& test_case = *unit_test.GetTestCase(i);
+    if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+      continue;
+    }
+    for (int j = 0; j < test_case.total_test_count(); ++j) {
+      const TestInfo& test_info = *test_case.GetTestInfo(j);
+      if (!test_info.should_run() || test_info.result()->Passed()) {
+        continue;
+      }
+      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+      printf("%s.%s", test_case.name(), test_info.name());
+      PrintFullTestCommentIfPresent(test_info);
+      printf("\n");
+    }
+  }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+                                                     int /*iteration*/) {
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("%s from %s ran.",
+         FormatTestCount(unit_test.test_to_run_count()).c_str(),
+         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms total)",
+           internal::StreamableToString(unit_test.elapsed_time()).c_str());
+  }
+  printf("\n");
+  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");
+  printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+  int num_failures = unit_test.failed_test_count();
+  if (!unit_test.Passed()) {
+    const int failed_test_count = unit_test.failed_test_count();
+    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");
+    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+    PrintFailedTests(unit_test);
+    printf("\n%2d FAILED %s\n", num_failures,
+                        num_failures == 1 ? "TEST" : "TESTS");
+  }
+
+  int num_disabled = unit_test.reportable_disabled_test_count();
+  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+    if (!num_failures) {
+      printf("\n");  // Add a spacer if no FAILURE banner is displayed.
+    }
+    ColoredPrintf(COLOR_YELLOW,
+                  "  YOU HAVE %d DISABLED %s\n\n",
+                  num_disabled,
+                  num_disabled == 1 ? "TEST" : "TESTS");
+  }
+  // Ensure that Google Test output is printed before, e.g., heapchecker output.
+  fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+  TestEventRepeater() : forwarding_enabled_(true) {}
+  virtual ~TestEventRepeater();
+  void Append(TestEventListener *listener);
+  TestEventListener* Release(TestEventListener* listener);
+
+  // Controls whether events will be forwarded to listeners_. Set to false
+  // in death test child processes.
+  bool forwarding_enabled() const { return forwarding_enabled_; }
+  void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+  virtual void OnTestProgramStart(const UnitTest& unit_test);
+  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
+  virtual void OnTestCaseStart(const TestCase& test_case);
+  virtual void OnTestStart(const TestInfo& test_info);
+  virtual void OnTestPartResult(const TestPartResult& result);
+  virtual void OnTestEnd(const TestInfo& test_info);
+  virtual void OnTestCaseEnd(const TestCase& test_case);
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+  virtual void OnTestProgramEnd(const UnitTest& unit_test);
+
+ private:
+  // Controls whether events will be forwarded to listeners_. Set to false
+  // in death test child processes.
+  bool forwarding_enabled_;
+  // The list of listeners that receive events.
+  std::vector<TestEventListener*> listeners_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater() {
+  ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener *listener) {
+  listeners_.push_back(listener);
+}
+
+// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
+TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
+  for (size_t i = 0; i < listeners_.size(); ++i) {
+    if (listeners_[i] == listener) {
+      listeners_.erase(listeners_.begin() + i);
+      return listener;
+    }
+  }
+
+  return NULL;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+  if (forwarding_enabled_) { \
+    for (size_t i = 0; i < listeners_.size(); i++) { \
+      listeners_[i]->Name(parameter); \
+    } \
+  } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+  if (forwarding_enabled_) { \
+    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
+      listeners_[i]->Name(parameter); \
+    } \
+  } \
+}
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+                                             int iteration) {
+  if (forwarding_enabled_) {
+    for (size_t i = 0; i < listeners_.size(); i++) {
+      listeners_[i]->OnTestIterationStart(unit_test, iteration);
+    }
+  }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+                                           int iteration) {
+  if (forwarding_enabled_) {
+    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
+      listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+    }
+  }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+  explicit XmlUnitTestResultPrinter(const char* output_file);
+
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+
+ private:
+  // Is c a whitespace character that is normalized to a space character
+  // when it appears in an XML attribute value?
+  static bool IsNormalizableWhitespace(char c) {
+    return c == 0x9 || c == 0xA || c == 0xD;
+  }
+
+  // May c appear in a well-formed XML document?
+  static bool IsValidXmlCharacter(char c) {
+    return IsNormalizableWhitespace(c) || c >= 0x20;
+  }
+
+  // Returns an XML-escaped copy of the input string str.  If
+  // is_attribute is true, the text is meant to appear as an attribute
+  // value, and normalizable whitespace is preserved by replacing it
+  // with character references.
+  static std::string EscapeXml(const std::string& str, bool is_attribute);
+
+  // Returns the given string with all characters invalid in XML removed.
+  static std::string RemoveInvalidXmlCharacters(const std::string& str);
+
+  // Convenience wrapper around EscapeXml when str is an attribute value.
+  static std::string EscapeXmlAttribute(const std::string& str) {
+    return EscapeXml(str, true);
+  }
+
+  // Convenience wrapper around EscapeXml when str is not an attribute value.
+  static std::string EscapeXmlText(const char* str) {
+    return EscapeXml(str, false);
+  }
+
+  // Verifies that the given attribute belongs to the given element and
+  // streams the attribute as XML.
+  static void OutputXmlAttribute(std::ostream* stream,
+                                 const std::string& element_name,
+                                 const std::string& name,
+                                 const std::string& value);
+
+  // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+  static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+  // Streams an XML representation of a TestInfo object.
+  static void OutputXmlTestInfo(::std::ostream* stream,
+                                const char* test_case_name,
+                                const TestInfo& test_info);
+
+  // Prints an XML representation of a TestCase object
+  static void PrintXmlTestCase(::std::ostream* stream,
+                               const TestCase& test_case);
+
+  // Prints an XML summary of unit_test to output stream out.
+  static void PrintXmlUnitTest(::std::ostream* stream,
+                               const UnitTest& unit_test);
+
+  // Produces a string representing the test properties in a result as space
+  // delimited XML attributes based on the property key="value" pairs.
+  // When the std::string is not empty, it includes a space at the beginning,
+  // to delimit this attribute from prior attributes.
+  static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+
+  // The output file.
+  const std::string output_file_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+    : output_file_(output_file) {
+  if (output_file_.c_str() == NULL || output_file_.empty()) {
+    fprintf(stderr, "XML output file may not be null\n");
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+                                                  int /*iteration*/) {
+  FILE* xmlout = NULL;
+  FilePath output_file(output_file_);
+  FilePath output_dir(output_file.RemoveFileName());
+
+  if (output_dir.CreateDirectoriesRecursively()) {
+    xmlout = posix::FOpen(output_file_.c_str(), "w");
+  }
+  if (xmlout == NULL) {
+    // TODO(wan): report the reason of the failure.
+    //
+    // We don't do it for now as:
+    //
+    //   1. There is no urgent need for it.
+    //   2. It's a bit involved to make the errno variable thread-safe on
+    //      all three operating systems (Linux, Windows, and Mac OS).
+    //   3. To interpret the meaning of errno in a thread-safe way,
+    //      we need the strerror_r() function, which is not available on
+    //      Windows.
+    fprintf(stderr,
+            "Unable to open file \"%s\"\n",
+            output_file_.c_str());
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+  std::stringstream stream;
+  PrintXmlUnitTest(&stream, unit_test);
+  fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+  fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str.  If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+std::string XmlUnitTestResultPrinter::EscapeXml(
+    const std::string& str, bool is_attribute) {
+  Message m;
+
+  for (size_t i = 0; i < str.size(); ++i) {
+    const char ch = str[i];
+    switch (ch) {
+      case '<':
+        m << "&lt;";
+        break;
+      case '>':
+        m << "&gt;";
+        break;
+      case '&':
+        m << "&amp;";
+        break;
+      case '\'':
+        if (is_attribute)
+          m << "&apos;";
+        else
+          m << '\'';
+        break;
+      case '"':
+        if (is_attribute)
+          m << "&quot;";
+        else
+          m << '"';
+        break;
+      default:
+        if (IsValidXmlCharacter(ch)) {
+          if (is_attribute && IsNormalizableWhitespace(ch))
+            m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+              << ";";
+          else
+            m << ch;
+        }
+        break;
+    }
+  }
+
+  return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+    const std::string& str) {
+  std::string output;
+  output.reserve(str.size());
+  for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
+    if (IsValidXmlCharacter(*it))
+      output.push_back(*it);
+
+  return output;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests">        <-- corresponds to a UnitTest object
+//   <testsuite name="testcase-name">  <-- corresponds to a TestCase object
+//     <testcase name="test-name">     <-- corresponds to a TestInfo object
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//                                     <-- individual assertion failures
+//     </testcase>
+//   </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+  ::std::stringstream ss;
+  ss << ms/1000.0;
+  return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+  // Using non-reentrant version as localtime_r is not portable.
+  time_t seconds = static_cast<time_t>(ms / 1000);
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4996)  // Temporarily disables warning 4996
+                                // (function or variable may be unsafe).
+  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
+# pragma warning(pop)           // Restores the warning state again.
+#else
+  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
+#endif
+  if (time_struct == NULL)
+    return "";  // Invalid ms value
+
+  // YYYY-MM-DDThh:mm:ss
+  return StreamableToString(time_struct->tm_year + 1900) + "-" +
+      String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
+      String::FormatIntWidth2(time_struct->tm_mday) + "T" +
+      String::FormatIntWidth2(time_struct->tm_hour) + ":" +
+      String::FormatIntWidth2(time_struct->tm_min) + ":" +
+      String::FormatIntWidth2(time_struct->tm_sec);
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+                                                     const char* data) {
+  const char* segment = data;
+  *stream << "<![CDATA[";
+  for (;;) {
+    const char* const next_segment = strstr(segment, "]]>");
+    if (next_segment != NULL) {
+      stream->write(
+          segment, static_cast<std::streamsize>(next_segment - segment));
+      *stream << "]]>]]&gt;<![CDATA[";
+      segment = next_segment + strlen("]]>");
+    } else {
+      *stream << segment;
+      break;
+    }
+  }
+  *stream << "]]>";
+}
+
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+    std::ostream* stream,
+    const std::string& element_name,
+    const std::string& name,
+    const std::string& value) {
+  const std::vector<std::string>& allowed_names =
+      GetReservedAttributesForElement(element_name);
+
+  GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+                   allowed_names.end())
+      << "Attribute " << name << " is not allowed for element <" << element_name
+      << ">.";
+
+  *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+                                                 const char* test_case_name,
+                                                 const TestInfo& test_info) {
+  const TestResult& result = *test_info.result();
+  const std::string kTestcase = "testcase";
+
+  *stream << "    <testcase";
+  OutputXmlAttribute(stream, kTestcase, "name", test_info.name());
+
+  if (test_info.value_param() != NULL) {
+    OutputXmlAttribute(stream, kTestcase, "value_param",
+                       test_info.value_param());
+  }
+  if (test_info.type_param() != NULL) {
+    OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
+  }
+
+  OutputXmlAttribute(stream, kTestcase, "status",
+                     test_info.should_run() ? "run" : "notrun");
+  OutputXmlAttribute(stream, kTestcase, "time",
+                     FormatTimeInMillisAsSeconds(result.elapsed_time()));
+  OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
+  *stream << TestPropertiesAsXmlAttributes(result);
+
+  int failures = 0;
+  for (int i = 0; i < result.total_part_count(); ++i) {
+    const TestPartResult& part = result.GetTestPartResult(i);
+    if (part.failed()) {
+      if (++failures == 1) {
+        *stream << ">\n";
+      }
+      const string location = internal::FormatCompilerIndependentFileLocation(
+          part.file_name(), part.line_number());
+      const string summary = location + "\n" + part.summary();
+      *stream << "      <failure message=\""
+              << EscapeXmlAttribute(summary.c_str())
+              << "\" type=\"\">";
+      const string detail = location + "\n" + part.message();
+      OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+      *stream << "</failure>\n";
+    }
+  }
+
+  if (failures == 0)
+    *stream << " />\n";
+  else
+    *stream << "    </testcase>\n";
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
+                                                const TestCase& test_case) {
+  const std::string kTestsuite = "testsuite";
+  *stream << "  <" << kTestsuite;
+  OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
+  OutputXmlAttribute(stream, kTestsuite, "tests",
+                     StreamableToString(test_case.reportable_test_count()));
+  OutputXmlAttribute(stream, kTestsuite, "failures",
+                     StreamableToString(test_case.failed_test_count()));
+  OutputXmlAttribute(
+      stream, kTestsuite, "disabled",
+      StreamableToString(test_case.reportable_disabled_test_count()));
+  OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+  OutputXmlAttribute(stream, kTestsuite, "time",
+                     FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
+  *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
+          << ">\n";
+
+  for (int i = 0; i < test_case.total_test_count(); ++i) {
+    if (test_case.GetTestInfo(i)->is_reportable())
+      OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
+  }
+  *stream << "  </" << kTestsuite << ">\n";
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
+                                                const UnitTest& unit_test) {
+  const std::string kTestsuites = "testsuites";
+
+  *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+  *stream << "<" << kTestsuites;
+
+  OutputXmlAttribute(stream, kTestsuites, "tests",
+                     StreamableToString(unit_test.reportable_test_count()));
+  OutputXmlAttribute(stream, kTestsuites, "failures",
+                     StreamableToString(unit_test.failed_test_count()));
+  OutputXmlAttribute(
+      stream, kTestsuites, "disabled",
+      StreamableToString(unit_test.reportable_disabled_test_count()));
+  OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+  OutputXmlAttribute(
+      stream, kTestsuites, "timestamp",
+      FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+  OutputXmlAttribute(stream, kTestsuites, "time",
+                     FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+
+  if (GTEST_FLAG(shuffle)) {
+    OutputXmlAttribute(stream, kTestsuites, "random_seed",
+                       StreamableToString(unit_test.random_seed()));
+  }
+
+  *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+  OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+  *stream << ">\n";
+
+  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+    if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
+      PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
+  }
+  *stream << "</" << kTestsuites << ">\n";
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+    const TestResult& result) {
+  Message attributes;
+  for (int i = 0; i < result.test_property_count(); ++i) {
+    const TestProperty& property = result.GetTestProperty(i);
+    attributes << " " << property.key() << "="
+        << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+  }
+  return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
+// replaces them by "%xx" where xx is their hexadecimal value. For
+// example, replaces "=" with "%3D".  This algorithm is O(strlen(str))
+// in both time and space -- important as the input str may contain an
+// arbitrarily long test failure message and stack trace.
+string StreamingListener::UrlEncode(const char* str) {
+  string result;
+  result.reserve(strlen(str) + 1);
+  for (char ch = *str; ch != '\0'; ch = *++str) {
+    switch (ch) {
+      case '%':
+      case '=':
+      case '&':
+      case '\n':
+        result.append("%" + String::FormatByte(static_cast<unsigned char>(ch)));
+        break;
+      default:
+        result.push_back(ch);
+        break;
+    }
+  }
+  return result;
+}
+
+void StreamingListener::SocketWriter::MakeConnection() {
+  GTEST_CHECK_(sockfd_ == -1)
+      << "MakeConnection() can't be called when there is already a connection.";
+
+  addrinfo hints;
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;    // To allow both IPv4 and IPv6 addresses.
+  hints.ai_socktype = SOCK_STREAM;
+  addrinfo* servinfo = NULL;
+
+  // Use the getaddrinfo() to get a linked list of IP addresses for
+  // the given host name.
+  const int error_num = getaddrinfo(
+      host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
+  if (error_num != 0) {
+    GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
+                        << gai_strerror(error_num);
+  }
+
+  // Loop through all the results and connect to the first we can.
+  for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
+       cur_addr = cur_addr->ai_next) {
+    sockfd_ = socket(
+        cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
+    if (sockfd_ != -1) {
+      // Connect the client socket to the server socket.
+      if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
+        close(sockfd_);
+        sockfd_ = -1;
+      }
+    }
+  }
+
+  freeaddrinfo(servinfo);  // all done with this structure
+
+  if (sockfd_ == -1) {
+    GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
+                        << host_name_ << ":" << port_num_;
+  }
+}
+
+// End of class Streaming Listener
+#endif  // GTEST_CAN_STREAM_RESULTS__
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
+    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+  TraceInfo trace;
+  trace.file = file;
+  trace.line = line;
+  trace.message = message.GetString();
+
+  UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace()
+    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+  UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as an std::string.  Parameters:
+//
+//   max_depth  - the maximum number of stack frames to be included
+//                in the trace.
+//   skip_count - the number of top frames to be skipped; doesn't count
+//                against max_depth.
+//
+string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
+                                             int /* skip_count */)
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  return "";
+}
+
+void OsStackTraceGetter::UponLeavingGTest()
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+    "... " GTEST_NAME_ " internal frames ...";
+
+// A helper class that creates the premature-exit file in its
+// constructor and deletes the file in its destructor.
+class ScopedPrematureExitFile {
+ public:
+  explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
+      : premature_exit_filepath_(premature_exit_filepath) {
+    // If a path to the premature-exit file is specified...
+    if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') {
+      // create the file with a single "0" character in it.  I/O
+      // errors are ignored as there's nothing better we can do and we
+      // don't want to fail the test because of this.
+      FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
+      fwrite("0", 1, 1, pfile);
+      fclose(pfile);
+    }
+  }
+
+  ~ScopedPrematureExitFile() {
+    if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') {
+      remove(premature_exit_filepath_);
+    }
+  }
+
+ private:
+  const char* const premature_exit_filepath_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
+};
+
+}  // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+    : repeater_(new internal::TestEventRepeater()),
+      default_result_printer_(NULL),
+      default_xml_generator_(NULL) {
+}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output.  Can be removed from the listeners list to shut down default
+// console output.  Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener) {
+  repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it.  It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
+  if (listener == default_result_printer_)
+    default_result_printer_ = NULL;
+  else if (listener == default_xml_generator_)
+    default_xml_generator_ = NULL;
+  return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
+  if (default_result_printer_ != listener) {
+    // It is an error to pass this method a listener that is already in the
+    // list.
+    delete Release(default_result_printer_);
+    default_result_printer_ = listener;
+    if (listener != NULL)
+      Append(listener);
+  }
+}
+
+// Sets the default_xml_generator attribute to the provided listener.  The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
+  if (default_xml_generator_ != listener) {
+    // It is an error to pass this method a listener that is already in the
+    // list.
+    delete Release(default_xml_generator_);
+    default_xml_generator_ = listener;
+    if (listener != NULL)
+      Append(listener);
+  }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const {
+  return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding() {
+  repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object.  The first time this method is
+// called, a UnitTest object is constructed and returned.  Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest* UnitTest::GetInstance() {
+  // When compiled with MSVC 7.1 in optimized mode, destroying the
+  // UnitTest object upon exiting the program messes up the exit code,
+  // causing successful tests to appear failed.  We have to use a
+  // different implementation in this case to bypass the compiler bug.
+  // This implementation makes the compiler happy, at the cost of
+  // leaking the UnitTest object.
+
+  // CodeGear C++Builder insists on a public destructor for the
+  // default implementation.  Use this implementation to keep good OO
+  // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+  static UnitTest* const instance = new UnitTest;
+  return instance;
+#else
+  static UnitTest instance;
+  return &instance;
+#endif  // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Gets the number of successful test cases.
+int UnitTest::successful_test_case_count() const {
+  return impl()->successful_test_case_count();
+}
+
+// Gets the number of failed test cases.
+int UnitTest::failed_test_case_count() const {
+  return impl()->failed_test_case_count();
+}
+
+// Gets the number of all test cases.
+int UnitTest::total_test_case_count() const {
+  return impl()->total_test_case_count();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTest::test_case_to_run_count() const {
+  return impl()->test_case_to_run_count();
+}
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+  return impl()->successful_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const {
+  return impl()->reportable_disabled_test_count();
+}
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+  return impl()->disabled_test_count();
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const {
+  return impl()->reportable_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the time of the test program start, in ms from the start of the
+// UNIX epoch.
+internal::TimeInMillis UnitTest::start_timestamp() const {
+    return impl()->start_timestamp();
+}
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+  return impl()->elapsed_time();
+}
+
+// Returns true iff the unit test passed (i.e. all test cases passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true iff the unit test failed (i.e. some test case failed
+// or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+const TestCase* UnitTest::GetTestCase(int i) const {
+  return impl()->GetTestCase(i);
+}
+
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test cases.
+const TestResult& UnitTest::ad_hoc_test_result() const {
+  return *impl()->ad_hoc_test_result();
+}
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+TestCase* UnitTest::GetMutableTestCase(int i) {
+  return impl()->GetMutableTestCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners() {
+  return *impl()->listeners();
+}
+
+// Registers and returns a global test environment.  When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered.  After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+  if (env == NULL) {
+    return NULL;
+  }
+
+  impl_->environments().push_back(env);
+  return env;
+}
+
+// Adds a TestPartResult to the current TestResult object.  All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results.  The user code should use the
+// assertion macros instead of calling this directly.
+void UnitTest::AddTestPartResult(
+    TestPartResult::Type result_type,
+    const char* file_name,
+    int line_number,
+    const std::string& message,
+    const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) {
+  Message msg;
+  msg << message;
+
+  internal::MutexLock lock(&mutex_);
+  if (impl_->gtest_trace_stack().size() > 0) {
+    msg << "\n" << GTEST_NAME_ << " trace:";
+
+    for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
+         i > 0; --i) {
+      const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+      msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+          << " " << trace.message;
+    }
+  }
+
+  if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+    msg << internal::kStackTraceMarker << os_stack_trace;
+  }
+
+  const TestPartResult result =
+    TestPartResult(result_type, file_name, line_number,
+                   msg.GetString().c_str());
+  impl_->GetTestPartResultReporterForCurrentThread()->
+      ReportTestPartResult(result);
+
+  if (result_type != TestPartResult::kSuccess) {
+    // gtest_break_on_failure takes precedence over
+    // gtest_throw_on_failure.  This allows a user to set the latter
+    // in the code (perhaps in order to use Google Test assertions
+    // with another testing framework) and specify the former on the
+    // command line for debugging.
+    if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+      // Using DebugBreak on Windows allows gtest to still break into a debugger
+      // when a failure happens and both the --gtest_break_on_failure and
+      // the --gtest_catch_exceptions flags are specified.
+      DebugBreak();
+#else
+      // Dereference NULL through a volatile pointer to prevent the compiler
+      // from removing. We use this rather than abort() or __builtin_trap() for
+      // portability: Symbian doesn't implement abort() well, and some debuggers
+      // don't correctly trap abort().
+      *static_cast<volatile int*>(NULL) = 1;
+#endif  // GTEST_OS_WINDOWS
+    } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+      throw internal::GoogleTestFailureException(result);
+#else
+      // We cannot call abort() as it generates a pop-up in debug mode
+      // that cannot be suppressed in VC 7.1 or below.
+      exit(1);
+#endif
+    }
+  }
+}
+
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+// from SetUpTestCase or TearDownTestCase, or to the global property set
+// when invoked elsewhere.  If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+                              const std::string& value) {
+  impl_->RecordProperty(TestProperty(key, value));
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+  const bool in_death_test_child_process =
+      internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+  // Google Test implements this protocol for catching that a test
+  // program exits before returning control to Google Test:
+  //
+  //   1. Upon start, Google Test creates a file whose absolute path
+  //      is specified by the environment variable
+  //      TEST_PREMATURE_EXIT_FILE.
+  //   2. When Google Test has finished its work, it deletes the file.
+  //
+  // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
+  // running a Google-Test-based test program and check the existence
+  // of the file at the end of the test execution to see if it has
+  // exited prematurely.
+
+  // If we are in the child process of a death test, don't
+  // create/delete the premature exit file, as doing so is unnecessary
+  // and will confuse the parent process.  Otherwise, create/delete
+  // the file upon entering/leaving this function.  If the program
+  // somehow exits before this function has a chance to return, the
+  // premature-exit file will be left undeleted, causing a test runner
+  // that understands the premature-exit-file protocol to report the
+  // test as having failed.
+  const internal::ScopedPrematureExitFile premature_exit_file(
+      in_death_test_child_process ?
+      NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+
+  // Captures the value of GTEST_FLAG(catch_exceptions).  This value will be
+  // used for the duration of the program.
+  impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
+
+#if GTEST_HAS_SEH
+  // Either the user wants Google Test to catch exceptions thrown by the
+  // tests or this is executing in the context of death test child
+  // process. In either case the user does not want to see pop-up dialogs
+  // about crashes - they are expected.
+  if (impl()->catch_exceptions() || in_death_test_child_process) {
+# if !GTEST_OS_WINDOWS_MOBILE
+    // SetErrorMode doesn't exist on CE.
+    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+# endif  // !GTEST_OS_WINDOWS_MOBILE
+
+# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+    // Death test children can be terminated with _abort().  On Windows,
+    // _abort() can show a dialog with a warning message.  This forces the
+    // abort message to go to stderr instead.
+    _set_error_mode(_OUT_TO_STDERR);
+# endif
+
+# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+    // In the debug version, Visual Studio pops up a separate dialog
+    // offering a choice to debug the aborted program. We need to suppress
+    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+    // executed. Google Test will notify the user of any unexpected
+    // failure via stderr.
+    //
+    // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+    // Users of prior VC versions shall suffer the agony and pain of
+    // clicking through the countless debug dialogs.
+    // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
+    // debug mode when compiled with VC 7.1 or lower.
+    if (!GTEST_FLAG(break_on_failure))
+      _set_abort_behavior(
+          0x0,                                    // Clear the following flags:
+          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
+# endif
+  }
+#endif  // GTEST_HAS_SEH
+
+  return internal::HandleExceptionsInMethodIfSupported(
+      impl(),
+      &internal::UnitTestImpl::RunAllTests,
+      "auxiliary test code (environments or event listeners)") ? 0 : 1;
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+  return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+const TestCase* UnitTest::current_test_case() const
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+const TestInfo* UnitTest::current_test_info() const
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+internal::ParameterizedTestCaseRegistry&
+    UnitTest::parameterized_test_registry()
+        GTEST_LOCK_EXCLUDED_(mutex_) {
+  return impl_->parameterized_test_registry();
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+  impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+  delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+void UnitTest::PopGTestTrace()
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+    : parent_(parent),
+#ifdef _MSC_VER
+# pragma warning(push)                    // Saves the current warning state.
+# pragma warning(disable:4355)            // Temporarily disables warning 4355
+                                         // (using this in initializer).
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+# pragma warning(pop)                     // Restores the warning state again.
+#else
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+#endif  // _MSC_VER
+      global_test_part_result_repoter_(
+          &default_global_test_part_result_reporter_),
+      per_thread_test_part_result_reporter_(
+          &default_per_thread_test_part_result_reporter_),
+#if GTEST_HAS_PARAM_TEST
+      parameterized_test_registry_(),
+      parameterized_tests_registered_(false),
+#endif  // GTEST_HAS_PARAM_TEST
+      last_death_test_case_(-1),
+      current_test_case_(NULL),
+      current_test_info_(NULL),
+      ad_hoc_test_result_(),
+      os_stack_trace_getter_(NULL),
+      post_flag_parse_init_performed_(false),
+      random_seed_(0),  // Will be overridden by the flag before first use.
+      random_(0),  // Will be reseeded before first use.
+      start_timestamp_(0),
+      elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+      death_test_factory_(new DefaultDeathTestFactory),
+#endif
+      // Will be overridden by the flag before first use.
+      catch_exceptions_(false) {
+  listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl() {
+  // Deletes every TestCase.
+  ForEach(test_cases_, internal::Delete<TestCase>);
+
+  // Deletes every Environment.
+  ForEach(environments_, internal::Delete<Environment>);
+
+  delete os_stack_trace_getter_;
+}
+
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test case's ad_hoc_test_result when invoke
+// from SetUpTestCase/TearDownTestCase, or to the global property set
+// otherwise.  If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
+  std::string xml_element;
+  TestResult* test_result;  // TestResult appropriate for property recording.
+
+  if (current_test_info_ != NULL) {
+    xml_element = "testcase";
+    test_result = &(current_test_info_->result_);
+  } else if (current_test_case_ != NULL) {
+    xml_element = "testsuite";
+    test_result = &(current_test_case_->ad_hoc_test_result_);
+  } else {
+    xml_element = "testsuites";
+    test_result = &ad_hoc_test_result_;
+  }
+  test_result->RecordProperty(xml_element, test_property);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
+  if (internal_run_death_test_flag_.get() != NULL)
+    listeners()->SuppressEventForwarding();
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput() {
+  const std::string& output_format = UnitTestOptions::GetOutputFormat();
+  if (output_format == "xml") {
+    listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+        UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+  } else if (output_format != "") {
+    printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+           output_format.c_str());
+    fflush(stdout);
+  }
+}
+
+#if GTEST_CAN_STREAM_RESULTS_
+// Initializes event listeners for streaming test results in string form.
+// Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureStreamingOutput() {
+  const std::string& target = GTEST_FLAG(stream_result_to);
+  if (!target.empty()) {
+    const size_t pos = target.find(':');
+    if (pos != std::string::npos) {
+      listeners()->Append(new StreamingListener(target.substr(0, pos),
+                                                target.substr(pos+1)));
+    } else {
+      printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
+             target.c_str());
+      fflush(stdout);
+    }
+  }
+}
+#endif  // GTEST_CAN_STREAM_RESULTS_
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests.  Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit() {
+  // Ensures that this function does not execute more than once.
+  if (!post_flag_parse_init_performed_) {
+    post_flag_parse_init_performed_ = true;
+
+#if GTEST_HAS_DEATH_TEST
+    InitDeathTestSubprocessControlInfo();
+    SuppressTestEventsIfInSubprocess();
+#endif  // GTEST_HAS_DEATH_TEST
+
+    // Registers parameterized tests. This makes parameterized tests
+    // available to the UnitTest reflection API without running
+    // RUN_ALL_TESTS.
+    RegisterParameterizedTests();
+
+    // Configures listeners for XML output. This makes it possible for users
+    // to shut down the default XML output before invoking RUN_ALL_TESTS.
+    ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+    // Configures listeners for streaming test results to the specified server.
+    ConfigureStreamingOutput();
+#endif  // GTEST_CAN_STREAM_RESULTS_
+  }
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+  // Constructor.
+  explicit TestCaseNameIs(const std::string& name)
+      : name_(name) {}
+
+  // Returns true iff the name of test_case matches name_.
+  bool operator()(const TestCase* test_case) const {
+    return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+  }
+
+ private:
+  std::string name_;
+};
+
+// Finds and returns a TestCase with the given name.  If one doesn't
+// exist, creates one and returns it.  It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+//   test_case_name: name of the test case
+//   type_param:     the name of the test case's type parameter, or NULL if
+//                   this is not a typed or a type-parameterized test case.
+//   set_up_tc:      pointer to the function that sets up the test case
+//   tear_down_tc:   pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+                                    const char* type_param,
+                                    Test::SetUpTestCaseFunc set_up_tc,
+                                    Test::TearDownTestCaseFunc tear_down_tc) {
+  // Can we find a TestCase with the given name?
+  const std::vector<TestCase*>::const_iterator test_case =
+      std::find_if(test_cases_.begin(), test_cases_.end(),
+                   TestCaseNameIs(test_case_name));
+
+  if (test_case != test_cases_.end())
+    return *test_case;
+
+  // No.  Let's create one.
+  TestCase* const new_test_case =
+      new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
+
+  // Is this a death test case?
+  if (internal::UnitTestOptions::MatchesFilter(test_case_name,
+                                               kDeathTestCaseFilter)) {
+    // Yes.  Inserts the test case after the last death test case
+    // defined so far.  This only works when the test cases haven't
+    // been shuffled.  Otherwise we may end up running a death test
+    // after a non-death test.
+    ++last_death_test_case_;
+    test_cases_.insert(test_cases_.begin() + last_death_test_case_,
+                       new_test_case);
+  } else {
+    // No.  Appends to the end of the list.
+    test_cases_.push_back(new_test_case);
+  }
+
+  test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
+  return new_test_case;
+}
+
+// Helpers for setting up / tearing down the given environment.  They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns true if all tests are successful.  If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+bool UnitTestImpl::RunAllTests() {
+  // Makes sure InitGoogleTest() was called.
+  if (!GTestIsInitialized()) {
+    printf("%s",
+           "\nThis test program did NOT call ::testing::InitGoogleTest "
+           "before calling RUN_ALL_TESTS().  Please fix it.\n");
+    return false;
+  }
+
+  // Do not run any test if the --help flag was specified.
+  if (g_help_flag)
+    return true;
+
+  // Repeats the call to the post-flag parsing initialization in case the
+  // user didn't call InitGoogleTest.
+  PostFlagParsingInit();
+
+  // Even if sharding is not on, test runners may want to use the
+  // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+  // protocol.
+  internal::WriteToShardStatusFileIfNeeded();
+
+  // True iff we are in a subprocess for running a thread-safe-style
+  // death test.
+  bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+  in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif  // GTEST_HAS_DEATH_TEST
+
+  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+                                        in_subprocess_for_death_test);
+
+  // Compares the full test names with the filter to decide which
+  // tests to run.
+  const bool has_tests_to_run = FilterTests(should_shard
+                                              ? HONOR_SHARDING_PROTOCOL
+                                              : IGNORE_SHARDING_PROTOCOL) > 0;
+
+  // Lists the tests and exits if the --gtest_list_tests flag was specified.
+  if (GTEST_FLAG(list_tests)) {
+    // This must be called *after* FilterTests() has been called.
+    ListTestsMatchingFilter();
+    return true;
+  }
+
+  random_seed_ = GTEST_FLAG(shuffle) ?
+      GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+  // True iff at least one test has failed.
+  bool failed = false;
+
+  TestEventListener* repeater = listeners()->repeater();
+
+  start_timestamp_ = GetTimeInMillis();
+  repeater->OnTestProgramStart(*parent_);
+
+  // How many times to repeat the tests?  We don't want to repeat them
+  // when we are inside the subprocess of a death test.
+  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+  // Repeats forever if the repeat count is negative.
+  const bool forever = repeat < 0;
+  for (int i = 0; forever || i != repeat; i++) {
+    // We want to preserve failures generated by ad-hoc test
+    // assertions executed before RUN_ALL_TESTS().
+    ClearNonAdHocTestResult();
+
+    const TimeInMillis start = GetTimeInMillis();
+
+    // Shuffles test cases and tests if requested.
+    if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+      random()->Reseed(random_seed_);
+      // This should be done before calling OnTestIterationStart(),
+      // such that a test event listener can see the actual test order
+      // in the event.
+      ShuffleTests();
+    }
+
+    // Tells the unit test event listeners that the tests are about to start.
+    repeater->OnTestIterationStart(*parent_, i);
+
+    // Runs each test case if there is at least one test to run.
+    if (has_tests_to_run) {
+      // Sets up all environments beforehand.
+      repeater->OnEnvironmentsSetUpStart(*parent_);
+      ForEach(environments_, SetUpEnvironment);
+      repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+      // Runs the tests only if there was no fatal failure during global
+      // set-up.
+      if (!Test::HasFatalFailure()) {
+        for (int test_index = 0; test_index < total_test_case_count();
+             test_index++) {
+          GetMutableTestCase(test_index)->Run();
+        }
+      }
+
+      // Tears down all environments in reverse order afterwards.
+      repeater->OnEnvironmentsTearDownStart(*parent_);
+      std::for_each(environments_.rbegin(), environments_.rend(),
+                    TearDownEnvironment);
+      repeater->OnEnvironmentsTearDownEnd(*parent_);
+    }
+
+    elapsed_time_ = GetTimeInMillis() - start;
+
+    // Tells the unit test event listener that the tests have just finished.
+    repeater->OnTestIterationEnd(*parent_, i);
+
+    // Gets the result and clears it.
+    if (!Passed()) {
+      failed = true;
+    }
+
+    // Restores the original test order after the iteration.  This
+    // allows the user to quickly repro a failure that happens in the
+    // N-th iteration without repeating the first (N - 1) iterations.
+    // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+    // case the user somehow changes the value of the flag somewhere
+    // (it's always safe to unshuffle the tests).
+    UnshuffleTests();
+
+    if (GTEST_FLAG(shuffle)) {
+      // Picks a new random seed for each iteration.
+      random_seed_ = GetNextRandomSeed(random_seed_);
+    }
+  }
+
+  repeater->OnTestProgramEnd(*parent_);
+
+  return !failed;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+  const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+  if (test_shard_file != NULL) {
+    FILE* const file = posix::FOpen(test_shard_file, "w");
+    if (file == NULL) {
+      ColoredPrintf(COLOR_RED,
+                    "Could not write to the test shard status file \"%s\" "
+                    "specified by the %s environment variable.\n",
+                    test_shard_file, kTestShardStatusFile);
+      fflush(stdout);
+      exit(EXIT_FAILURE);
+    }
+    fclose(file);
+  }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+                 const char* shard_index_env,
+                 bool in_subprocess_for_death_test) {
+  if (in_subprocess_for_death_test) {
+    return false;
+  }
+
+  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+  if (total_shards == -1 && shard_index == -1) {
+    return false;
+  } else if (total_shards == -1 && shard_index != -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestShardIndex << " = " << shard_index
+      << ", but have left " << kTestTotalShards << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (total_shards != -1 && shard_index == -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestTotalShards << " = " << total_shards
+      << ", but have left " << kTestShardIndex << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (shard_index < 0 || shard_index >= total_shards) {
+    const Message msg = Message()
+      << "Invalid environment variables: we require 0 <= "
+      << kTestShardIndex << " < " << kTestTotalShards
+      << ", but you have " << kTestShardIndex << "=" << shard_index
+      << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  }
+
+  return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
+  const char* str_val = posix::GetEnv(var);
+  if (str_val == NULL) {
+    return default_val;
+  }
+
+  Int32 result;
+  if (!ParseInt32(Message() << "The value of environment variable " << var,
+                  str_val, &result)) {
+    exit(EXIT_FAILURE);
+  }
+  return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+  return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+  // num_runnable_tests are the number of tests that will
+  // run across all shards (i.e., match filter and are not disabled).
+  // num_selected_tests are the number of tests to be run on
+  // this shard.
+  int num_runnable_tests = 0;
+  int num_selected_tests = 0;
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    TestCase* const test_case = test_cases_[i];
+    const std::string &test_case_name = test_case->name();
+    test_case->set_should_run(false);
+
+    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+      TestInfo* const test_info = test_case->test_info_list()[j];
+      const std::string test_name(test_info->name());
+      // A test is disabled if test case name or test name matches
+      // kDisableTestFilter.
+      const bool is_disabled =
+          internal::UnitTestOptions::MatchesFilter(test_case_name,
+                                                   kDisableTestFilter) ||
+          internal::UnitTestOptions::MatchesFilter(test_name,
+                                                   kDisableTestFilter);
+      test_info->is_disabled_ = is_disabled;
+
+      const bool matches_filter =
+          internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+                                                       test_name);
+      test_info->matches_filter_ = matches_filter;
+
+      const bool is_runnable =
+          (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+          matches_filter;
+
+      const bool is_selected = is_runnable &&
+          (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+           ShouldRunTestOnShard(total_shards, shard_index,
+                                num_runnable_tests));
+
+      num_runnable_tests += is_runnable;
+      num_selected_tests += is_selected;
+
+      test_info->should_run_ = is_selected;
+      test_case->set_should_run(test_case->should_run() || is_selected);
+    }
+  }
+  return num_selected_tests;
+}
+
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n".  If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length) {
+  if (str != NULL) {
+    for (int i = 0; *str != '\0'; ++str) {
+      if (i >= max_length) {
+        printf("...");
+        break;
+      }
+      if (*str == '\n') {
+        printf("\\n");
+        i += 2;
+      } else {
+        printf("%c", *str);
+        ++i;
+      }
+    }
+  }
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+  // Print at most this many characters for each type/value parameter.
+  const int kMaxParamLength = 250;
+
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    const TestCase* const test_case = test_cases_[i];
+    bool printed_test_case_name = false;
+
+    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+      const TestInfo* const test_info =
+          test_case->test_info_list()[j];
+      if (test_info->matches_filter_) {
+        if (!printed_test_case_name) {
+          printed_test_case_name = true;
+          printf("%s.", test_case->name());
+          if (test_case->type_param() != NULL) {
+            printf("  # %s = ", kTypeParamLabel);
+            // We print the type parameter on a single line to make
+            // the output easy to parse by a program.
+            PrintOnOneLine(test_case->type_param(), kMaxParamLength);
+          }
+          printf("\n");
+        }
+        printf("  %s", test_info->name());
+        if (test_info->value_param() != NULL) {
+          printf("  # %s = ", kValueParamLabel);
+          // We print the value parameter on a single line to make the
+          // output easy to parse by a program.
+          PrintOnOneLine(test_info->value_param(), kMaxParamLength);
+        }
+        printf("\n");
+      }
+    }
+  }
+  fflush(stdout);
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+    OsStackTraceGetterInterface* getter) {
+  if (os_stack_trace_getter_ != getter) {
+    delete os_stack_trace_getter_;
+    os_stack_trace_getter_ = getter;
+  }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+  if (os_stack_trace_getter_ == NULL) {
+    os_stack_trace_getter_ = new OsStackTraceGetter;
+  }
+
+  return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+TestResult* UnitTestImpl::current_test_result() {
+  return current_test_info_ ?
+      &(current_test_info_->result_) : &ad_hoc_test_result_;
+}
+
+// Shuffles all test cases, and the tests within each test case,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+  // Shuffles the death test cases.
+  ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+
+  // Shuffles the non-death test cases.
+  ShuffleRange(random(), last_death_test_case_ + 1,
+               static_cast<int>(test_cases_.size()), &test_case_indices_);
+
+  // Shuffles the tests inside each test case.
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    test_cases_[i]->ShuffleTests(random());
+  }
+}
+
+// Restores the test cases and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    // Unshuffles the tests in each test case.
+    test_cases_[i]->UnshuffleTests();
+    // Resets the index of each test case.
+    test_case_indices_[i] = static_cast<int>(i);
+  }
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+                                            int skip_count) {
+  // We pass skip_count + 1 to skip this wrapper function in addition
+  // to what the user really wants to skip.
+  return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+  // This condition is always false so AlwaysTrue() never actually throws,
+  // but it makes the compiler think that it may throw.
+  if (IsTrue(false))
+    throw ClassUniqueToAlwaysTrue();
+#endif  // GTEST_HAS_EXCEPTIONS
+  return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false.  None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr) {
+  const size_t prefix_len = strlen(prefix);
+  if (strncmp(*pstr, prefix, prefix_len) == 0) {
+    *pstr += prefix_len;
+    return true;
+  }
+  return false;
+}
+
+// Parses a string as a command line flag.  The string should have
+// the format "--flag=value".  When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+                           const char* flag,
+                           bool def_optional) {
+  // str and flag must not be NULL.
+  if (str == NULL || flag == NULL) return NULL;
+
+  // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+  const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
+  const size_t flag_len = flag_str.length();
+  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+  // Skips the flag name.
+  const char* flag_end = str + flag_len;
+
+  // When def_optional is true, it's OK to not have a "=value" part.
+  if (def_optional && (flag_end[0] == '\0')) {
+    return flag_end;
+  }
+
+  // If def_optional is true and there are more characters after the
+  // flag name, or if def_optional is false, there must be a '=' after
+  // the flag name.
+  if (flag_end[0] != '=') return NULL;
+
+  // Returns the string after "=".
+  return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, true);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Converts the string value to a bool.
+  *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+  return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  return ParseInt32(Message() << "The value of flag --" << flag,
+                    value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  *value = value_str;
+  return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str) {
+  return (SkipPrefix("--", &str) ||
+          SkipPrefix("-", &str) ||
+          SkipPrefix("/", &str)) &&
+         !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+         (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+          SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text.  The following escape
+// sequences can be used in the string to control the text color:
+//
+//   @@    prints a single '@' character.
+//   @R    changes the color to red.
+//   @G    changes the color to green.
+//   @Y    changes the color to yellow.
+//   @D    changes to the default terminal text color.
+//
+// TODO(wan@google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str) {
+  GTestColor color = COLOR_DEFAULT;  // The current color.
+
+  // Conceptually, we split the string into segments divided by escape
+  // sequences.  Then we print one segment at a time.  At the end of
+  // each iteration, the str pointer advances to the beginning of the
+  // next segment.
+  for (;;) {
+    const char* p = strchr(str, '@');
+    if (p == NULL) {
+      ColoredPrintf(color, "%s", str);
+      return;
+    }
+
+    ColoredPrintf(color, "%s", std::string(str, p).c_str());
+
+    const char ch = p[1];
+    str = p + 2;
+    if (ch == '@') {
+      ColoredPrintf(color, "@");
+    } else if (ch == 'D') {
+      color = COLOR_DEFAULT;
+    } else if (ch == 'R') {
+      color = COLOR_RED;
+    } else if (ch == 'G') {
+      color = COLOR_GREEN;
+    } else if (ch == 'Y') {
+      color = COLOR_YELLOW;
+    } else {
+      --str;
+    }
+  }
+}
+
+static const char kColorEncodedHelpMessage[] =
+"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+"following command line flags to control its behavior:\n"
+"\n"
+"Test Selection:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
+"      List the names of all tests instead of running them. The name of\n"
+"      TEST(Foo, Bar) is \"Foo.Bar\".\n"
+"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+    "[@G-@YNEGATIVE_PATTERNS]@D\n"
+"      Run only the tests whose name matches one of the positive patterns but\n"
+"      none of the negative patterns. '?' matches any single character; '*'\n"
+"      matches any substring; ':' separates two patterns.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
+"      Run all disabled tests too.\n"
+"\n"
+"Test Execution:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+"      Run the tests repeatedly; use a negative count to repeat forever.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
+"      Randomize tests' orders on every iteration.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
+"      Random number seed to use for shuffling test orders (between 1 and\n"
+"      99999, or 0 to use a seed based on the current time).\n"
+"\n"
+"Test Output:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+"      Enable/disable colored output. The default is @Gauto@D.\n"
+"  -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
+"      Don't print the elapsed time of each test.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
+    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+"      Generate an XML report in the given directory or with the given file\n"
+"      name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
+#if GTEST_CAN_STREAM_RESULTS_
+"  @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n"
+"      Stream test results to the given server.\n"
+#endif  // GTEST_CAN_STREAM_RESULTS_
+"\n"
+"Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+"      Set the default death test style.\n"
+#endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
+"      Turn assertion failures into debugger break-points.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
+"      Turn assertion failures into C++ exceptions.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
+"      Do not report exceptions as test failures. Instead, allow them\n"
+"      to crash the program or throw a pop-up (on Windows).\n"
+"\n"
+"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
+    "the corresponding\n"
+"environment variable of a flag (all letters in upper-case). For example, to\n"
+"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+    "color=no@D or set\n"
+"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
+"\n"
+"For more information, please read the " GTEST_NAME_ " documentation at\n"
+"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+"(not one in your own code or tests), please report it to\n"
+"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.  The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+  for (int i = 1; i < *argc; i++) {
+    const std::string arg_string = StreamableToString(argv[i]);
+    const char* const arg = arg_string.c_str();
+
+    using internal::ParseBoolFlag;
+    using internal::ParseInt32Flag;
+    using internal::ParseStringFlag;
+
+    // Do we see a Google Test flag?
+    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+                      &GTEST_FLAG(also_run_disabled_tests)) ||
+        ParseBoolFlag(arg, kBreakOnFailureFlag,
+                      &GTEST_FLAG(break_on_failure)) ||
+        ParseBoolFlag(arg, kCatchExceptionsFlag,
+                      &GTEST_FLAG(catch_exceptions)) ||
+        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+        ParseStringFlag(arg, kDeathTestStyleFlag,
+                        &GTEST_FLAG(death_test_style)) ||
+        ParseBoolFlag(arg, kDeathTestUseFork,
+                      &GTEST_FLAG(death_test_use_fork)) ||
+        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+        ParseStringFlag(arg, kInternalRunDeathTestFlag,
+                        &GTEST_FLAG(internal_run_death_test)) ||
+        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+        ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+        ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+        ParseInt32Flag(arg, kStackTraceDepthFlag,
+                       &GTEST_FLAG(stack_trace_depth)) ||
+        ParseStringFlag(arg, kStreamResultToFlag,
+                        &GTEST_FLAG(stream_result_to)) ||
+        ParseBoolFlag(arg, kThrowOnFailureFlag,
+                      &GTEST_FLAG(throw_on_failure))
+        ) {
+      // Yes.  Shift the remainder of the argv list left by one.  Note
+      // that argv has (*argc + 1) elements, the last one always being
+      // NULL.  The following loop moves the trailing NULL element as
+      // well.
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+
+      // Decrements the argument count.
+      (*argc)--;
+
+      // We also need to decrement the iterator as we just removed
+      // an element.
+      i--;
+    } else if (arg_string == "--help" || arg_string == "-h" ||
+               arg_string == "-?" || arg_string == "/?" ||
+               HasGoogleTestFlagPrefix(arg)) {
+      // Both help flag and unrecognized Google Test flags (excluding
+      // internal ones) trigger help display.
+      g_help_flag = true;
+    }
+  }
+
+  if (g_help_flag) {
+    // We print the help here instead of in RUN_ALL_TESTS(), as the
+    // latter may not be called at all if the user is using Google
+    // Test with another testing framework.
+    PrintColorEncoded(kColorEncodedHelpMessage);
+  }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+  g_init_gtest_count++;
+
+  // We don't want to run the initialization code twice.
+  if (g_init_gtest_count != 1) return;
+
+  if (*argc <= 0) return;
+
+  internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+
+  g_argvs.clear();
+  for (int i = 0; i != *argc; i++) {
+    g_argvs.push_back(StreamableToString(argv[i]));
+  }
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+  ParseGoogleTestFlagsOnly(argc, argv);
+  GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+}  // namespace internal
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+}  // namespace testing
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_MAC
+#  include <crt_externs.h>
+# endif  // GTEST_OS_MAC
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+
+# if GTEST_OS_LINUX
+#  include <signal.h>
+# endif  // GTEST_OS_LINUX
+
+# include <stdarg.h>
+
+# if GTEST_OS_WINDOWS
+#  include <windows.h>
+# else
+#  include <sys/mman.h>
+#  include <sys/wait.h>
+# endif  // GTEST_OS_WINDOWS
+
+# if GTEST_OS_QNX
+#  include <spawn.h>
+# endif  // GTEST_OS_QNX
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+    death_test_style,
+    internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+    "Indicates how to run a death test in a forked child process: "
+    "\"threadsafe\" (child process re-executes the test binary "
+    "from the beginning, running only the specific death test) or "
+    "\"fast\" (child process runs the death test immediately "
+    "after forking).");
+
+GTEST_DEFINE_bool_(
+    death_test_use_fork,
+    internal::BoolFromGTestEnv("death_test_use_fork", false),
+    "Instructs to use fork()/_exit() instead of clone() in death tests. "
+    "Ignored and always uses fork() on POSIX systems where clone() is not "
+    "implemented. Useful when running under valgrind or similar tools if "
+    "those do not support clone(). Valgrind 3.3.1 will just fail if "
+    "it sees an unsupported combination of clone() flags. "
+    "It is not recommended to use this flag w/o valgrind though it will "
+    "work in 99% of the cases. Once valgrind is fixed, this flag will "
+    "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+    internal_run_death_test, "",
+    "Indicates the file, line number, temporal index of "
+    "the single death test to run, and a file descriptor to "
+    "which a success code may be sent, all separated by "
+    "the '|' characters.  This flag is specified if and only if the current "
+    "process is a sub-process launched for running a thread-safe "
+    "death test.  FOR INTERNAL USE ONLY.");
+}  // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Valid only for fast death tests. Indicates the code is running in the
+// child process of a fast style death test.
+static bool g_in_fast_death_test_child = false;
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process.  Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests.  IMPORTANT: This is an internal utility.  Using it may break the
+// implementation of death tests.  User code MUST NOT use it.
+bool InDeathTestChild() {
+# if GTEST_OS_WINDOWS
+
+  // On Windows, death tests are thread-safe regardless of the value of the
+  // death_test_style flag.
+  return !GTEST_FLAG(internal_run_death_test).empty();
+
+# else
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe")
+    return !GTEST_FLAG(internal_run_death_test).empty();
+  else
+    return g_in_fast_death_test_child;
+#endif
+}
+
+}  // namespace internal
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+# if GTEST_OS_WINDOWS
+
+  return exit_status == exit_code_;
+
+# else
+
+  return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+# endif  // GTEST_OS_WINDOWS
+}
+
+# if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+  return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+# endif  // !GTEST_OS_WINDOWS
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static std::string ExitSummary(int exit_code) {
+  Message m;
+
+# if GTEST_OS_WINDOWS
+
+  m << "Exited with exit status " << exit_code;
+
+# else
+
+  if (WIFEXITED(exit_code)) {
+    m << "Exited with exit status " << WEXITSTATUS(exit_code);
+  } else if (WIFSIGNALED(exit_code)) {
+    m << "Terminated by signal " << WTERMSIG(exit_code);
+  }
+#  ifdef WCOREDUMP
+  if (WCOREDUMP(exit_code)) {
+    m << " (core dumped)";
+  }
+#  endif
+# endif  // GTEST_OS_WINDOWS
+
+  return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+  return !ExitedWithCode(0)(exit_status);
+}
+
+# if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement.  It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static std::string DeathTestThreadWarning(size_t thread_count) {
+  Message msg;
+  msg << "Death tests use fork(), which is unsafe particularly"
+      << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+  if (thread_count == 0)
+    msg << "couldn't detect the number of threads.";
+  else
+    msg << "detected " << thread_count << " threads.";
+  return msg.GetString();
+}
+# endif  // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestThrew = 'T';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test can
+// conclude.  DIED means that the process died while executing the test
+// code; LIVED means that process lived beyond the end of the test code;
+// RETURNED means that the test statement attempted to execute a return
+// statement, which is not allowed; THREW means that the test statement
+// returned control by throwing an exception.  IN_PROGRESS means the test
+// has not yet concluded.
+// TODO(vladl@google.com): Unify names and possibly values for
+// AbortReason, DeathTestOutcome, and flag characters above.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process.  Otherwise, the
+// message is simply printed to stderr.  In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const std::string& message) {
+  // On a POSIX system, this function may be called from a threadsafe-style
+  // death test child process, which operates on a very small stack.  Use
+  // the heap for any additional non-minuscule memory requirements.
+  const InternalRunDeathTestFlag* const flag =
+      GetUnitTestImpl()->internal_run_death_test_flag();
+  if (flag != NULL) {
+    FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+    fputc(kDeathTestInternalError, parent);
+    fprintf(parent, "%s", message.c_str());
+    fflush(parent);
+    _exit(1);
+  } else {
+    fprintf(stderr, "%s", message.c_str());
+    fflush(stderr);
+    posix::Abort();
+  }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+# define GTEST_DEATH_TEST_CHECK_(expression) \
+  do { \
+    if (!::testing::internal::IsTrue(expression)) { \
+      DeathTestAbort( \
+          ::std::string("CHECK failed: File ") + __FILE__ +  ", line " \
+          + ::testing::internal::StreamableToString(__LINE__) + ": " \
+          + #expression); \
+    } \
+  } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again.  The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR.  If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+  do { \
+    int gtest_retval; \
+    do { \
+      gtest_retval = (expression); \
+    } while (gtest_retval == -1 && errno == EINTR); \
+    if (gtest_retval == -1) { \
+      DeathTestAbort( \
+          ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+          + ::testing::internal::StreamableToString(__LINE__) + ": " \
+          + #expression + " != -1"); \
+    } \
+  } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+std::string GetLastErrnoDescription() {
+    return errno == 0 ? "" : posix::StrError(errno);
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+  Message error;
+  char buffer[256];
+  int num_read;
+
+  do {
+    while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+      buffer[num_read] = '\0';
+      error << buffer;
+    }
+  } while (num_read == -1 && errno == EINTR);
+
+  if (num_read == 0) {
+    GTEST_LOG_(FATAL) << error.GetString();
+  } else {
+    const int last_error = errno;
+    GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+                      << GetLastErrnoDescription() << " [" << last_error << "]";
+  }
+}
+
+// Death test constructor.  Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+  TestInfo* const info = GetUnitTestImpl()->current_test_info();
+  if (info == NULL) {
+    DeathTestAbort("Cannot run a death test outside of a TEST or "
+                   "TEST_F construct");
+  }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+                       const char* file, int line, DeathTest** test) {
+  return GetUnitTestImpl()->death_test_factory()->Create(
+      statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+  return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const std::string& message) {
+  last_death_test_message_ = message;
+}
+
+std::string DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+  DeathTestImpl(const char* a_statement, const RE* a_regex)
+      : statement_(a_statement),
+        regex_(a_regex),
+        spawned_(false),
+        status_(-1),
+        outcome_(IN_PROGRESS),
+        read_fd_(-1),
+        write_fd_(-1) {}
+
+  // read_fd_ is expected to be closed and cleared by a derived class.
+  ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+  void Abort(AbortReason reason);
+  virtual bool Passed(bool status_ok);
+
+  const char* statement() const { return statement_; }
+  const RE* regex() const { return regex_; }
+  bool spawned() const { return spawned_; }
+  void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+  int status() const { return status_; }
+  void set_status(int a_status) { status_ = a_status; }
+  DeathTestOutcome outcome() const { return outcome_; }
+  void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+  int read_fd() const { return read_fd_; }
+  void set_read_fd(int fd) { read_fd_ = fd; }
+  int write_fd() const { return write_fd_; }
+  void set_write_fd(int fd) { write_fd_ = fd; }
+
+  // Called in the parent process only. Reads the result code of the death
+  // test child process via a pipe, interprets it to set the outcome_
+  // member, and closes read_fd_.  Outputs diagnostics and terminates in
+  // case of unexpected codes.
+  void ReadAndInterpretStatusByte();
+
+ private:
+  // The textual content of the code this object is testing.  This class
+  // doesn't own this string and should not attempt to delete it.
+  const char* const statement_;
+  // The regular expression which test output must match.  DeathTestImpl
+  // doesn't own this object and should not attempt to delete it.
+  const RE* const regex_;
+  // True if the death test child process has been successfully spawned.
+  bool spawned_;
+  // The exit status of the child process.
+  int status_;
+  // How the death test concluded.
+  DeathTestOutcome outcome_;
+  // Descriptor to the read end of the pipe to the child process.  It is
+  // always -1 in the child process.  The child keeps its write end of the
+  // pipe in write_fd_.
+  int read_fd_;
+  // Descriptor to the child's write end of the pipe to the parent process.
+  // It is always -1 in the parent process.  The parent keeps its end of the
+  // pipe in read_fd_.
+  int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_.  Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+  char flag;
+  int bytes_read;
+
+  // The read() here blocks until data is available (signifying the
+  // failure of the death test) or until the pipe is closed (signifying
+  // its success), so it's okay to call this in the parent before
+  // the child process has exited.
+  do {
+    bytes_read = posix::Read(read_fd(), &flag, 1);
+  } while (bytes_read == -1 && errno == EINTR);
+
+  if (bytes_read == 0) {
+    set_outcome(DIED);
+  } else if (bytes_read == 1) {
+    switch (flag) {
+      case kDeathTestReturned:
+        set_outcome(RETURNED);
+        break;
+      case kDeathTestThrew:
+        set_outcome(THREW);
+        break;
+      case kDeathTestLived:
+        set_outcome(LIVED);
+        break;
+      case kDeathTestInternalError:
+        FailFromInternalError(read_fd());  // Does not return.
+        break;
+      default:
+        GTEST_LOG_(FATAL) << "Death test child process reported "
+                          << "unexpected status byte ("
+                          << static_cast<unsigned int>(flag) << ")";
+    }
+  } else {
+    GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+                      << GetLastErrnoDescription();
+  }
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+  set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+  // The parent process considers the death test to be a failure if
+  // it finds any data in our pipe.  So, here we write a single flag byte
+  // to the pipe, then exit.
+  const char status_ch =
+      reason == TEST_DID_NOT_DIE ? kDeathTestLived :
+      reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
+
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+  // We are leaking the descriptor here because on some platforms (i.e.,
+  // when built as Windows DLL), destructors of global objects will still
+  // run after calling _exit(). On such systems, write_fd_ will be
+  // indirectly closed from the destructor of UnitTestImpl, causing double
+  // close if it is also closed here. On debug configurations, double close
+  // may assert. As there are no in-process buffers to flush here, we are
+  // relying on the OS to close the descriptor after the process terminates
+  // when the destructors are not run.
+  _exit(1);  // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Returns an indented copy of stderr output for a death test.
+// This makes distinguishing death test output lines from regular log lines
+// much easier.
+static ::std::string FormatDeathTestOutput(const ::std::string& output) {
+  ::std::string ret;
+  for (size_t at = 0; ; ) {
+    const size_t line_end = output.find('\n', at);
+    ret += "[  DEATH   ] ";
+    if (line_end == ::std::string::npos) {
+      ret += output.substr(at);
+      break;
+    }
+    ret += output.substr(at, line_end + 1 - at);
+    at = line_end + 1;
+  }
+  return ret;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+//   outcome:  An enumeration describing how the death test
+//             concluded: DIED, LIVED, THREW, or RETURNED.  The death test
+//             fails in the latter three cases.
+//   status:   The exit status of the child process. On *nix, it is in the
+//             in the format specified by wait(2). On Windows, this is the
+//             value supplied to the ExitProcess() API or a numeric code
+//             of the exception that terminated the program.
+//   regex:    A regular expression object to be applied to
+//             the test's captured standard error output; the death test
+//             fails if it does not match.
+//
+// Argument:
+//   status_ok: true if exit_status is acceptable in the context of
+//              this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met.  Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+  if (!spawned())
+    return false;
+
+  const std::string error_message = GetCapturedStderr();
+
+  bool success = false;
+  Message buffer;
+
+  buffer << "Death test: " << statement() << "\n";
+  switch (outcome()) {
+    case LIVED:
+      buffer << "    Result: failed to die.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case THREW:
+      buffer << "    Result: threw an exception.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case RETURNED:
+      buffer << "    Result: illegal return in test statement.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case DIED:
+      if (status_ok) {
+        const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+        if (matched) {
+          success = true;
+        } else {
+          buffer << "    Result: died but not with expected error.\n"
+                 << "  Expected: " << regex()->pattern() << "\n"
+                 << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+        }
+      } else {
+        buffer << "    Result: died but not with expected exit code:\n"
+               << "            " << ExitSummary(status()) << "\n"
+               << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+      }
+      break;
+    case IN_PROGRESS:
+    default:
+      GTEST_LOG_(FATAL)
+          << "DeathTest::Passed somehow called before conclusion of test";
+  }
+
+  DeathTest::set_last_death_test_message(buffer.GetString());
+  return success;
+}
+
+# if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes:  Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+//    ends of it.
+// 2. The parent starts the child and provides it with the information
+//    necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+//    using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+//    this is done before step 3, the object's reference count goes down to
+//    0 and it is destroyed, preventing the child from acquiring it. The
+//    parent now has to release it, or read operations on the read end of
+//    the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+//    any possible error messages) from the pipe, and its stderr and then
+//    determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+  WindowsDeathTest(const char* a_statement,
+                   const RE* a_regex,
+                   const char* file,
+                   int line)
+      : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+  virtual TestRole AssumeRole();
+
+ private:
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+  // Handle to the write end of the pipe to the child process.
+  AutoHandle write_handle_;
+  // Child process handle.
+  AutoHandle child_handle_;
+  // Event the child process uses to signal the parent that it has
+  // acquired the handle to the write end of the pipe. After seeing this
+  // event the parent can release its own handles to make sure its
+  // ReadFile() calls return when the child terminates.
+  AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  // Wait until the child either signals that it has acquired the write end
+  // of the pipe or it dies.
+  const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+  switch (::WaitForMultipleObjects(2,
+                                   wait_handles,
+                                   FALSE,  // Waits for any of the handles.
+                                   INFINITE)) {
+    case WAIT_OBJECT_0:
+    case WAIT_OBJECT_0 + 1:
+      break;
+    default:
+      GTEST_DEATH_TEST_CHECK_(false);  // Should not get here.
+  }
+
+  // The child has acquired the write end of the pipe or exited.
+  // We release the handle on our side and continue.
+  write_handle_.Reset();
+  event_handle_.Reset();
+
+  ReadAndInterpretStatusByte();
+
+  // Waits for the child process to exit if it haven't already. This
+  // returns immediately if the child has already exited, regardless of
+  // whether previous calls to WaitForMultipleObjects synchronized on this
+  // handle or not.
+  GTEST_DEATH_TEST_CHECK_(
+      WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+                                             INFINITE));
+  DWORD status_code;
+  GTEST_DEATH_TEST_CHECK_(
+      ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
+  child_handle_.Reset();
+  set_status(static_cast<int>(status_code));
+  return status();
+}
+
+// The AssumeRole process for a Windows death test.  It creates a child
+// process with the same executable as the current process to run the
+// death test.  The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    // ParseInternalRunDeathTestFlag() has performed all the necessary
+    // processing.
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  // WindowsDeathTest uses an anonymous pipe to communicate results of
+  // a death test.
+  SECURITY_ATTRIBUTES handles_are_inheritable = {
+    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+  HANDLE read_handle, write_handle;
+  GTEST_DEATH_TEST_CHECK_(
+      ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+                   0)  // Default buffer size.
+      != FALSE);
+  set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+                                O_RDONLY));
+  write_handle_.Reset(write_handle);
+  event_handle_.Reset(::CreateEvent(
+      &handles_are_inheritable,
+      TRUE,    // The event will automatically reset to non-signaled state.
+      FALSE,   // The initial state is non-signalled.
+      NULL));  // The even is unnamed.
+  GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+  const std::string filter_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
+      info->test_case_name() + "." + info->name();
+  const std::string internal_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
+      "=" + file_ + "|" + StreamableToString(line_) + "|" +
+      StreamableToString(death_test_index) + "|" +
+      StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
+      // size_t has the same width as pointers on both 32-bit and 64-bit
+      // Windows platforms.
+      // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+      "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
+      "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
+
+  char executable_path[_MAX_PATH + 1];  // NOLINT
+  GTEST_DEATH_TEST_CHECK_(
+      _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+                                            executable_path,
+                                            _MAX_PATH));
+
+  std::string command_line =
+      std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
+      internal_flag + "\"";
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // Flush the log buffers since the log streams are shared with the child.
+  FlushInfoLog();
+
+  // The child process will share the standard handles with the parent.
+  STARTUPINFOA startup_info;
+  memset(&startup_info, 0, sizeof(STARTUPINFO));
+  startup_info.dwFlags = STARTF_USESTDHANDLES;
+  startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+  startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+  PROCESS_INFORMATION process_info;
+  GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+      executable_path,
+      const_cast<char*>(command_line.c_str()),
+      NULL,   // Retuned process handle is not inheritable.
+      NULL,   // Retuned thread handle is not inheritable.
+      TRUE,   // Child inherits all inheritable handles (for write_handle_).
+      0x0,    // Default creation flags.
+      NULL,   // Inherit the parent's environment.
+      UnitTest::GetInstance()->original_working_dir(),
+      &startup_info,
+      &process_info) != FALSE);
+  child_handle_.Reset(process_info.hProcess);
+  ::CloseHandle(process_info.hThread);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+# else  // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface.  Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+  ForkingDeathTest(const char* statement, const RE* regex);
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+
+ protected:
+  void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+  // PID of child process during death test; 0 in the child process itself.
+  pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+    : DeathTestImpl(a_statement, a_regex),
+      child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  ReadAndInterpretStatusByte();
+
+  int status_value;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+  set_status(status_value);
+  return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+  NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+      ForkingDeathTest(a_statement, a_regex) { }
+  virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test.  It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+  const size_t thread_count = GetThreadCount();
+  if (thread_count != 1) {
+    GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+  DeathTest::set_last_death_test_message("");
+  CaptureStderr();
+  // When we fork the process below, the log file buffers are copied, but the
+  // file descriptors are shared.  We flush all log files here so that closing
+  // the file descriptors in the child process doesn't throw off the
+  // synchronization between descriptors and buffers in the parent process.
+  // This is as close to the fork as possible to avoid a race condition in case
+  // there are multiple threads running before the death test, and another
+  // thread writes to the log file.
+  FlushInfoLog();
+
+  const pid_t child_pid = fork();
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  set_child_pid(child_pid);
+  if (child_pid == 0) {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+    set_write_fd(pipe_fd[1]);
+    // Redirects all logging to stderr in the child process to prevent
+    // concurrent writes to the log files.  We capture stderr in the parent
+    // process and append the child process' output to a log.
+    LogToStderr();
+    // Event forwarding to the listeners of event listener API mush be shut
+    // down in death test subprocesses.
+    GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+    g_in_fast_death_test_child = true;
+    return EXECUTE_TEST;
+  } else {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+    set_read_fd(pipe_fd[0]);
+    set_spawned(true);
+    return OVERSEE_TEST;
+  }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+  ExecDeathTest(const char* a_statement, const RE* a_regex,
+                const char* file, int line) :
+      ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
+  virtual TestRole AssumeRole();
+ private:
+  static ::std::vector<testing::internal::string>
+  GetArgvsForDeathTestChildProcess() {
+    ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+    return args;
+  }
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+  Arguments() {
+    args_.push_back(NULL);
+  }
+
+  ~Arguments() {
+    for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+         ++i) {
+      free(*i);
+    }
+  }
+  void AddArgument(const char* argument) {
+    args_.insert(args_.end() - 1, posix::StrDup(argument));
+  }
+
+  template <typename Str>
+  void AddArguments(const ::std::vector<Str>& arguments) {
+    for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+         i != arguments.end();
+         ++i) {
+      args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+    }
+  }
+  char* const* Argv() {
+    return &args_[0];
+  }
+
+ private:
+  std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+  char* const* argv;  // Command-line arguments for the child's call to exec
+  int close_fd;       // File descriptor to close; the read end of a pipe
+};
+
+#  if GTEST_OS_MAC
+inline char** GetEnviron() {
+  // When Google Test is built as a framework on MacOS X, the environ variable
+  // is unavailable. Apple's documentation (man environ) recommends using
+  // _NSGetEnviron() instead.
+  return *_NSGetEnviron();
+}
+#  else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#  endif  // GTEST_OS_MAC
+
+#  if !GTEST_OS_QNX
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+  ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+  // We need to execute the test program in the same environment where
+  // it was originally invoked.  Therefore we change to the original
+  // working directory first.
+  const char* const original_dir =
+      UnitTest::GetInstance()->original_working_dir();
+  // We can safely call chdir() as it's a direct system call.
+  if (chdir(original_dir) != 0) {
+    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+                   GetLastErrnoDescription());
+    return EXIT_FAILURE;
+  }
+
+  // We can safely call execve() as it's a direct system call.  We
+  // cannot use execvp() as it's a libc function and thus potentially
+  // unsafe.  Since execve() doesn't search the PATH, the user must
+  // invoke the test program via a valid path that contains at least
+  // one path separator.
+  execve(args->argv[0], args->argv, GetEnviron());
+  DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
+                 original_dir + " failed: " +
+                 GetLastErrnoDescription());
+  return EXIT_FAILURE;
+}
+#  endif  // !GTEST_OS_QNX
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+//
+// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
+// StackLowerThanAddress into StackGrowsDown, which then doesn't give
+// correct answer.
+void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
+void StackLowerThanAddress(const void* ptr, bool* result) {
+  int dummy;
+  *result = (&dummy < ptr);
+}
+
+bool StackGrowsDown() {
+  int dummy;
+  bool result;
+  StackLowerThanAddress(&dummy, &result);
+  return result;
+}
+
+// Spawns a child process with the same executable as the current process in
+// a thread-safe manner and instructs it to run the death test.  The
+// implementation uses fork(2) + exec.  On systems where clone(2) is
+// available, it is used instead, being slightly more thread-safe.  On QNX,
+// fork supports only single-threaded environments, so this function uses
+// spawn(2) there instead.  The function dies with an error message if
+// anything goes wrong.
+static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
+  ExecDeathTestArgs args = { argv, close_fd };
+  pid_t child_pid = -1;
+
+#  if GTEST_OS_QNX
+  // Obtains the current directory and sets it to be closed in the child
+  // process.
+  const int cwd_fd = open(".", O_RDONLY);
+  GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
+  // We need to execute the test program in the same environment where
+  // it was originally invoked.  Therefore we change to the original
+  // working directory first.
+  const char* const original_dir =
+      UnitTest::GetInstance()->original_working_dir();
+  // We can safely call chdir() as it's a direct system call.
+  if (chdir(original_dir) != 0) {
+    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+                   GetLastErrnoDescription());
+    return EXIT_FAILURE;
+  }
+
+  int fd_flags;
+  // Set close_fd to be closed after spawn.
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
+                                        fd_flags | FD_CLOEXEC));
+  struct inheritance inherit = {0};
+  // spawn is a system call.
+  child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
+  // Restores the current working directory.
+  GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
+
+#  else   // GTEST_OS_QNX
+#   if GTEST_OS_LINUX
+  // When a SIGPROF signal is received while fork() or clone() are executing,
+  // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+  // it after the call to fork()/clone() is complete.
+  struct sigaction saved_sigprof_action;
+  struct sigaction ignore_sigprof_action;
+  memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+  sigemptyset(&ignore_sigprof_action.sa_mask);
+  ignore_sigprof_action.sa_handler = SIG_IGN;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
+      SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+#   endif  // GTEST_OS_LINUX
+
+#   if GTEST_HAS_CLONE
+  const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+  if (!use_fork) {
+    static const bool stack_grows_down = StackGrowsDown();
+    const size_t stack_size = getpagesize();
+    // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+    void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+                             MAP_ANON | MAP_PRIVATE, -1, 0);
+    GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+
+    // Maximum stack alignment in bytes:  For a downward-growing stack, this
+    // amount is subtracted from size of the stack space to get an address
+    // that is within the stack space and is aligned on all systems we care
+    // about.  As far as I know there is no ABI with stack alignment greater
+    // than 64.  We assume stack and stack_size already have alignment of
+    // kMaxStackAlignment.
+    const size_t kMaxStackAlignment = 64;
+    void* const stack_top =
+        static_cast<char*>(stack) +
+            (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
+    GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
+        reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
+
+    child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+    GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+  }
+#   else
+  const bool use_fork = true;
+#   endif  // GTEST_HAS_CLONE
+
+  if (use_fork && (child_pid = fork()) == 0) {
+      ExecDeathTestChildMain(&args);
+      _exit(0);
+  }
+#  endif  // GTEST_OS_QNX
+#  if GTEST_OS_LINUX
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(
+      sigaction(SIGPROF, &saved_sigprof_action, NULL));
+#  endif  // GTEST_OS_LINUX
+
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test.  It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+  // Clear the close-on-exec flag on the write end of the pipe, lest
+  // it be closed when the child process does an exec:
+  GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+  const std::string filter_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
+      + info->test_case_name() + "." + info->name();
+  const std::string internal_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+      + file_ + "|" + StreamableToString(line_) + "|"
+      + StreamableToString(death_test_index) + "|"
+      + StreamableToString(pipe_fd[1]);
+  Arguments args;
+  args.AddArguments(GetArgvsForDeathTestChildProcess());
+  args.AddArgument(filter_flag.c_str());
+  args.AddArgument(internal_flag.c_str());
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // See the comment in NoExecDeathTest::AssumeRole for why the next line
+  // is necessary.
+  FlushInfoLog();
+
+  const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+  set_child_pid(child_pid);
+  set_read_fd(pipe_fd[0]);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+
+# endif  // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address.  If the test should be
+// skipped, sets that pointer to NULL.  Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+                                     const char* file, int line,
+                                     DeathTest** test) {
+  UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const int death_test_index = impl->current_test_info()
+      ->increment_death_test_count();
+
+  if (flag != NULL) {
+    if (death_test_index > flag->index()) {
+      DeathTest::set_last_death_test_message(
+          "Death test count (" + StreamableToString(death_test_index)
+          + ") somehow exceeded expected maximum ("
+          + StreamableToString(flag->index()) + ")");
+      return false;
+    }
+
+    if (!(flag->file() == file && flag->line() == line &&
+          flag->index() == death_test_index)) {
+      *test = NULL;
+      return true;
+    }
+  }
+
+# if GTEST_OS_WINDOWS
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+      GTEST_FLAG(death_test_style) == "fast") {
+    *test = new WindowsDeathTest(statement, regex, file, line);
+  }
+
+# else
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe") {
+    *test = new ExecDeathTest(statement, regex, file, line);
+  } else if (GTEST_FLAG(death_test_style) == "fast") {
+    *test = new NoExecDeathTest(statement, regex);
+  }
+
+# endif  // GTEST_OS_WINDOWS
+
+  else {  // NOLINT - this is more readable than unbalanced brackets inside #if.
+    DeathTest::set_last_death_test_message(
+        "Unknown death test style \"" + GTEST_FLAG(death_test_style)
+        + "\" encountered");
+    return false;
+  }
+
+  return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+                        ::std::vector< ::std::string>* dest) {
+  ::std::vector< ::std::string> parsed;
+  ::std::string::size_type pos = 0;
+  while (::testing::internal::AlwaysTrue()) {
+    const ::std::string::size_type colon = str.find(delimiter, pos);
+    if (colon == ::std::string::npos) {
+      parsed.push_back(str.substr(pos));
+      break;
+    } else {
+      parsed.push_back(str.substr(pos, colon - pos));
+      pos = colon + 1;
+    }
+  }
+  dest->swap(parsed);
+}
+
+# if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+                            size_t write_handle_as_size_t,
+                            size_t event_handle_as_size_t) {
+  AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+                                                   FALSE,  // Non-inheritable.
+                                                   parent_process_id));
+  if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+    DeathTestAbort("Unable to open parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  // TODO(vladl@google.com): Replace the following check with a
+  // compile-time assertion when available.
+  GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+  const HANDLE write_handle =
+      reinterpret_cast<HANDLE>(write_handle_as_size_t);
+  HANDLE dup_write_handle;
+
+  // The newly initialized handle is accessible only in in the parent
+  // process. To obtain one accessible within the child, we need to use
+  // DuplicateHandle.
+  if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+                         ::GetCurrentProcess(), &dup_write_handle,
+                         0x0,    // Requested privileges ignored since
+                                 // DUPLICATE_SAME_ACCESS is used.
+                         FALSE,  // Request non-inheritable handler.
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort("Unable to duplicate the pipe handle " +
+                   StreamableToString(write_handle_as_size_t) +
+                   " from the parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+  HANDLE dup_event_handle;
+
+  if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+                         ::GetCurrentProcess(), &dup_event_handle,
+                         0x0,
+                         FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort("Unable to duplicate the event handle " +
+                   StreamableToString(event_handle_as_size_t) +
+                   " from the parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  const int write_fd =
+      ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+  if (write_fd == -1) {
+    DeathTestAbort("Unable to convert pipe handle " +
+                   StreamableToString(write_handle_as_size_t) +
+                   " to a file descriptor");
+  }
+
+  // Signals the parent that the write end of the pipe has been acquired
+  // so the parent can release its own write end.
+  ::SetEvent(dup_event_handle);
+
+  return write_fd;
+}
+# endif  // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+  if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+  // can use it here.
+  int line = -1;
+  int index = -1;
+  ::std::vector< ::std::string> fields;
+  SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+  int write_fd = -1;
+
+# if GTEST_OS_WINDOWS
+
+  unsigned int parent_process_id = 0;
+  size_t write_handle_as_size_t = 0;
+  size_t event_handle_as_size_t = 0;
+
+  if (fields.size() != 6
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &parent_process_id)
+      || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+      || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+    DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+                   GTEST_FLAG(internal_run_death_test));
+  }
+  write_fd = GetStatusFileDescriptor(parent_process_id,
+                                     write_handle_as_size_t,
+                                     event_handle_as_size_t);
+# else
+
+  if (fields.size() != 4
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &write_fd)) {
+    DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+        + GTEST_FLAG(internal_run_death_test));
+  }
+
+# endif  // GTEST_OS_WINDOWS
+
+  return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+}  // namespace internal
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+# include <io.h>
+#elif GTEST_OS_SYMBIAN
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+# include <sys/syslimits.h>
+#else
+# include <limits.h>
+# include <climits>  // Some Linux distributions define PATH_MAX here.
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+# define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif  // GTEST_OS_WINDOWS
+
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kPathSeparatorString[] = "\\";
+const char kAlternatePathSeparatorString[] = "/";
+# if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+# else
+const char kCurrentDirectoryString[] = ".\\";
+# endif  // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif  // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c) {
+#if GTEST_HAS_ALT_PATH_SEP_
+  return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+  return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+  // Windows CE doesn't have a current directory, so we just return
+  // something reasonable.
+  return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+  const std::string dot_extension = std::string(".") + extension;
+  if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
+    return FilePath(pathname_.substr(
+        0, pathname_.length() - dot_extension.length()));
+  }
+  return *this;
+}
+
+// Returns a pointer to the last occurence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const {
+  const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+  const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+  // Comparing two pointers of which only one is NULL is undefined.
+  if (last_alt_sep != NULL &&
+      (last_sep == NULL || last_alt_sep > last_sep)) {
+    return last_alt_sep;
+  }
+#endif
+  return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+  const char* const last_sep = FindLastPathSeparator();
+  return last_sep ? FilePath(last_sep + 1) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+  const char* const last_sep = FindLastPathSeparator();
+  std::string dir;
+  if (last_sep) {
+    dir = std::string(c_str(), last_sep + 1 - c_str());
+  } else {
+    dir = kCurrentDirectoryString;
+  }
+  return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+                                const FilePath& base_name,
+                                int number,
+                                const char* extension) {
+  std::string file;
+  if (number == 0) {
+    file = base_name.string() + "." + extension;
+  } else {
+    file = base_name.string() + "_" + StreamableToString(number)
+        + "." + extension;
+  }
+  return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+                               const FilePath& relative_path) {
+  if (directory.IsEmpty())
+    return relative_path;
+  const FilePath dir(directory.RemoveTrailingPathSeparator());
+  return FilePath(dir.string() + kPathSeparator + relative_path.string());
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#if GTEST_OS_WINDOWS_MOBILE
+  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  return attributes != kInvalidFileAttributes;
+#else
+  posix::StatStruct file_stat;
+  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif  // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+  bool result = false;
+#if GTEST_OS_WINDOWS
+  // Don't strip off trailing separator if path is a root directory on
+  // Windows (like "C:\\").
+  const FilePath& path(IsRootDirectory() ? *this :
+                                           RemoveTrailingPathSeparator());
+#else
+  const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  if ((attributes != kInvalidFileAttributes) &&
+      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    result = true;
+  }
+#else
+  posix::StatStruct file_stat;
+  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+      posix::IsDir(file_stat);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+  return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+  // TODO(wan@google.com): on Windows a network share like
+  // \\server\share can be a root directory, although it cannot be the
+  // current directory.  Handle this properly.
+  return pathname_.length() == 3 && IsAbsolutePath();
+#else
+  return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+  const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+  return pathname_.length() >= 3 &&
+     ((name[0] >= 'a' && name[0] <= 'z') ||
+      (name[0] >= 'A' && name[0] <= 'Z')) &&
+     name[1] == ':' &&
+     IsPathSeparator(name[2]);
+#else
+  return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+                                          const FilePath& base_name,
+                                          const char* extension) {
+  FilePath full_pathname;
+  int number = 0;
+  do {
+    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+  } while (full_pathname.FileOrDirectoryExists());
+  return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+  return !pathname_.empty() &&
+         IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+  if (!this->IsDirectory()) {
+    return false;
+  }
+
+  if (pathname_.length() == 0 || this->DirectoryExists()) {
+    return true;
+  }
+
+  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS_MOBILE
+  FilePath removed_sep(this->RemoveTrailingPathSeparator());
+  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+  int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+  delete [] unicode;
+#elif GTEST_OS_WINDOWS
+  int result = _mkdir(pathname_.c_str());
+#else
+  int result = mkdir(pathname_.c_str(), 0777);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+  if (result == -1) {
+    return this->DirectoryExists();  // An error is OK if the directory exists.
+  }
+  return true;  // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+  return IsDirectory()
+      ? FilePath(pathname_.substr(0, pathname_.length() - 1))
+      : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
+void FilePath::Normalize() {
+  if (pathname_.c_str() == NULL) {
+    pathname_ = "";
+    return;
+  }
+  const char* src = pathname_.c_str();
+  char* const dest = new char[pathname_.length() + 1];
+  char* dest_ptr = dest;
+  memset(dest_ptr, 0, pathname_.length() + 1);
+
+  while (*src != '\0') {
+    *dest_ptr = *src;
+    if (!IsPathSeparator(*src)) {
+      src++;
+    } else {
+#if GTEST_HAS_ALT_PATH_SEP_
+      if (*dest_ptr == kAlternatePathSeparator) {
+        *dest_ptr = kPathSeparator;
+      }
+#endif
+      while (IsPathSeparator(*src))
+        src++;
+    }
+    dest_ptr++;
+  }
+  *dest_ptr = '\0';
+  pathname_ = dest;
+  delete[] dest;
+}
+
+}  // namespace internal
+}  // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>  // For TerminateProcess()
+#elif GTEST_OS_WINDOWS
+# include <io.h>
+# include <sys/stat.h>
+#else
+# include <unistd.h>
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_MAC
+# include <mach/mach_init.h>
+# include <mach/task.h>
+# include <mach/vm_map.h>
+#endif  // GTEST_OS_MAC
+
+#if GTEST_OS_QNX
+# include <devctl.h>
+# include <sys/procfs.h>
+#endif  // GTEST_OS_QNX
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif  // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+  const task_t task = mach_task_self();
+  mach_msg_type_number_t thread_count;
+  thread_act_array_t thread_list;
+  const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+  if (status == KERN_SUCCESS) {
+    // task_threads allocates resources in thread_list and we need to free them
+    // to avoid leaks.
+    vm_deallocate(task,
+                  reinterpret_cast<vm_address_t>(thread_list),
+                  sizeof(thread_t) * thread_count);
+    return static_cast<size_t>(thread_count);
+  } else {
+    return 0;
+  }
+}
+
+#elif GTEST_OS_QNX
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+  const int fd = open("/proc/self/as", O_RDONLY);
+  if (fd < 0) {
+    return 0;
+  }
+  procfs_info process_info;
+  const int status =
+      devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
+  close(fd);
+  if (status == EOK) {
+    return static_cast<size_t>(process_info.num_threads);
+  } else {
+    return 0;
+  }
+}
+
+#else
+
+size_t GetThreadCount() {
+  // There's no portable way to detect the number of threads, so we just
+  // return 0 to indicate that we cannot detect it.
+  return 0;
+}
+
+#endif  // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE.  Currently only needed for death tests.
+
+RE::~RE() {
+  if (is_valid_) {
+    // regfree'ing an invalid regex might crash because the content
+    // of the regex is undefined. Since the regex's are essentially
+    // the same, one cannot be valid (or invalid) without the other
+    // being so too.
+    regfree(&partial_regex_);
+    regfree(&full_regex_);
+  }
+  free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = posix::StrDup(regex);
+
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match.
+  const size_t full_regex_len = strlen(regex) + 10;
+  char* const full_pattern = new char[full_regex_len];
+
+  snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+  is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+  // We want to call regcomp(&partial_regex_, ...) even if the
+  // previous expression returns false.  Otherwise partial_regex_ may
+  // not be properly initialized can may cause trouble when it's
+  // freed.
+  //
+  // Some implementation of POSIX regex (e.g. on at least some
+  // versions of Cygwin) doesn't accept the empty string as a valid
+  // regex.  We change it to an equivalent form "()" to be safe.
+  if (is_valid_) {
+    const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+    is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+  }
+  EXPECT_TRUE(is_valid_)
+      << "Regular expression \"" << regex
+      << "\" is not a valid POSIX Extended regular expression.";
+
+  delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+  return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification.  Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsAsciiPunct(char ch) {
+  return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsAsciiWordChar(char ch) {
+  return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+      ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+  return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch.  The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+  if (escaped) {  // "\\p" where p is pattern_char.
+    switch (pattern_char) {
+      case 'd': return IsAsciiDigit(ch);
+      case 'D': return !IsAsciiDigit(ch);
+      case 'f': return ch == '\f';
+      case 'n': return ch == '\n';
+      case 'r': return ch == '\r';
+      case 's': return IsAsciiWhiteSpace(ch);
+      case 'S': return !IsAsciiWhiteSpace(ch);
+      case 't': return ch == '\t';
+      case 'v': return ch == '\v';
+      case 'w': return IsAsciiWordChar(ch);
+      case 'W': return !IsAsciiWordChar(ch);
+    }
+    return IsAsciiPunct(pattern_char) && pattern_char == ch;
+  }
+
+  return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+std::string FormatRegexSyntaxError(const char* regex, int index) {
+  return (Message() << "Syntax error at index " << index
+          << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+  if (regex == NULL) {
+    // TODO(wan@google.com): fix the source file location in the
+    // assertion failures to match where the regex is used in user
+    // code.
+    ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+    return false;
+  }
+
+  bool is_valid = true;
+
+  // True iff ?, *, or + can follow the previous atom.
+  bool prev_repeatable = false;
+  for (int i = 0; regex[i]; i++) {
+    if (regex[i] == '\\') {  // An escape sequence
+      i++;
+      if (regex[i] == '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "'\\' cannot appear at the end.";
+        return false;
+      }
+
+      if (!IsValidEscape(regex[i])) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "invalid escape sequence \"\\" << regex[i] << "\".";
+        is_valid = false;
+      }
+      prev_repeatable = true;
+    } else {  // Not an escape sequence.
+      const char ch = regex[i];
+
+      if (ch == '^' && i > 0) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'^' can only appear at the beginning.";
+        is_valid = false;
+      } else if (ch == '$' && regex[i + 1] != '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'$' can only appear at the end.";
+        is_valid = false;
+      } else if (IsInSet(ch, "()[]{}|")) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' is unsupported.";
+        is_valid = false;
+      } else if (IsRepeat(ch) && !prev_repeatable) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' can only follow a repeatable token.";
+        is_valid = false;
+      }
+
+      prev_repeatable = !IsInSet(ch, "^$?*+");
+    }
+  }
+
+  return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression.  The regex atom is defined as c if escaped is false,
+// or \c otherwise.  repeat is the repetition meta character (?, *,
+// or +).  The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway.  We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char c, char repeat, const char* regex,
+    const char* str) {
+  const size_t min_count = (repeat == '+') ? 1 : 0;
+  const size_t max_count = (repeat == '?') ? 1 :
+      static_cast<size_t>(-1) - 1;
+  // We cannot call numeric_limits::max() as it conflicts with the
+  // max() macro on Windows.
+
+  for (size_t i = 0; i <= max_count; ++i) {
+    // We know that the atom matches each of the first i characters in str.
+    if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+      // We have enough matches at the head, and the tail matches too.
+      // Since we only care about *whether* the pattern matches str
+      // (as opposed to *how* it matches), there is no need to find a
+      // greedy match.
+      return true;
+    }
+    if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+      return false;
+  }
+  return false;
+}
+
+// Returns true iff regex matches a prefix of str.  regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+  if (*regex == '\0')  // An empty regex matches a prefix of anything.
+    return true;
+
+  // "$" only matches the end of a string.  Note that regex being
+  // valid guarantees that there's nothing after "$" in it.
+  if (*regex == '$')
+    return *str == '\0';
+
+  // Is the first thing in regex an escape sequence?
+  const bool escaped = *regex == '\\';
+  if (escaped)
+    ++regex;
+  if (IsRepeat(regex[1])) {
+    // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+    // here's an indirect recursion.  It terminates as the regex gets
+    // shorter in each recursion.
+    return MatchRepetitionAndRegexAtHead(
+        escaped, regex[0], regex[1], regex + 2, str);
+  } else {
+    // regex isn't empty, isn't "$", and doesn't start with a
+    // repetition.  We match the first atom of regex with the first
+    // character of str and recurse.
+    return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+        MatchRegexAtHead(regex + 1, str + 1);
+  }
+}
+
+// Returns true iff regex matches any substring of str.  regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally.  In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+  if (regex == NULL || str == NULL)
+    return false;
+
+  if (*regex == '^')
+    return MatchRegexAtHead(regex + 1, str);
+
+  // A successful match can be anywhere in str.
+  do {
+    if (MatchRegexAtHead(regex, str))
+      return true;
+  } while (*str++ != '\0');
+  return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+  free(const_cast<char*>(pattern_));
+  free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = full_pattern_ = NULL;
+  if (regex != NULL) {
+    pattern_ = posix::StrDup(regex);
+  }
+
+  is_valid_ = ValidateRegex(regex);
+  if (!is_valid_) {
+    // No need to calculate the full pattern when the regex is invalid.
+    return;
+  }
+
+  const size_t len = strlen(regex);
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match: we need space to prepend a '^', append a '$', and
+  // terminate the string with '\0'.
+  char* buffer = static_cast<char*>(malloc(len + 3));
+  full_pattern_ = buffer;
+
+  if (*regex != '^')
+    *buffer++ = '^';  // Makes sure full_pattern_ starts with '^'.
+
+  // We don't use snprintf or strncpy, as they trigger a warning when
+  // compiled with VC++ 8.0.
+  memcpy(buffer, regex, len);
+  buffer += len;
+
+  if (len == 0 || regex[len - 1] != '$')
+    *buffer++ = '$';  // Makes sure full_pattern_ ends with '$'.
+
+  *buffer = '\0';
+}
+
+#endif  // GTEST_USES_POSIX_RE
+
+const char kUnknownFile[] = "unknown file";
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
+  const std::string file_name(file == NULL ? kUnknownFile : file);
+
+  if (line < 0) {
+    return file_name + ":";
+  }
+#ifdef _MSC_VER
+  return file_name + "(" + StreamableToString(line) + "):";
+#else
+  return file_name + ":" + StreamableToString(line) + ":";
+#endif  // _MSC_VER
+}
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+// Note that FormatCompilerIndependentFileLocation() does NOT append colon
+// to the file location it produces, unlike FormatFileLocation().
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
+    const char* file, int line) {
+  const std::string file_name(file == NULL ? kUnknownFile : file);
+
+  if (line < 0)
+    return file_name;
+  else
+    return file_name + ":" + StreamableToString(line);
+}
+
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+    : severity_(severity) {
+  const char* const marker =
+      severity == GTEST_INFO ?    "[  INFO ]" :
+      severity == GTEST_WARNING ? "[WARNING]" :
+      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
+  GetStream() << ::std::endl << marker << " "
+              << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog() {
+  GetStream() << ::std::endl;
+  if (severity_ == GTEST_FATAL) {
+    fflush(stderr);
+    posix::Abort();
+  }
+}
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif  // _MSC_VER
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream {
+ public:
+  // The ctor redirects the stream to a temporary file.
+  explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+# if GTEST_OS_WINDOWS
+    char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+    char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+
+    ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+    const UINT success = ::GetTempFileNameA(temp_dir_path,
+                                            "gtest_redir",
+                                            0,  // Generate unique file name.
+                                            temp_file_path);
+    GTEST_CHECK_(success != 0)
+        << "Unable to create a temporary file in " << temp_dir_path;
+    const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+    GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+                                    << temp_file_path;
+    filename_ = temp_file_path;
+# else
+    // There's no guarantee that a test has write access to the current
+    // directory, so we create the temporary file in the /tmp directory
+    // instead. We use /tmp on most systems, and /sdcard on Android.
+    // That's because Android doesn't have /tmp.
+#  if GTEST_OS_LINUX_ANDROID
+    // Note: Android applications are expected to call the framework's
+    // Context.getExternalStorageDirectory() method through JNI to get
+    // the location of the world-writable SD Card directory. However,
+    // this requires a Context handle, which cannot be retrieved
+    // globally from native code. Doing so also precludes running the
+    // code as part of a regular standalone executable, which doesn't
+    // run in a Dalvik process (e.g. when running it through 'adb shell').
+    //
+    // The location /sdcard is directly accessible from native code
+    // and is the only location (unofficially) supported by the Android
+    // team. It's generally a symlink to the real SD Card mount point
+    // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
+    // other OEM-customized locations. Never rely on these, and always
+    // use /sdcard.
+    char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
+#  else
+    char name_template[] = "/tmp/captured_stream.XXXXXX";
+#  endif  // GTEST_OS_LINUX_ANDROID
+    const int captured_fd = mkstemp(name_template);
+    filename_ = name_template;
+# endif  // GTEST_OS_WINDOWS
+    fflush(NULL);
+    dup2(captured_fd, fd_);
+    close(captured_fd);
+  }
+
+  ~CapturedStream() {
+    remove(filename_.c_str());
+  }
+
+  std::string GetCapturedString() {
+    if (uncaptured_fd_ != -1) {
+      // Restores the original stream.
+      fflush(NULL);
+      dup2(uncaptured_fd_, fd_);
+      close(uncaptured_fd_);
+      uncaptured_fd_ = -1;
+    }
+
+    FILE* const file = posix::FOpen(filename_.c_str(), "r");
+    const std::string content = ReadEntireFile(file);
+    posix::FClose(file);
+    return content;
+  }
+
+ private:
+  // Reads the entire content of a file as an std::string.
+  static std::string ReadEntireFile(FILE* file);
+
+  // Returns the size (in bytes) of a file.
+  static size_t GetFileSize(FILE* file);
+
+  const int fd_;  // A stream to capture.
+  int uncaptured_fd_;
+  // Name of the temporary file holding the stderr output.
+  ::std::string filename_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+// Returns the size (in bytes) of a file.
+size_t CapturedStream::GetFileSize(FILE* file) {
+  fseek(file, 0, SEEK_END);
+  return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+std::string CapturedStream::ReadEntireFile(FILE* file) {
+  const size_t file_size = GetFileSize(file);
+  char* const buffer = new char[file_size];
+
+  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
+  size_t bytes_read = 0;       // # of bytes read so far
+
+  fseek(file, 0, SEEK_SET);
+
+  // Keeps reading the file until we cannot read further or the
+  // pre-determined file size is reached.
+  do {
+    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+    bytes_read += bytes_last_read;
+  } while (bytes_last_read > 0 && bytes_read < file_size);
+
+  const std::string content(buffer, bytes_read);
+  delete[] buffer;
+
+  return content;
+}
+
+# ifdef _MSC_VER
+#  pragma warning(pop)
+# endif  // _MSC_VER
+
+static CapturedStream* g_captured_stderr = NULL;
+static CapturedStream* g_captured_stdout = NULL;
+
+// Starts capturing an output stream (stdout/stderr).
+void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
+  if (*stream != NULL) {
+    GTEST_LOG_(FATAL) << "Only one " << stream_name
+                      << " capturer can exist at a time.";
+  }
+  *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+std::string GetCapturedStream(CapturedStream** captured_stream) {
+  const std::string content = (*captured_stream)->GetCapturedString();
+
+  delete *captured_stream;
+  *captured_stream = NULL;
+
+  return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout() {
+  CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+  CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+std::string GetCapturedStdout() {
+  return GetCapturedStream(&g_captured_stdout);
+}
+
+// Stops capturing stderr and returns the captured string.
+std::string GetCapturedStderr() {
+  return GetCapturedStream(&g_captured_stderr);
+}
+
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+::std::vector<testing::internal::string> g_argvs;
+
+static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
+                                        NULL;  // Owned.
+
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
+  if (g_injected_test_argvs != argvs)
+    delete g_injected_test_argvs;
+  g_injected_test_argvs = argvs;
+}
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
+  if (g_injected_test_argvs != NULL) {
+    return *g_injected_test_argvs;
+  }
+  return g_argvs;
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix {
+void Abort() {
+  DebugBreak();
+  TerminateProcess(GetCurrentProcess(), 1);
+}
+}  // namespace posix
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag.  For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static std::string FlagToEnvVar(const char* flag) {
+  const std::string full_flag =
+      (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+  Message env_var;
+  for (size_t i = 0; i != full_flag.length(); i++) {
+    env_var << ToUpper(full_flag.c_str()[i]);
+  }
+
+  return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+  // Parses the environment variable as a decimal integer.
+  char* end = NULL;
+  const long long_value = strtol(str, &end, 10);  // NOLINT
+
+  // Has strtol() consumed all characters in the string?
+  if (*end != '\0') {
+    // No - an invalid character was encountered.
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value \"" << str << "\".\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  // Is the parsed value in the range of an Int32?
+  const Int32 result = static_cast<Int32>(long_value);
+  if (long_value == LONG_MAX || long_value == LONG_MIN ||
+      // The parsed value overflows as a long.  (strtol() returns
+      // LONG_MAX or LONG_MIN when the input overflows.)
+      result != long_value
+      // The parsed value overflows as an Int32.
+      ) {
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value " << str << ", which overflows.\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  *value = result;
+  return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  return string_value == NULL ?
+      default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  if (string_value == NULL) {
+    // The environment variable is not set.
+    return default_value;
+  }
+
+  Int32 result = default_value;
+  if (!ParseInt32(Message() << "Environment variable " << env_var,
+                  string_value, &result)) {
+    printf("The default value %s is used.\n",
+           (Message() << default_value).GetString().c_str());
+    fflush(stdout);
+    return default_value;
+  }
+
+  return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const value = posix::GetEnv(env_var.c_str());
+  return value == NULL ? default_value : value;
+}
+
+}  // namespace internal
+}  // namespace testing
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// It uses the << operator when possible, and prints the bytes in the
+// object otherwise.  A user can override its behavior for a class
+// type Foo by defining either operator<<(::std::ostream&, const Foo&)
+// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
+// defines Foo.
+
+#include <ctype.h>
+#include <stdio.h>
+#include <ostream>  // NOLINT
+#include <string>
+
+namespace testing {
+
+namespace {
+
+using ::std::ostream;
+
+// Prints a segment of bytes in the given object.
+void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
+                                size_t count, ostream* os) {
+  char text[5] = "";
+  for (size_t i = 0; i != count; i++) {
+    const size_t j = start + i;
+    if (i != 0) {
+      // Organizes the bytes into groups of 2 for easy parsing by
+      // human.
+      if ((j % 2) == 0)
+        *os << ' ';
+      else
+        *os << '-';
+    }
+    GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
+    *os << text;
+  }
+}
+
+// Prints the bytes in the given value to the given ostream.
+void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
+                              ostream* os) {
+  // Tells the user how big the object is.
+  *os << count << "-byte object <";
+
+  const size_t kThreshold = 132;
+  const size_t kChunkSize = 64;
+  // If the object size is bigger than kThreshold, we'll have to omit
+  // some details by printing only the first and the last kChunkSize
+  // bytes.
+  // TODO(wan): let the user control the threshold using a flag.
+  if (count < kThreshold) {
+    PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
+  } else {
+    PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
+    *os << " ... ";
+    // Rounds up to 2-byte boundary.
+    const size_t resume_pos = (count - kChunkSize + 1)/2*2;
+    PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
+  }
+  *os << ">";
+}
+
+}  // namespace
+
+namespace internal2 {
+
+// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
+// given object.  The delegation simplifies the implementation, which
+// uses the << operator and thus is easier done outside of the
+// ::testing::internal namespace, which contains a << operator that
+// sometimes conflicts with the one in STL.
+void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
+                          ostream* os) {
+  PrintBytesInObjectToImpl(obj_bytes, count, os);
+}
+
+}  // namespace internal2
+
+namespace internal {
+
+// Depending on the value of a char (or wchar_t), we print it in one
+// of three formats:
+//   - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
+//   - as a hexidecimal escape sequence (e.g. '\x7F'), or
+//   - as a special escape sequence (e.g. '\r', '\n').
+enum CharFormat {
+  kAsIs,
+  kHexEscape,
+  kSpecialEscape
+};
+
+// Returns true if c is a printable ASCII character.  We test the
+// value of c directly instead of calling isprint(), which is buggy on
+// Windows Mobile.
+inline bool IsPrintableAscii(wchar_t c) {
+  return 0x20 <= c && c <= 0x7E;
+}
+
+// Prints a wide or narrow char c as a character literal without the
+// quotes, escaping it when necessary; returns how c was formatted.
+// The template argument UnsignedChar is the unsigned version of Char,
+// which is the type of c.
+template <typename UnsignedChar, typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
+  switch (static_cast<wchar_t>(c)) {
+    case L'\0':
+      *os << "\\0";
+      break;
+    case L'\'':
+      *os << "\\'";
+      break;
+    case L'\\':
+      *os << "\\\\";
+      break;
+    case L'\a':
+      *os << "\\a";
+      break;
+    case L'\b':
+      *os << "\\b";
+      break;
+    case L'\f':
+      *os << "\\f";
+      break;
+    case L'\n':
+      *os << "\\n";
+      break;
+    case L'\r':
+      *os << "\\r";
+      break;
+    case L'\t':
+      *os << "\\t";
+      break;
+    case L'\v':
+      *os << "\\v";
+      break;
+    default:
+      if (IsPrintableAscii(c)) {
+        *os << static_cast<char>(c);
+        return kAsIs;
+      } else {
+        *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
+        return kHexEscape;
+      }
+  }
+  return kSpecialEscape;
+}
+
+// Prints a wchar_t c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+  switch (c) {
+    case L'\'':
+      *os << "'";
+      return kAsIs;
+    case L'"':
+      *os << "\\\"";
+      return kSpecialEscape;
+    default:
+      return PrintAsCharLiteralTo<wchar_t>(c, os);
+  }
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
+  return PrintAsStringLiteralTo(
+      static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
+}
+
+// Prints a wide or narrow character c and its code.  '\0' is printed
+// as "'\\0'", other unprintable characters are also properly escaped
+// using the standard C++ escape sequence.  The template argument
+// UnsignedChar is the unsigned version of Char, which is the type of c.
+template <typename UnsignedChar, typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os) {
+  // First, print c as a literal in the most readable form we can find.
+  *os << ((sizeof(c) > 1) ? "L'" : "'");
+  const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
+  *os << "'";
+
+  // To aid user debugging, we also print c's code in decimal, unless
+  // it's 0 (in which case c was printed as '\\0', making the code
+  // obvious).
+  if (c == 0)
+    return;
+  *os << " (" << static_cast<int>(c);
+
+  // For more convenience, we print c's code again in hexidecimal,
+  // unless c was already printed in the form '\x##' or the code is in
+  // [1, 9].
+  if (format == kHexEscape || (1 <= c && c <= 9)) {
+    // Do nothing.
+  } else {
+    *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
+  }
+  *os << ")";
+}
+
+void PrintTo(unsigned char c, ::std::ostream* os) {
+  PrintCharAndCodeTo<unsigned char>(c, os);
+}
+void PrintTo(signed char c, ::std::ostream* os) {
+  PrintCharAndCodeTo<unsigned char>(c, os);
+}
+
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its code.  L'\0' is printed as "L'\\0'".
+void PrintTo(wchar_t wc, ostream* os) {
+  PrintCharAndCodeTo<wchar_t>(wc, os);
+}
+
+// Prints the given array of characters to the ostream.  CharType must be either
+// char or wchar_t.
+// The array starts at begin, the length is len, it may include '\0' characters
+// and may not be NUL-terminated.
+template <typename CharType>
+static void PrintCharsAsStringTo(
+    const CharType* begin, size_t len, ostream* os) {
+  const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
+  *os << kQuoteBegin;
+  bool is_previous_hex = false;
+  for (size_t index = 0; index < len; ++index) {
+    const CharType cur = begin[index];
+    if (is_previous_hex && IsXDigit(cur)) {
+      // Previous character is of '\x..' form and this character can be
+      // interpreted as another hexadecimal digit in its number. Break string to
+      // disambiguate.
+      *os << "\" " << kQuoteBegin;
+    }
+    is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+  }
+  *os << "\"";
+}
+
+// Prints a (const) char/wchar_t array of 'len' elements, starting at address
+// 'begin'.  CharType must be either char or wchar_t.
+template <typename CharType>
+static void UniversalPrintCharArray(
+    const CharType* begin, size_t len, ostream* os) {
+  // The code
+  //   const char kFoo[] = "foo";
+  // generates an array of 4, not 3, elements, with the last one being '\0'.
+  //
+  // Therefore when printing a char array, we don't print the last element if
+  // it's '\0', such that the output matches the string literal as it's
+  // written in the source code.
+  if (len > 0 && begin[len - 1] == '\0') {
+    PrintCharsAsStringTo(begin, len - 1, os);
+    return;
+  }
+
+  // If, however, the last element in the array is not '\0', e.g.
+  //    const char kFoo[] = { 'f', 'o', 'o' };
+  // we must print the entire array.  We also print a message to indicate
+  // that the array is not NUL-terminated.
+  PrintCharsAsStringTo(begin, len, os);
+  *os << " (no terminating NUL)";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) wchar_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints the given C string to the ostream.
+void PrintTo(const char* s, ostream* os) {
+  if (s == NULL) {
+    *os << "NULL";
+  } else {
+    *os << ImplicitCast_<const void*>(s) << " pointing to ";
+    PrintCharsAsStringTo(s, strlen(s), os);
+  }
+}
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Prints the given wide C string to the ostream.
+void PrintTo(const wchar_t* s, ostream* os) {
+  if (s == NULL) {
+    *os << "NULL";
+  } else {
+    *os << ImplicitCast_<const void*>(s) << " pointing to ";
+    PrintCharsAsStringTo(s, wcslen(s), os);
+  }
+}
+#endif  // wchar_t is native
+
+// Prints a ::string object.
+#if GTEST_HAS_GLOBAL_STRING
+void PrintStringTo(const ::string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+// Prints a ::wstring object.
+#if GTEST_HAS_GLOBAL_WSTRING
+void PrintWideStringTo(const ::wstring& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+}  // namespace internal
+
+}  // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+std::string TestPartResult::ExtractSummary(const char* message) {
+  const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+  return stack_trace == NULL ? message :
+      std::string(message, stack_trace);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+  return os
+      << result.file_name() << ":" << result.line_number() << ": "
+      << (result.type() == TestPartResult::kSuccess ? "Success" :
+          result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
+          "Non-fatal failure") << ":\n"
+      << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+  array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+  if (index < 0 || index >= size()) {
+    printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+    internal::posix::Abort();
+  }
+
+  return array_[index];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+  return static_cast<int>(array_.size());
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+    : has_new_fatal_failure_(false),
+      original_reporter_(GetUnitTestImpl()->
+                         GetTestPartResultReporterForCurrentThread()) {
+  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+      original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+    const TestPartResult& result) {
+  if (result.fatally_failed())
+    has_new_fatal_failure_ = true;
+  original_reporter_->ReportTestPartResult(result);
+}
+
+}  // namespace internal
+
+}  // namespace testing
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+namespace testing {
+namespace internal {
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str) {
+  while (IsSpace(*str))
+    str++;
+  return str;
+}
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+    const char* file, int line, const char* registered_tests) {
+  typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+  registered_ = true;
+
+  // Skip initial whitespace in registered_tests since some
+  // preprocessors prefix stringizied literals with whitespace.
+  registered_tests = SkipSpaces(registered_tests);
+
+  Message errors;
+  ::std::set<std::string> tests;
+  for (const char* names = registered_tests; names != NULL;
+       names = SkipComma(names)) {
+    const std::string name = GetPrefixUntilComma(names);
+    if (tests.count(name) != 0) {
+      errors << "Test " << name << " is listed more than once.\n";
+      continue;
+    }
+
+    bool found = false;
+    for (DefinedTestIter it = defined_test_names_.begin();
+         it != defined_test_names_.end();
+         ++it) {
+      if (name == *it) {
+        found = true;
+        break;
+      }
+    }
+
+    if (found) {
+      tests.insert(name);
+    } else {
+      errors << "No test named " << name
+             << " can be found in this test case.\n";
+    }
+  }
+
+  for (DefinedTestIter it = defined_test_names_.begin();
+       it != defined_test_names_.end();
+       ++it) {
+    if (tests.count(*it) == 0) {
+      errors << "You forgot to list test " << *it << ".\n";
+    }
+  }
+
+  const std::string& errors_str = errors.GetString();
+  if (errors_str != "") {
+    fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+            errors_str.c_str());
+    fflush(stderr);
+    posix::Abort();
+  }
+
+  return registered_tests;
+}
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
diff --git a/gtest/gtest.h b/gtest/gtest.h
new file mode 100644
index 0000000..4f3804f
--- /dev/null
+++ b/gtest/gtest.h
@@ -0,0 +1,20061 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test.  It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#include <limits>
+#include <ostream>
+#include <vector>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms.  They are subject to change without notice.  DO NOT USE
+// THEM IN USER CODE.
+//
+// This file is fundamental to Google Test.  All other Google Test source
+// files are expected to #include this.  Therefore, it cannot #include
+// any other Google Test header.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior.  If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+//   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)
+//                              is/isn't available.
+//   GTEST_HAS_EXCEPTIONS     - Define it to 1/0 to indicate that exceptions
+//                              are enabled.
+//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::string, which is different to std::string).
+//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::wstring, which is different to std::wstring).
+//   GTEST_HAS_POSIX_RE       - Define it to 1/0 to indicate that POSIX regular
+//                              expressions are/aren't available.
+//   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>
+//                              is/isn't available.
+//   GTEST_HAS_RTTI           - Define it to 1/0 to indicate that RTTI is/isn't
+//                              enabled.
+//   GTEST_HAS_STD_WSTRING    - Define it to 1/0 to indicate that
+//                              std::wstring does/doesn't work (Google Test can
+//                              be used where std::wstring is unavailable).
+//   GTEST_HAS_TR1_TUPLE      - Define it to 1/0 to indicate tr1::tuple
+//                              is/isn't available.
+//   GTEST_HAS_SEH            - Define it to 1/0 to indicate whether the
+//                              compiler supports Microsoft's "Structured
+//                              Exception Handling".
+//   GTEST_HAS_STREAM_REDIRECTION
+//                            - Define it to 1/0 to indicate whether the
+//                              platform supports I/O stream redirection using
+//                              dup() and dup2().
+//   GTEST_USE_OWN_TR1_TUPLE  - Define it to 1/0 to indicate whether Google
+//                              Test's own tr1 tuple implementation should be
+//                              used.  Unused when the user sets
+//                              GTEST_HAS_TR1_TUPLE to 0.
+//   GTEST_LANG_CXX11         - Define it to 1/0 to indicate that Google Test
+//                              is building in C++11/C++98 mode.
+//   GTEST_LINKED_AS_SHARED_LIBRARY
+//                            - Define to 1 when compiling tests that use
+//                              Google Test as a shared library (known as
+//                              DLL on Windows).
+//   GTEST_CREATE_SHARED_LIBRARY
+//                            - Define to 1 when compiling Google Test itself
+//                              as a shared library.
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+//   GTEST_OS_AIX      - IBM AIX
+//   GTEST_OS_CYGWIN   - Cygwin
+//   GTEST_OS_HPUX     - HP-UX
+//   GTEST_OS_LINUX    - Linux
+//     GTEST_OS_LINUX_ANDROID - Google Android
+//   GTEST_OS_MAC      - Mac OS X
+//     GTEST_OS_IOS    - iOS
+//       GTEST_OS_IOS_SIMULATOR - iOS simulator
+//   GTEST_OS_NACL     - Google Native Client (NaCl)
+//   GTEST_OS_OPENBSD  - OpenBSD
+//   GTEST_OS_QNX      - QNX
+//   GTEST_OS_SOLARIS  - Sun Solaris
+//   GTEST_OS_SYMBIAN  - Symbian
+//   GTEST_OS_WINDOWS  - Windows (Desktop, MinGW, or Mobile)
+//     GTEST_OS_WINDOWS_DESKTOP  - Windows Desktop
+//     GTEST_OS_WINDOWS_MINGW    - MinGW
+//     GTEST_OS_WINDOWS_MOBILE   - Windows Mobile
+//   GTEST_OS_ZOS      - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support.  Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable.  If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+//   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized
+//                            tests)
+//   GTEST_HAS_DEATH_TEST   - death tests
+//   GTEST_HAS_PARAM_TEST   - value-parameterized tests
+//   GTEST_HAS_TYPED_TEST   - typed tests
+//   GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+//   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used. Do not confuse with
+//                            GTEST_HAS_POSIX_RE (see above) which users can
+//                            define themselves.
+//   GTEST_USES_SIMPLE_RE   - our own simple regex is used;
+//                            the above two are mutually exclusive.
+//   GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+//
+// Macros for basic C++ coding:
+//   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+//   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a
+//                              variable don't have to be used.
+//   GTEST_DISALLOW_ASSIGN_   - disables operator=.
+//   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+//   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
+//
+// Synchronization:
+//   Mutex, MutexLock, ThreadLocal, GetThreadCount()
+//                  - synchronization primitives.
+//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+//                         synchronization primitives have real implementations
+//                         and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+//   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.
+//   IteratorTraits - partial implementation of std::iterator_traits, which
+//                    is not available in libCstd when compiled with Sun C++.
+//
+// Smart pointers:
+//   scoped_ptr     - as in TR2.
+//
+// Regular expressions:
+//   RE             - a simple regular expression class using the POSIX
+//                    Extended Regular Expression syntax on UNIX-like
+//                    platforms, or a reduced regular exception syntax on
+//                    other platforms, including Windows.
+//
+// Logging:
+//   GTEST_LOG_()   - logs messages at the specified severity level.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+//   CaptureStdout()     - starts capturing stdout.
+//   GetCapturedStdout() - stops capturing stdout and returns the captured
+//                         string.
+//   CaptureStderr()     - starts capturing stderr.
+//   GetCapturedStderr() - stops capturing stderr and returns the captured
+//                         string.
+//
+// Integer types:
+//   TypeWithSize   - maps an integer to a int type.
+//   Int32, UInt32, Int64, UInt64, TimeInMillis
+//                  - integers of known sizes.
+//   BiggestInt     - the biggest signed integer type.
+//
+// Command-line utilities:
+//   GTEST_FLAG()       - references a flag.
+//   GTEST_DECLARE_*()  - declares a flag.
+//   GTEST_DEFINE_*()   - defines a flag.
+//   GetInjectableArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+//   GetEnv()             - gets the value of an environment variable.
+//   BoolFromGTestEnv()   - parses a bool environment variable.
+//   Int32FromGTestEnv()  - parses an Int32 environment variable.
+//   StringFromGTestEnv() - parses a string environment variable.
+
+#include <ctype.h>   // for isspace, etc
+#include <stddef.h>  // for ptrdiff_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif  // !_WIN32_WCE
+
+#if defined __APPLE__
+# include <AvailabilityMacros.h>
+# include <TargetConditionals.h>
+#endif
+
+#include <iostream>  // NOLINT
+#include <sstream>  // NOLINT
+#include <string>  // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif  // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+# define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+#  define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(__MINGW__) || defined(__MINGW32__)
+#  define GTEST_OS_WINDOWS_MINGW 1
+# else
+#  define GTEST_OS_WINDOWS_DESKTOP 1
+# endif  // _WIN32_WCE
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+# if TARGET_OS_IPHONE
+#  define GTEST_OS_IOS 1
+#  if TARGET_IPHONE_SIMULATOR
+#   define GTEST_OS_IOS_SIMULATOR 1
+#  endif
+# endif
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# if defined __ANDROID__
+#  define GTEST_OS_LINUX_ANDROID 1
+# endif
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#elif defined __OpenBSD__
+# define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+# define GTEST_OS_QNX 1
+#endif  // __CYGWIN__
+
+#ifndef GTEST_LANG_CXX11
+// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
+// -std={c,gnu}++{0x,11} is passed.  The C++11 standard specifies a
+// value for __cplusplus, and recent versions of clang, gcc, and
+// probably other compilers set that too in C++11 mode.
+# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
+// Compiling in at least C++11 mode.
+#  define GTEST_LANG_CXX11 1
+# else
+#  define GTEST_LANG_CXX11 0
+# endif
+#endif
+
+// Brings in definitions for functions used in the testing::internal::posix
+// namespace (read, write, close, chdir, isatty, stat). We do not currently
+// use them on Windows Mobile.
+#if !GTEST_OS_WINDOWS
+// This assumes that non-Windows OSes provide unistd.h. For OSes where this
+// is not the case, we need to include headers that provide the functions
+// mentioned above.
+# include <unistd.h>
+# include <strings.h>
+#elif !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+#endif
+
+#if GTEST_OS_LINUX_ANDROID
+// Used to define __ANDROID_API__ matching the target NDK API level.
+#  include <android/api-level.h>  // NOLINT
+#endif
+
+// Defines this to true iff Google Test can use POSIX regular expressions.
+#ifndef GTEST_HAS_POSIX_RE
+# if GTEST_OS_LINUX_ANDROID
+// On Android, <regex.h> is only available starting with Gingerbread.
+#  define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
+# else
+#  define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
+# endif
+#endif
+
+#if GTEST_HAS_POSIX_RE
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise.  We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+# include <regex.h>  // NOLINT
+
+# define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+// <regex.h> is not available on Windows.  Use our own simple regex
+// implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform.  Use our own
+// simple regex implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#endif  // GTEST_HAS_POSIX_RE
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+#  ifndef _HAS_EXCEPTIONS
+#   define _HAS_EXCEPTIONS 1
+#  endif  // _HAS_EXCEPTIONS
+#  define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions.  However, there is no compile-time way of
+// detecting whether they are enabled or not.  Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__HP_aCC)
+// Exception handling is in effect by default in HP aCC compiler. It has to
+// be turned of by +noeh compiler option if desired.
+#  define GTEST_HAS_EXCEPTIONS 1
+# else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+#  define GTEST_HAS_EXCEPTIONS 0
+# endif  // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif  // GTEST_HAS_EXCEPTIONS
+
+#if !defined(GTEST_HAS_STD_STRING)
+// Even though we don't use this macro any longer, we keep it in case
+// some clients still depend on it.
+# define GTEST_HAS_STD_STRING 1
+#elif !GTEST_HAS_STD_STRING
+// The user told us that ::std::string isn't available.
+# error "Google Test cannot be used where ::std::string isn't available."
+#endif  // !defined(GTEST_HAS_STD_STRING)
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+# define GTEST_HAS_GLOBAL_STRING 0
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
+//   is available.
+
+// Cygwin 1.7 and below doesn't support ::std::wstring.
+// Solaris' libc++ doesn't support it either.  Android has
+// no support for it at least as recent as Froyo (2.2).
+# define GTEST_HAS_STD_WSTRING \
+    (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+
+#endif  // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+# define GTEST_HAS_GLOBAL_WSTRING \
+    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+# ifdef _MSC_VER
+
+#  ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.
+#   define GTEST_HAS_RTTI 1
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+
+#  ifdef __GXX_RTTI
+// When building against STLport with the Android NDK and with
+// -frtti -fno-exceptions, the build fails at link time with undefined
+// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
+// so disable RTTI when detected.
+#   if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
+       !defined(__EXCEPTIONS)
+#    define GTEST_HAS_RTTI 0
+#   else
+#    define GTEST_HAS_RTTI 1
+#   endif  // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif  // __GXX_RTTI
+
+// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
+// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
+// first version with C++ support.
+# elif defined(__clang__)
+
+#  define GTEST_HAS_RTTI __has_feature(cxx_rtti)
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+#  ifdef __RTTI_ALL__
+#   define GTEST_HAS_RTTI 1
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif
+
+# else
+
+// For all other compilers, we assume RTTI is enabled.
+#  define GTEST_HAS_RTTI 1
+
+# endif  // _MSC_VER
+
+#endif  // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+# include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we assume pthreads support is
+// available on Linux and Mac.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
+    || GTEST_OS_QNX)
+#endif  // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+# include <pthread.h>  // NOLINT
+
+// For timespec and nanosleep, used below.
+# include <time.h>  // NOLINT
+#endif
+
+// Determines whether Google Test can use tr1/tuple.  You can define
+// this macro to 0 to prevent Google Test from using tuple (any
+// feature depending on tuple with be disabled in this mode).
+#ifndef GTEST_HAS_TR1_TUPLE
+# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
+// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
+#  define GTEST_HAS_TR1_TUPLE 0
+# else
+// The user didn't tell us not to do it, so we assume it's OK.
+#  define GTEST_HAS_TR1_TUPLE 1
+# endif
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Determines whether Google Test's own tr1 tuple implementation
+// should be used.
+#ifndef GTEST_USE_OWN_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// We use our own TR1 tuple if we aren't sure the user has an
+// implementation of it already.  At this time, libstdc++ 4.0.0+ and
+// MSVC 2010 are the only mainstream standard libraries that come
+// with a TR1 tuple implementation.  NVIDIA's CUDA NVCC compiler
+// pretends to be GCC by defining __GNUC__ and friends, but cannot
+// compile GCC's tuple implementation.  MSVC 2008 (9.0) provides TR1
+// tuple in a 323 MB Feature Pack download, which we cannot assume the
+// user has.  QNX's QCC compiler is a modified GCC but it doesn't
+// support TR1 tuple.  libc++ only provides std::tuple, in C++11 mode,
+// and it can be used with some compilers that define __GNUC__.
+# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
+      && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
+#  define GTEST_ENV_HAS_TR1_TUPLE_ 1
+# endif
+
+// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
+// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
+// can build with clang but need to use gcc4.2's libstdc++).
+# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
+#  define GTEST_ENV_HAS_STD_TUPLE_ 1
+# endif
+
+# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
+#  define GTEST_USE_OWN_TR1_TUPLE 0
+# else
+#  define GTEST_USE_OWN_TR1_TUPLE 1
+# endif
+
+#endif  // GTEST_USE_OWN_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+# if GTEST_USE_OWN_TR1_TUPLE
+// This file was GENERATED by command:
+//     pump.py gtest-tuple.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility>  // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined).  This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+    template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
+   private:
+#endif
+
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
+    void, void, void>
+#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
+    void, void, void>
+#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
+    void, void, void>
+#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
+    void, void, void>
+#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
+    void, void, void>
+#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
+    void, void, void>
+#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    void, void, void>
+#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, void, void>
+#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, T##8, void>
+#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, T##8, T##9>
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+#define GTEST_0_TYPENAMES_(T)
+#define GTEST_1_TYPENAMES_(T) typename T##0
+#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
+#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
+#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3
+#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4
+#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5
+#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6
+#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
+#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, \
+    typename T##7, typename T##8
+#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, \
+    typename T##7, typename T##8, typename T##9
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior.  We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+    typename T3 = void, typename T4 = void, typename T5 = void,
+    typename T6 = void, typename T7 = void, typename T8 = void,
+    typename T9 = void>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; };  // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&.  This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; };  // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>.  kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
+  typedef T0 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
+  typedef T1 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
+  typedef T2 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
+  typedef T3 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
+  typedef T4 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
+  typedef T5 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
+  typedef T6 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
+  typedef T7 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
+  typedef T8 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
+  typedef T9 type;
+};
+
+}  // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+  tuple() {}
+  tuple(const tuple& /* t */)  {}
+  tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+class GTEST_1_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
+
+  tuple(const tuple& t) : f0_(t.f0_) {}
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    return *this;
+  }
+
+  T0 f0_;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+class GTEST_2_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
+      f1_(f1) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
+  template <typename U0, typename U1>
+  tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+  template <typename U0, typename U1>
+  tuple& operator=(const ::std::pair<U0, U1>& p) {
+    f0_ = p.first;
+    f1_ = p.second;
+    return *this;
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+class GTEST_3_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+class GTEST_4_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+class GTEST_5_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
+      GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_) {}
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+class GTEST_6_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_) {}
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+class GTEST_7_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+class GTEST_8_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
+      GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5), f6_(f6), f7_(f7) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+class GTEST_9_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+      GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    f8_ = t.f8_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+  T8 f8_;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+class tuple {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
+      f9_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+      GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
+      f9_(t.f9_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    f8_ = t.f8_;
+    f9_ = t.f9_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+  T8 f8_;
+  T9 f9_;
+};
+
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple().  And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+template <GTEST_1_TYPENAMES_(T)>
+inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
+  return GTEST_1_TUPLE_(T)(f0);
+}
+
+template <GTEST_2_TYPENAMES_(T)>
+inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
+  return GTEST_2_TUPLE_(T)(f0, f1);
+}
+
+template <GTEST_3_TYPENAMES_(T)>
+inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
+  return GTEST_3_TUPLE_(T)(f0, f1, f2);
+}
+
+template <GTEST_4_TYPENAMES_(T)>
+inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3) {
+  return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
+}
+
+template <GTEST_5_TYPENAMES_(T)>
+inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4) {
+  return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
+}
+
+template <GTEST_6_TYPENAMES_(T)>
+inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5) {
+  return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
+}
+
+template <GTEST_7_TYPENAMES_(T)>
+inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
+  return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
+}
+
+template <GTEST_8_TYPENAMES_(T)>
+inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
+  return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
+}
+
+template <GTEST_9_TYPENAMES_(T)>
+inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+    const T8& f8) {
+  return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
+}
+
+template <GTEST_10_TYPENAMES_(T)>
+inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+    const T8& f8, const T9& f9) {
+  return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
+}
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+template <GTEST_0_TYPENAMES_(T)>
+struct tuple_size<GTEST_0_TUPLE_(T) > {
+  static const int value = 0;
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+struct tuple_size<GTEST_1_TUPLE_(T) > {
+  static const int value = 1;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+struct tuple_size<GTEST_2_TUPLE_(T) > {
+  static const int value = 2;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+struct tuple_size<GTEST_3_TUPLE_(T) > {
+  static const int value = 3;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+struct tuple_size<GTEST_4_TUPLE_(T) > {
+  static const int value = 4;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+struct tuple_size<GTEST_5_TUPLE_(T) > {
+  static const int value = 5;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+struct tuple_size<GTEST_6_TUPLE_(T) > {
+  static const int value = 6;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+struct tuple_size<GTEST_7_TUPLE_(T) > {
+  static const int value = 7;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+struct tuple_size<GTEST_8_TUPLE_(T) > {
+  static const int value = 8;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+struct tuple_size<GTEST_9_TUPLE_(T) > {
+  static const int value = 9;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct tuple_size<GTEST_10_TUPLE_(T) > {
+  static const int value = 10;
+};
+
+template <int k, class Tuple>
+struct tuple_element {
+  typedef typename gtest_internal::TupleElement<
+      k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+template <>
+class Get<0> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+  Field(Tuple& t) { return t.f0_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+  ConstField(const Tuple& t) { return t.f0_; }
+};
+
+template <>
+class Get<1> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+  Field(Tuple& t) { return t.f1_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+  ConstField(const Tuple& t) { return t.f1_; }
+};
+
+template <>
+class Get<2> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+  Field(Tuple& t) { return t.f2_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+  ConstField(const Tuple& t) { return t.f2_; }
+};
+
+template <>
+class Get<3> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+  Field(Tuple& t) { return t.f3_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+  ConstField(const Tuple& t) { return t.f3_; }
+};
+
+template <>
+class Get<4> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+  Field(Tuple& t) { return t.f4_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+  ConstField(const Tuple& t) { return t.f4_; }
+};
+
+template <>
+class Get<5> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+  Field(Tuple& t) { return t.f5_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+  ConstField(const Tuple& t) { return t.f5_; }
+};
+
+template <>
+class Get<6> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+  Field(Tuple& t) { return t.f6_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+  ConstField(const Tuple& t) { return t.f6_; }
+};
+
+template <>
+class Get<7> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+  Field(Tuple& t) { return t.f7_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+  ConstField(const Tuple& t) { return t.f7_; }
+};
+
+template <>
+class Get<8> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+  Field(Tuple& t) { return t.f8_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+  ConstField(const Tuple& t) { return t.f8_; }
+};
+
+template <>
+class Get<9> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+  Field(Tuple& t) { return t.f9_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+  ConstField(const Tuple& t) { return t.f9_; }
+};
+
+}  // namespace gtest_internal
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(GTEST_10_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k,  GTEST_10_TUPLE_(T)))
+get(const GTEST_10_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+    return true;
+  }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+    return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+        ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+  }
+};
+
+}  // namespace gtest_internal
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator==(const GTEST_10_TUPLE_(T)& t,
+                       const GTEST_10_TUPLE_(U)& u) {
+  return gtest_internal::SameSizeTuplePrefixComparator<
+      tuple_size<GTEST_10_TUPLE_(T) >::value,
+      tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
+}
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
+                       const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+}  // namespace tr1
+}  // namespace std
+
+#undef GTEST_0_TUPLE_
+#undef GTEST_1_TUPLE_
+#undef GTEST_2_TUPLE_
+#undef GTEST_3_TUPLE_
+#undef GTEST_4_TUPLE_
+#undef GTEST_5_TUPLE_
+#undef GTEST_6_TUPLE_
+#undef GTEST_7_TUPLE_
+#undef GTEST_8_TUPLE_
+#undef GTEST_9_TUPLE_
+#undef GTEST_10_TUPLE_
+
+#undef GTEST_0_TYPENAMES_
+#undef GTEST_1_TYPENAMES_
+#undef GTEST_2_TYPENAMES_
+#undef GTEST_3_TYPENAMES_
+#undef GTEST_4_TYPENAMES_
+#undef GTEST_5_TYPENAMES_
+#undef GTEST_6_TYPENAMES_
+#undef GTEST_7_TYPENAMES_
+#undef GTEST_8_TYPENAMES_
+#undef GTEST_9_TYPENAMES_
+#undef GTEST_10_TYPENAMES_
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+# elif GTEST_ENV_HAS_STD_TUPLE_
+#  include <tuple>
+// C++11 puts its tuple into the ::std namespace rather than
+// ::std::tr1.  gtest expects tuple to live in ::std::tr1, so put it there.
+// This causes undefined behavior, but supported compilers react in
+// the way we intend.
+namespace std {
+namespace tr1 {
+using ::std::get;
+using ::std::make_tuple;
+using ::std::tuple;
+using ::std::tuple_element;
+using ::std::tuple_size;
+}
+}
+
+# elif GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+#  ifdef BOOST_HAS_TR1_TUPLE
+#   undef BOOST_HAS_TR1_TUPLE
+#  endif  // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+#  define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+#  include <tuple>
+
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+#  if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled.  _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>.  Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+#   define _TR1_FUNCTIONAL 1
+#   include <tr1/tuple>
+#   undef _TR1_FUNCTIONAL  // Allows the user to #include
+                        // <tr1/functional> if he chooses to.
+#  else
+#   include <tr1/tuple>  // NOLINT
+#  endif  // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+# else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+#  include <tuple>  // NOLINT
+# endif  // GTEST_USE_OWN_TR1_TUPLE
+
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+# if GTEST_OS_LINUX && !defined(__ia64__)
+#  if GTEST_OS_LINUX_ANDROID
+// On Android, clone() is only available on ARM starting with Gingerbread.
+#    if defined(__arm__) && __ANDROID_API__ >= 9
+#     define GTEST_HAS_CLONE 1
+#    else
+#     define GTEST_HAS_CLONE 0
+#    endif
+#  else
+#   define GTEST_HAS_CLONE 1
+#  endif
+# else
+#  define GTEST_HAS_CLONE 0
+# endif  // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif  // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#ifndef GTEST_HAS_STREAM_REDIRECTION
+// By default, we assume that stream redirection is supported on all
+// platforms except known mobile ones.
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+#  define GTEST_HAS_STREAM_REDIRECTION 0
+# else
+#  define GTEST_HAS_STREAM_REDIRECTION 1
+# endif  // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier as
+// abort() in a VC 7.1 application compiled as GUI in debug config
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+     (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
+     (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
+     GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
+     GTEST_OS_OPENBSD || GTEST_OS_QNX)
+# define GTEST_HAS_DEATH_TEST 1
+# include <vector>  // NOLINT
+#endif
+
+// We don't support MSVC 7.1 with exceptions disabled now.  Therefore
+// all the compilers we care about are adequate for supporting
+// value-parameterized tests.
+#define GTEST_HAS_PARAM_TEST 1
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+    defined(__IBMCPP__) || defined(__HP_aCC)
+# define GTEST_HAS_TYPED_TEST 1
+# define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled.  The implementation doesn't
+// work on Sun Studio since it doesn't understand templated conversion
+// operators.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
+# define GTEST_HAS_COMBINE 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+    (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX
+# define GTEST_CAN_STREAM_RESULTS_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding.  This leads to problems with code like:
+//
+//   if (gate)
+//     ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default:  // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used.  This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor.  Example:
+//
+//   struct Foo {
+//     Foo() { ... }
+//   } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+# define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type)\
+  void operator=(type const &)
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+  type(type const &);\
+  GTEST_DISALLOW_ASSIGN_(type)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro.  The macro should be used on function declarations
+// following the argument list:
+//
+//   Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+# define GTEST_MUST_USE_RESULT_
+#endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling.  This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+#  define GTEST_HAS_SEH 1
+# else
+// Assume no SEH.
+#  define GTEST_HAS_SEH 0
+# endif
+
+#endif  // GTEST_HAS_SEH
+
+#ifdef _MSC_VER
+
+# if GTEST_LINKED_AS_SHARED_LIBRARY
+#  define GTEST_API_ __declspec(dllimport)
+# elif GTEST_CREATE_SHARED_LIBRARY
+#  define GTEST_API_ __declspec(dllexport)
+# endif
+
+#endif  // _MSC_VER
+
+#ifndef GTEST_API_
+# define GTEST_API_
+#endif
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+# define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+# define GTEST_NO_INLINE_
+#endif
+
+// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
+#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
+# define GTEST_HAS_CXXABI_H_ 1
+#else
+# define GTEST_HAS_CXXABI_H_ 0
+#endif
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+// A secret type that Google Test users don't know about.  It has no
+// definition on purpose.  Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+//                         content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define GTEST_COMPILE_ASSERT_(expr, msg) \
+  typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
+      msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
+
+// Implementation details of GTEST_COMPILE_ASSERT_:
+//
+// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//    #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
+//                                      // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     GTEST_COMPILE_ASSERT_(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
+//
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+#if GTEST_HAS_GLOBAL_STRING
+typedef ::string string;
+#else
+typedef ::std::string string;
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+typedef ::wstring wstring;
+#elif GTEST_HAS_STD_WSTRING
+typedef ::std::wstring wstring;
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// A helper for suppressing warnings on constant condition.  It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+  typedef T element_type;
+
+  explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+  ~scoped_ptr() { reset(); }
+
+  T& operator*() const { return *ptr_; }
+  T* operator->() const { return ptr_; }
+  T* get() const { return ptr_; }
+
+  T* release() {
+    T* const ptr = ptr_;
+    ptr_ = NULL;
+    return ptr;
+  }
+
+  void reset(T* p = NULL) {
+    if (p != ptr_) {
+      if (IsTrue(sizeof(T) > 0)) {  // Makes sure T is a complete type.
+        delete ptr_;
+      }
+      ptr_ = p;
+    }
+  }
+
+ private:
+  T* ptr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>.  It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE {
+ public:
+  // A copy constructor is required by the Standard to initialize object
+  // references from r-values.
+  RE(const RE& other) { Init(other.pattern()); }
+
+  // Constructs an RE from a string.
+  RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT
+
+#if GTEST_HAS_GLOBAL_STRING
+
+  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  RE(const char* regex) { Init(regex); }  // NOLINT
+  ~RE();
+
+  // Returns the string representation of the regex.
+  const char* pattern() const { return pattern_; }
+
+  // FullMatch(str, re) returns true iff regular expression re matches
+  // the entire str.
+  // PartialMatch(str, re) returns true iff regular expression re
+  // matches a substring of str (including str itself).
+  //
+  // TODO(wan@google.com): make FullMatch() and PartialMatch() work
+  // when str contains NUL characters.
+  static bool FullMatch(const ::std::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::std::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+
+#if GTEST_HAS_GLOBAL_STRING
+
+  static bool FullMatch(const ::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  static bool FullMatch(const char* str, const RE& re);
+  static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+  void Init(const char* regex);
+
+  // We use a const char* instead of an std::string, as Google Test used to be
+  // used where std::string is not available.  TODO(wan@google.com): change to
+  // std::string.
+  const char* pattern_;
+  bool is_valid_;
+
+#if GTEST_USES_POSIX_RE
+
+  regex_t full_regex_;     // For FullMatch().
+  regex_t partial_regex_;  // For PartialMatch().
+
+#else  // GTEST_USES_SIMPLE_RE
+
+  const char* full_pattern_;  // For FullMatch();
+
+#endif
+
+  GTEST_DISALLOW_ASSIGN_(RE);
+};
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
+                                                               int line);
+
+// Defines logging utilities:
+//   GTEST_LOG_(severity) - logs messages at the specified severity level. The
+//                          message itself is streamed into the macro.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+  GTEST_INFO,
+  GTEST_WARNING,
+  GTEST_ERROR,
+  GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog {
+ public:
+  GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+  // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+  ~GTestLog();
+
+  ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+  const GTestLogSeverity severity_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#define GTEST_LOG_(severity) \
+    ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+                                  __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+//  Synopsys:
+//    GTEST_CHECK_(boolean_condition);
+//     or
+//    GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+//    This checks the condition and if the condition is not satisfied
+//    it prints message about the condition violation, including the
+//    condition itself, plus additional message streamed into it, if any,
+//    and then it aborts the program. It aborts the program irrespective of
+//    whether it is built in the debug mode or not.
+#define GTEST_CHECK_(condition) \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+    if (::testing::internal::IsTrue(condition)) \
+      ; \
+    else \
+      GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success).  Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+  if (const int gtest_error = (posix_call)) \
+    GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+                      << gtest_error
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Use ImplicitCast_ as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*).  When you use ImplicitCast_, the compiler checks that
+// the cast is safe.  Such explicit ImplicitCast_s are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+//   ImplicitCast_<ToType>(expr)
+//
+// ImplicitCast_ would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., implicit_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To>
+inline To ImplicitCast_(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., down_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To, typename From>  // use like this: DownCast_<T*>(foo);
+inline To DownCast_(From* f) {  // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    const To to = NULL;
+    ::testing::internal::ImplicitCast_<From*>(to);
+  }
+
+#if GTEST_HAS_RTTI
+  // RTTI: debug mode only!
+  GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+  return static_cast<To>(f);
+}
+
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+  GTEST_CHECK_(typeid(*base) == typeid(Derived));
+  return dynamic_cast<Derived*>(base);  // NOLINT
+#else
+  return static_cast<Derived*>(base);  // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Defines the stderr capturer:
+//   CaptureStdout     - starts capturing stdout.
+//   GetCapturedStdout - stops capturing stdout and returns the captured string.
+//   CaptureStderr     - starts capturing stderr.
+//   GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ std::string GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ std::string GetCapturedStderr();
+
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+
+#if GTEST_HAS_DEATH_TEST
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs();
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
+                             new_argvs);
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+extern ::std::vector<testing::internal::string> g_argvs;
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+#if GTEST_HAS_PTHREAD
+
+// Sleeps for (roughly) n milli-seconds.  This function is only for
+// testing Google Test's own constructs.  Don't use it in user tests,
+// either directly or indirectly.
+inline void SleepMilliseconds(int n) {
+  const timespec time = {
+    0,                  // 0 seconds.
+    n * 1000L * 1000L,  // And n ms.
+  };
+  nanosleep(&time, NULL);
+}
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified.  Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification {
+ public:
+  Notification() : notified_(false) {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+  }
+  ~Notification() {
+    pthread_mutex_destroy(&mutex_);
+  }
+
+  // Notifies all threads created with this notification to start. Must
+  // be called from the controller thread.
+  void Notify() {
+    pthread_mutex_lock(&mutex_);
+    notified_ = true;
+    pthread_mutex_unlock(&mutex_);
+  }
+
+  // Blocks until the controller thread notifies. Must be called from a test
+  // thread.
+  void WaitForNotification() {
+    for (;;) {
+      pthread_mutex_lock(&mutex_);
+      const bool notified = notified_;
+      pthread_mutex_unlock(&mutex_);
+      if (notified)
+        break;
+      SleepMilliseconds(10);
+    }
+  }
+
+ private:
+  pthread_mutex_t mutex_;
+  bool notified_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase {
+ public:
+  virtual ~ThreadWithParamBase() {}
+  virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical.  Some compilers (for
+// example, SunStudio) treat them as different types.  Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
+  static_cast<ThreadWithParamBase*>(thread)->Run();
+  return NULL;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+//   void ThreadFunc(int param) { /* Do things with param */ }
+//   Notification thread_can_start;
+//   ...
+//   // The thread_can_start parameter is optional; you can supply NULL.
+//   ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+//   thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+  typedef void (*UserThreadFunc)(T);
+
+  ThreadWithParam(
+      UserThreadFunc func, T param, Notification* thread_can_start)
+      : func_(func),
+        param_(param),
+        thread_can_start_(thread_can_start),
+        finished_(false) {
+    ThreadWithParamBase* const base = this;
+    // The thread can be created only after all fields except thread_
+    // have been initialized.
+    GTEST_CHECK_POSIX_SUCCESS_(
+        pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+  }
+  ~ThreadWithParam() { Join(); }
+
+  void Join() {
+    if (!finished_) {
+      GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+      finished_ = true;
+    }
+  }
+
+  virtual void Run() {
+    if (thread_can_start_ != NULL)
+      thread_can_start_->WaitForNotification();
+    func_(param_);
+  }
+
+ private:
+  const UserThreadFunc func_;  // User-supplied thread function.
+  const T param_;  // User-supplied parameter to the thread function.
+  // When non-NULL, used to block execution until the controller thread
+  // notifies.
+  Notification* const thread_can_start_;
+  bool finished_;  // true iff we know that the thread function has finished.
+  pthread_t thread_;  // The native thread object.
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms. They
+// are used in conjunction with class MutexLock:
+//
+//   Mutex mutex;
+//   ...
+//   MutexLock lock(&mutex);  // Acquires the mutex and releases it at the end
+//                            // of the current scope.
+//
+// MutexBase implements behavior for both statically and dynamically
+// allocated mutexes.  Do not use MutexBase directly.  Instead, write
+// the following to define a static mutex:
+//
+//   GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//
+// You can forward declare a static mutex like this:
+//
+//   GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// To create a dynamic mutex, just define an object of type Mutex.
+class MutexBase {
+ public:
+  // Acquires this mutex.
+  void Lock() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+    owner_ = pthread_self();
+    has_owner_ = true;
+  }
+
+  // Releases this mutex.
+  void Unlock() {
+    // Since the lock is being released the owner_ field should no longer be
+    // considered valid. We don't protect writing to has_owner_ here, as it's
+    // the caller's responsibility to ensure that the current thread holds the
+    // mutex when this is called.
+    has_owner_ = false;
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+  }
+
+  // Does nothing if the current thread holds the mutex. Otherwise, crashes
+  // with high probability.
+  void AssertHeld() const {
+    GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
+        << "The current thread is not holding the mutex @" << this;
+  }
+
+  // A static mutex may be used before main() is entered.  It may even
+  // be used before the dynamic initialization stage.  Therefore we
+  // must be able to initialize a static mutex object at link time.
+  // This means MutexBase has to be a POD and its member variables
+  // have to be public.
+ public:
+  pthread_mutex_t mutex_;  // The underlying pthread mutex.
+  // has_owner_ indicates whether the owner_ field below contains a valid thread
+  // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
+  // accesses to the owner_ field should be protected by a check of this field.
+  // An alternative might be to memset() owner_ to all zeros, but there's no
+  // guarantee that a zero'd pthread_t is necessarily invalid or even different
+  // from pthread_self().
+  bool has_owner_;
+  pthread_t owner_;  // The thread holding the mutex.
+};
+
+// Forward-declares a static mutex.
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+    extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+// The initialization list here does not explicitly initialize each field,
+// instead relying on default initialization for the unspecified fields. In
+// particular, the owner_ field (a pthread_t) is not explicitly initialized.
+// This allows initialization to work whether pthread_t is a scalar or struct.
+// The flag -Wmissing-field-initializers must not be specified for this to work.
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+    ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase {
+ public:
+  Mutex() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+    has_owner_ = false;
+  }
+  ~Mutex() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+  }
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms.  Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(MutexBase* mutex)
+      : mutex_(mutex) { mutex_->Lock(); }
+
+  ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+  MutexBase* const mutex_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage.  Therefore it cannot be templatized to access
+// ThreadLocal<T>.  Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase {
+ public:
+  virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
+  delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+//
+//   // Thread 1
+//   ThreadLocal<int> tl(100);  // 100 is the default value for each thread.
+//
+//   // Thread 2
+//   tl.set(150);  // Changes the value for thread 2 only.
+//   EXPECT_EQ(150, tl.get());
+//
+//   // Thread 1
+//   EXPECT_EQ(100, tl.get());  // In thread 1, tl has the original value.
+//   tl.set(200);
+//   EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// An object managed for a thread by a ThreadLocal instance is deleted
+// when the thread exits.  Or, if the ThreadLocal instance dies in
+// that thread, when the ThreadLocal dies.  It's the user's
+// responsibility to ensure that all other threads using a ThreadLocal
+// have exited when it dies, or the per-thread objects for those
+// threads will not be deleted.
+//
+// Google Test only uses global ThreadLocal objects.  That means they
+// will die after main() has returned.  Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal {
+ public:
+  ThreadLocal() : key_(CreateKey()),
+                  default_() {}
+  explicit ThreadLocal(const T& value) : key_(CreateKey()),
+                                         default_(value) {}
+
+  ~ThreadLocal() {
+    // Destroys the managed object for the current thread, if any.
+    DeleteThreadLocalValue(pthread_getspecific(key_));
+
+    // Releases resources associated with the key.  This will *not*
+    // delete managed objects for other threads.
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+  }
+
+  T* pointer() { return GetOrCreateValue(); }
+  const T* pointer() const { return GetOrCreateValue(); }
+  const T& get() const { return *pointer(); }
+  void set(const T& value) { *pointer() = value; }
+
+ private:
+  // Holds a value of type T.
+  class ValueHolder : public ThreadLocalValueHolderBase {
+   public:
+    explicit ValueHolder(const T& value) : value_(value) {}
+
+    T* pointer() { return &value_; }
+
+   private:
+    T value_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+  };
+
+  static pthread_key_t CreateKey() {
+    pthread_key_t key;
+    // When a thread exits, DeleteThreadLocalValue() will be called on
+    // the object managed for that thread.
+    GTEST_CHECK_POSIX_SUCCESS_(
+        pthread_key_create(&key, &DeleteThreadLocalValue));
+    return key;
+  }
+
+  T* GetOrCreateValue() const {
+    ThreadLocalValueHolderBase* const holder =
+        static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+    if (holder != NULL) {
+      return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+    }
+
+    ValueHolder* const new_holder = new ValueHolder(default_);
+    ThreadLocalValueHolderBase* const holder_base = new_holder;
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+    return new_holder->pointer();
+  }
+
+  // A key pthreads uses for looking up per-thread values.
+  const pthread_key_t key_;
+  const T default_;  // The default value for each thread.
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# define GTEST_IS_THREADSAFE 1
+
+#else  // GTEST_HAS_PTHREAD
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable).  Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+  Mutex() {}
+  void Lock() {}
+  void Unlock() {}
+  void AssertHeld() const {}
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+  extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(Mutex*) {}  // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+  ThreadLocal() : value_() {}
+  explicit ThreadLocal(const T& value) : value_(value) {}
+  T* pointer() { return &value_; }
+  const T* pointer() const { return &value_; }
+  const T& get() const { return value_; }
+  void set(const T& value) { value_ = value; }
+ private:
+  T value_;
+};
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+# define GTEST_IS_THREADSAFE 0
+
+#endif  // GTEST_HAS_PTHREAD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler and generates a warning in Sun Studio.  The Nokia Symbian
+// and the IBM XL C/C++ compiler try to instantiate a copy constructor
+// for objects passed through ellipsis (...), failing for uncopyable
+// objects.  We define this to ensure that only POD is passed through
+// ellipsis on these systems.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_ELLIPSIS_NEEDS_POD_ 1
+#else
+# define GTEST_CAN_COMPARE_NULL 1
+#endif
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template.  These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+# define GTEST_NEEDS_IS_POINTER_ 1
+#endif
+
+template <bool bool_value>
+struct bool_constant {
+  typedef bool_constant<bool_value> type;
+  static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+template <typename Iterator>
+struct IteratorTraits {
+  typedef typename Iterator::value_type value_type;
+};
+
+template <typename T>
+struct IteratorTraits<T*> {
+  typedef T value_type;
+};
+
+template <typename T>
+struct IteratorTraits<const T*> {
+  typedef T value_type;
+};
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_SEP_ "\\"
+# define GTEST_HAS_ALT_PATH_SEP_ 1
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+# define GTEST_PATH_SEP_ "/"
+# define GTEST_HAS_ALT_PATH_SEP_ 0
+typedef long long BiggestInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+
+// Utilities for char.
+
+// isspace(int ch) and friends accept an unsigned char or EOF.  char
+// may be signed, depending on the compiler (or compiler flags).
+// Therefore we need to cast a char to unsigned char before calling
+// isspace(), etc.
+
+inline bool IsAlpha(char ch) {
+  return isalpha(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch) {
+  return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch) {
+  return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch) {
+  return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch) {
+  return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch) {
+  return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch) {
+  return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(wchar_t ch) {
+  const unsigned char low_byte = static_cast<unsigned char>(ch);
+  return ch == low_byte && isxdigit(low_byte) != 0;
+}
+
+inline char ToLower(char ch) {
+  return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch) {
+  return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions.  These wrappers hide the differences between
+// Windows/MSVC and POSIX systems.  Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+# ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+# else  // !__BORLANDC__
+#  if GTEST_OS_WINDOWS_MOBILE
+inline int IsATTY(int /* fd */) { return 0; }
+#  else
+inline int IsATTY(int fd) { return _isatty(fd); }
+#  endif  // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+# endif  // __BORLANDC__
+
+# if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+# else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+  return (_S_IFDIR & st.st_mode) != 0;
+}
+# endif  // GTEST_OS_WINDOWS_MOBILE
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif  // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+# pragma warning(push)
+# pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n) {
+  return strncpy(dest, src, n);
+}
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+  return fopen(path, mode);
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+  return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count) {
+  return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+  return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name) {
+#if GTEST_OS_WINDOWS_MOBILE
+  // We are on Windows CE, which has no environment variables.
+  return NULL;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+  // Environment variables which we programmatically clear will be set to the
+  // empty string rather than unset (NULL).  Handle that case.
+  const char* const env = getenv(name);
+  return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+  return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop)  // Restores the warning state.
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+}  // namespace posix
+
+// MSVC "deprecates" snprintf and issues warnings wherever it is used.  In
+// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
+// MSVC-based platforms.  We map the GTEST_SNPRINTF_ macro to the appropriate
+// function in order to achieve that.  We use macro definition here because
+// snprintf is a variadic function.
+#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+// MSVC 2005 and above support variadic macros.
+# define GTEST_SNPRINTF_(buffer, size, format, ...) \
+     _snprintf_s(buffer, size, size, format, __VA_ARGS__)
+#elif defined(_MSC_VER)
+// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
+// complain about _snprintf.
+# define GTEST_SNPRINTF_ _snprintf
+#else
+# define GTEST_SNPRINTF_ snprintf
+#endif
+
+// The maximum number a BiggestInt can represent.  This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type.  It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+//   TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs.  Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+  // This prevents the user from using TypeWithSize<N> with incorrect
+  // values of N.
+  typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+  // unsigned int has size 4 in both gcc and MSVC.
+  //
+  // As base/basictypes.h doesn't compile on Windows, we cannot use
+  // uint32, uint64, and etc here.
+  typedef int Int;
+  typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#if GTEST_OS_WINDOWS
+  typedef __int64 Int;
+  typedef unsigned __int64 UInt;
+#else
+  typedef long long Int;  // NOLINT
+  typedef unsigned long long UInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+    GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+    GTEST_API_ extern ::std::string GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+    GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+    GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+    GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
+
+// Thread annotations
+#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+#define GTEST_LOCK_EXCLUDED_(locks)
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+#if GTEST_OS_LINUX
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+
+
+// Ensures that there is at least one operator<< in the global namespace.
+// See Message& operator<<(...) below for why.
+void operator<<(const testing::internal::Secret&, int);
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+//   1. You stream a bunch of values to a Message object.
+//      It will remember the text in a stringstream.
+//   2. Then you stream the Message object to an ostream.
+//      This causes the text in the Message to be streamed
+//      to the ostream.
+//
+// For example;
+//
+//   testing::Message foo;
+//   foo << 1 << " != " << 2;
+//   std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from.  In particular, its
+// destructor is not virtual.
+//
+// Note that stringstream behaves differently in gcc and in MSVC.  You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do).  The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message {
+ private:
+  // The type of basic IO manipulators (endl, ends, and flush) for
+  // narrow streams.
+  typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+  // Constructs an empty Message.
+  Message();
+
+  // Copy constructor.
+  Message(const Message& msg) : ss_(new ::std::stringstream) {  // NOLINT
+    *ss_ << msg.GetString();
+  }
+
+  // Constructs a Message from a C-string.
+  explicit Message(const char* str) : ss_(new ::std::stringstream) {
+    *ss_ << str;
+  }
+
+#if GTEST_OS_SYMBIAN
+  // Streams a value (either a pointer or not) to this object.
+  template <typename T>
+  inline Message& operator <<(const T& value) {
+    StreamHelper(typename internal::is_pointer<T>::type(), value);
+    return *this;
+  }
+#else
+  // Streams a non-pointer value to this object.
+  template <typename T>
+  inline Message& operator <<(const T& val) {
+    // Some libraries overload << for STL containers.  These
+    // overloads are defined in the global namespace instead of ::std.
+    //
+    // C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+    // overloads are visible in either the std namespace or the global
+    // namespace, but not other namespaces, including the testing
+    // namespace which Google Test's Message class is in.
+    //
+    // To allow STL containers (and other types that has a << operator
+    // defined in the global namespace) to be used in Google Test
+    // assertions, testing::Message must access the custom << operator
+    // from the global namespace.  With this using declaration,
+    // overloads of << defined in the global namespace and those
+    // visible via Koenig lookup are both exposed in this function.
+    using ::operator <<;
+    *ss_ << val;
+    return *this;
+  }
+
+  // Streams a pointer value to this object.
+  //
+  // This function is an overload of the previous one.  When you
+  // stream a pointer to a Message, this definition will be used as it
+  // is more specialized.  (The C++ Standard, section
+  // [temp.func.order].)  If you stream a non-pointer, then the
+  // previous definition will be used.
+  //
+  // The reason for this overload is that streaming a NULL pointer to
+  // ostream is undefined behavior.  Depending on the compiler, you
+  // may get "0", "(nil)", "(null)", or an access violation.  To
+  // ensure consistent result across compilers, we always treat NULL
+  // as "(null)".
+  template <typename T>
+  inline Message& operator <<(T* const& pointer) {  // NOLINT
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      *ss_ << pointer;
+    }
+    return *this;
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // Since the basic IO manipulators are overloaded for both narrow
+  // and wide streams, we have to provide this specialized definition
+  // of operator <<, even though its body is the same as the
+  // templatized version above.  Without this definition, streaming
+  // endl or other basic IO manipulators to Message will confuse the
+  // compiler.
+  Message& operator <<(BasicNarrowIoManip val) {
+    *ss_ << val;
+    return *this;
+  }
+
+  // Instead of 1/0, we want to see true/false for bool values.
+  Message& operator <<(bool b) {
+    return *this << (b ? "true" : "false");
+  }
+
+  // These two overloads allow streaming a wide C string to a Message
+  // using the UTF-8 encoding.
+  Message& operator <<(const wchar_t* wide_c_str);
+  Message& operator <<(wchar_t* wide_c_str);
+
+#if GTEST_HAS_STD_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::std::wstring& wstr);
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::wstring& wstr);
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+  // Gets the text streamed to this object so far as an std::string.
+  // Each '\0' character in the buffer is replaced with "\\0".
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  std::string GetString() const;
+
+ private:
+
+#if GTEST_OS_SYMBIAN
+  // These are needed as the Nokia Symbian Compiler cannot decide between
+  // const T& and const T* in a function template. The Nokia compiler _can_
+  // decide between class template specializations for T and T*, so a
+  // tr1::type_traits-like is_pointer works, and we can overload on that.
+  template <typename T>
+  inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      *ss_ << pointer;
+    }
+  }
+  template <typename T>
+  inline void StreamHelper(internal::false_type /*is_pointer*/,
+                           const T& value) {
+    // See the comments in Message& operator <<(const T&) above for why
+    // we need this using statement.
+    using ::operator <<;
+    *ss_ << value;
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // We'll hold the text streamed to this object here.
+  const internal::scoped_ptr< ::std::stringstream> ss_;
+
+  // We declare (but don't implement) this to prevent the compiler
+  // from implementing the assignment operator.
+  void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+  return os << sb.GetString();
+}
+
+namespace internal {
+
+// Converts a streamable value to an std::string.  A NULL pointer is
+// converted to "(null)".  When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+template <typename T>
+std::string StreamableToString(const T& streamable) {
+  return (Message() << streamable).GetString();
+}
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test.  They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+# include <mem.h>
+#endif
+
+#include <string.h>
+#include <string>
+
+
+namespace testing {
+namespace internal {
+
+// String - an abstract class holding static string utilities.
+class GTEST_API_ String {
+ public:
+  // Static utility methods
+
+  // Clones a 0-terminated C string, allocating memory using new.  The
+  // caller is responsible for deleting the return value using
+  // delete[].  Returns the cloned string, or NULL if the input is
+  // NULL.
+  //
+  // This is different from strdup() in string.h, which allocates
+  // memory using malloc().
+  static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+  // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+  // able to pass strings to Win32 APIs on CE we need to convert them
+  // to 'Unicode', UTF-16.
+
+  // Creates a UTF-16 wide string from the given ANSI string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the wide string, or NULL if the
+  // input is NULL.
+  //
+  // The wide string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static LPCWSTR AnsiToUtf16(const char* c_str);
+
+  // Creates an ANSI string from the given wide string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the ANSI string, or NULL if the
+  // input is NULL.
+  //
+  // The returned string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+  // Compares two C strings.  Returns true iff they have the same content.
+  //
+  // Unlike strcmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CStringEquals(const char* lhs, const char* rhs);
+
+  // Converts a wide C string to a String using the UTF-8 encoding.
+  // NULL will be converted to "(null)".  If an error occurred during
+  // the conversion, "(failed to convert from wide string)" is
+  // returned.
+  static std::string ShowWideCString(const wchar_t* wide_c_str);
+
+  // Compares two wide C strings.  Returns true iff they have the same
+  // content.
+  //
+  // Unlike wcscmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+  // Compares two C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike strcasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CaseInsensitiveCStringEquals(const char* lhs,
+                                           const char* rhs);
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+  static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                               const wchar_t* rhs);
+
+  // Returns true iff the given string ends with the given suffix, ignoring
+  // case. Any string is considered to end with an empty suffix.
+  static bool EndsWithCaseInsensitive(
+      const std::string& str, const std::string& suffix);
+
+  // Formats an int value as "%02d".
+  static std::string FormatIntWidth2(int value);  // "%02d" for width == 2
+
+  // Formats an int value as "%X".
+  static std::string FormatHexInt(int value);
+
+  // Formats a byte as "%02X".
+  static std::string FormatByte(unsigned char value);
+
+ private:
+  String();  // Not meant to be instantiated.
+};  // class String
+
+// Gets the content of the stringstream's buffer as an std::string.  Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test.  They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath {
+ public:
+  FilePath() : pathname_("") { }
+  FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+  explicit FilePath(const std::string& pathname) : pathname_(pathname) {
+    Normalize();
+  }
+
+  FilePath& operator=(const FilePath& rhs) {
+    Set(rhs);
+    return *this;
+  }
+
+  void Set(const FilePath& rhs) {
+    pathname_ = rhs.pathname_;
+  }
+
+  const std::string& string() const { return pathname_; }
+  const char* c_str() const { return pathname_.c_str(); }
+
+  // Returns the current working directory, or "" if unsuccessful.
+  static FilePath GetCurrentDir();
+
+  // Given directory = "dir", base_name = "test", number = 0,
+  // extension = "xml", returns "dir/test.xml". If number is greater
+  // than zero (e.g., 12), returns "dir/test_12.xml".
+  // On Windows platform, uses \ as the separator rather than /.
+  static FilePath MakeFileName(const FilePath& directory,
+                               const FilePath& base_name,
+                               int number,
+                               const char* extension);
+
+  // Given directory = "dir", relative_path = "test.xml",
+  // returns "dir/test.xml".
+  // On Windows, uses \ as the separator rather than /.
+  static FilePath ConcatPaths(const FilePath& directory,
+                              const FilePath& relative_path);
+
+  // Returns a pathname for a file that does not currently exist. The pathname
+  // will be directory/base_name.extension or
+  // directory/base_name_<number>.extension if directory/base_name.extension
+  // already exists. The number will be incremented until a pathname is found
+  // that does not already exist.
+  // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+  // There could be a race condition if two or more processes are calling this
+  // function at the same time -- they could both pick the same filename.
+  static FilePath GenerateUniqueFileName(const FilePath& directory,
+                                         const FilePath& base_name,
+                                         const char* extension);
+
+  // Returns true iff the path is "".
+  bool IsEmpty() const { return pathname_.empty(); }
+
+  // If input name has a trailing separator character, removes it and returns
+  // the name, otherwise return the name string unmodified.
+  // On Windows platform, uses \ as the separator, other platforms use /.
+  FilePath RemoveTrailingPathSeparator() const;
+
+  // Returns a copy of the FilePath with the directory part removed.
+  // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+  // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+  // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+  // returns an empty FilePath ("").
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveDirectoryName() const;
+
+  // RemoveFileName returns the directory path with the filename removed.
+  // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+  // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+  // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+  // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveFileName() const;
+
+  // Returns a copy of the FilePath with the case-insensitive extension removed.
+  // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+  // FilePath("dir/file"). If a case-insensitive extension is not
+  // found, returns a copy of the original FilePath.
+  FilePath RemoveExtension(const char* extension) const;
+
+  // Creates directories so that path exists. Returns true if successful or if
+  // the directories already exist; returns false if unable to create
+  // directories for any reason. Will also return false if the FilePath does
+  // not represent a directory (that is, it doesn't end with a path separator).
+  bool CreateDirectoriesRecursively() const;
+
+  // Create the directory so that path exists. Returns true if successful or
+  // if the directory already exists; returns false if unable to create the
+  // directory for any reason, including if the parent directory does not
+  // exist. Not named "CreateDirectory" because that's a macro on Windows.
+  bool CreateFolder() const;
+
+  // Returns true if FilePath describes something in the file-system,
+  // either a file, directory, or whatever, and that something exists.
+  bool FileOrDirectoryExists() const;
+
+  // Returns true if pathname describes a directory in the file-system
+  // that exists.
+  bool DirectoryExists() const;
+
+  // Returns true if FilePath ends with a path separator, which indicates that
+  // it is intended to represent a directory. Returns false otherwise.
+  // This does NOT check that a directory (or file) actually exists.
+  bool IsDirectory() const;
+
+  // Returns true if pathname describes a root directory. (Windows has one
+  // root directory per disk drive.)
+  bool IsRootDirectory() const;
+
+  // Returns true if pathname describes an absolute path.
+  bool IsAbsolutePath() const;
+
+ private:
+  // Replaces multiple consecutive separators with a single separator.
+  // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+  // redundancies that might be in a pathname involving "." or "..".
+  //
+  // A pathname with multiple consecutive separators may occur either through
+  // user error or as a result of some scripts or APIs that generate a pathname
+  // with a trailing separator. On other platforms the same API or script
+  // may NOT generate a pathname with a trailing "/". Then elsewhere that
+  // pathname may have another "/" and pathname components added to it,
+  // without checking for the separator already being there.
+  // The script language and operating system may allow paths like "foo//bar"
+  // but some of the functions in FilePath will not handle that correctly. In
+  // particular, RemoveTrailingPathSeparator() only removes one separator, and
+  // it is called in CreateDirectoriesRecursively() assuming that it will change
+  // a pathname from directory syntax (trailing separator) to filename syntax.
+  //
+  // On Windows this method also replaces the alternate path separator '/' with
+  // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+  // "bar\\foo".
+
+  void Normalize();
+
+  // Returns a pointer to the last occurence of a valid path separator in
+  // the FilePath. On Windows, for example, both '/' and '\' are valid path
+  // separators. Returns NULL if no path separator was found.
+  const char* FindLastPathSeparator() const;
+
+  std::string pathname_;
+};  // class FilePath
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+// This file was GENERATED by command:
+//     pump.py gtest-type-util.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+
+// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+#  include <cxxabi.h>
+# elif defined(__HP_aCC)
+#  include <acxx_demangle.h>
+# endif  // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+# if GTEST_HAS_RTTI
+
+  const char* const name = typeid(T).name();
+#  if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+  int status = 0;
+  // gcc's implementation of typeid(T).name() mangles the type name,
+  // so we have to demangle it.
+#   if GTEST_HAS_CXXABI_H_
+  using abi::__cxa_demangle;
+#   endif  // GTEST_HAS_CXXABI_H_
+  char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+  const std::string name_str(status == 0 ? readable_name : name);
+  free(readable_name);
+  return name_str;
+#  else
+  return name;
+#  endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC
+
+# else
+
+  return "<type>";
+
+# endif  // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type.  This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+  typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types.  This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+  typedef T1 Head;
+  typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+  typedef T1 Head;
+  typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+  typedef T1 Head;
+  typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+  typedef T1 Head;
+  typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+  typedef T1 Head;
+  typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types6 {
+  typedef T1 Head;
+  typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types7 {
+  typedef T1 Head;
+  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types8 {
+  typedef T1 Head;
+  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+  typedef T1 Head;
+  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+  typedef T1 Head;
+  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types11 {
+  typedef T1 Head;
+  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types12 {
+  typedef T1 Head;
+  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types13 {
+  typedef T1 Head;
+  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+  typedef T1 Head;
+  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+  typedef T1 Head;
+  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types16 {
+  typedef T1 Head;
+  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types17 {
+  typedef T1 Head;
+  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types18 {
+  typedef T1 Head;
+  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+  typedef T1 Head;
+  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+  typedef T1 Head;
+  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types21 {
+  typedef T1 Head;
+  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types22 {
+  typedef T1 Head;
+  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types23 {
+  typedef T1 Head;
+  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+  typedef T1 Head;
+  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+  typedef T1 Head;
+  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types26 {
+  typedef T1 Head;
+  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types27 {
+  typedef T1 Head;
+  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types28 {
+  typedef T1 Head;
+  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+  typedef T1 Head;
+  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+  typedef T1 Head;
+  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types31 {
+  typedef T1 Head;
+  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types32 {
+  typedef T1 Head;
+  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types33 {
+  typedef T1 Head;
+  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+  typedef T1 Head;
+  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+  typedef T1 Head;
+  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types36 {
+  typedef T1 Head;
+  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types37 {
+  typedef T1 Head;
+  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types38 {
+  typedef T1 Head;
+  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+  typedef T1 Head;
+  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+  typedef T1 Head;
+  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types41 {
+  typedef T1 Head;
+  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types42 {
+  typedef T1 Head;
+  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types43 {
+  typedef T1 Head;
+  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+  typedef T1 Head;
+  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+  typedef T1 Head;
+  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types46 {
+  typedef T1 Head;
+  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types47 {
+  typedef T1 Head;
+  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types48 {
+  typedef T1 Head;
+  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+  typedef T1 Head;
+  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+  typedef T1 Head;
+  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+}  // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length.  Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+    typename T3 = internal::None, typename T4 = internal::None,
+    typename T5 = internal::None, typename T6 = internal::None,
+    typename T7 = internal::None, typename T8 = internal::None,
+    typename T9 = internal::None, typename T10 = internal::None,
+    typename T11 = internal::None, typename T12 = internal::None,
+    typename T13 = internal::None, typename T14 = internal::None,
+    typename T15 = internal::None, typename T16 = internal::None,
+    typename T17 = internal::None, typename T18 = internal::None,
+    typename T19 = internal::None, typename T20 = internal::None,
+    typename T21 = internal::None, typename T22 = internal::None,
+    typename T23 = internal::None, typename T24 = internal::None,
+    typename T25 = internal::None, typename T26 = internal::None,
+    typename T27 = internal::None, typename T28 = internal::None,
+    typename T29 = internal::None, typename T30 = internal::None,
+    typename T31 = internal::None, typename T32 = internal::None,
+    typename T33 = internal::None, typename T34 = internal::None,
+    typename T35 = internal::None, typename T36 = internal::None,
+    typename T37 = internal::None, typename T38 = internal::None,
+    typename T39 = internal::None, typename T40 = internal::None,
+    typename T41 = internal::None, typename T42 = internal::None,
+    typename T43 = internal::None, typename T44 = internal::None,
+    typename T45 = internal::None, typename T46 = internal::None,
+    typename T47 = internal::None, typename T48 = internal::None,
+    typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, internal::None, internal::None, internal::None> {
+  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, internal::None, internal::None> {
+  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, T49, internal::None> {
+  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>.  This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+  template <typename T>
+  struct Bind {
+    typedef Tmpl<T> type;
+  };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+  TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates.  This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists.  In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates4 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates7 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates10 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates13 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates16 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates19 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates22 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates25 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates28 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates31 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates34 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates37 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates40 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates43 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates46 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates49 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length.  Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, NoneT, NoneT, NoneT> {
+  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, NoneT, NoneT> {
+  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, T49, NoneT> {
+  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList {
+  typedef Types1<T> type;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> > {
+  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__.  Writing
+//
+//   foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number.  For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+class ProtocolMessage;
+namespace proto2 { class Message; }
+
+namespace testing {
+
+// Forward declarations.
+
+class AssertionResult;                 // Result of an assertion.
+class Message;                         // Represents a failure message.
+class Test;                            // Represents a test.
+class TestInfo;                        // Information about a test.
+class TestPartResult;                  // Result of a test part.
+class UnitTest;                        // A collection of test cases.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal {
+
+struct TraceInfo;                      // Information about a trace point.
+class ScopedTrace;                     // Implements scoped trace.
+class TestInfoImpl;                    // Opaque implementation of TestInfo
+class UnitTestImpl;                    // Opaque implementation of UnitTest
+
+// How many times InitGoogleTest() has been called.
+GTEST_API_ extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant).  Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler.  These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise.  Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal.  Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2];  // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_POD_
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_IS_NULL_LITERAL_(x) false
+#else
+# define GTEST_IS_NULL_LITERAL_(x) \
+    (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif  // GTEST_ELLIPSIS_NEEDS_POD_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ std::string AppendUserMessage(
+    const std::string& gtest_msg, const Message& user_msg);
+
+#if GTEST_HAS_EXCEPTIONS
+
+// This exception is thrown by (and only by) a failed Google Test
+// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
+// are enabled).  We derive it from std::runtime_error, which is for
+// errors presumably detectable only at run time.  Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
+ public:
+  explicit GoogleTestFailureException(const TestPartResult& failure);
+};
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+// A helper class for creating scoped traces in user programs.
+class GTEST_API_ ScopedTrace {
+ public:
+  // The c'tor pushes the given source file location and message onto
+  // a trace stack maintained by Google Test.
+  ScopedTrace(const char* file, int line, const Message& message);
+
+  // The d'tor pops the info pushed by the c'tor.
+  //
+  // Note that the d'tor is not virtual in order to be efficient.
+  // Don't inherit from ScopedTrace!
+  ~ScopedTrace();
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_;  // A ScopedTrace object does its job in its
+                            // c'tor and d'tor.  Therefore it doesn't
+                            // need to be used otherwise.
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+                                     const char* actual_expression,
+                                     const std::string& expected_value,
+                                     const std::string& actual_value,
+                                     bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ std::string GetBoolAssertionFailureMessage(
+    const AssertionResult& assertion_result,
+    const char* expression_text,
+    const char* actual_predicate_value,
+    const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison.  (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly.  Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+//   The most-significant bit being the leftmost, an IEEE
+//   floating-point looks like
+//
+//     sign_bit exponent_bits fraction_bits
+//
+//   Here, sign_bit is a single bit that designates the sign of the
+//   number.
+//
+//   For float, there are 8 exponent bits and 23 fraction bits.
+//
+//   For double, there are 11 exponent bits and 52 fraction bits.
+//
+//   More details can be found at
+//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+  // Defines the unsigned integer type that has the same size as the
+  // floating point number.
+  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+  // Constants.
+
+  // # of bits in a number.
+  static const size_t kBitCount = 8*sizeof(RawType);
+
+  // # of fraction bits in a number.
+  static const size_t kFractionBitCount =
+    std::numeric_limits<RawType>::digits - 1;
+
+  // # of exponent bits in a number.
+  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+  // The mask for the sign bit.
+  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+  // The mask for the fraction bits.
+  static const Bits kFractionBitMask =
+    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+  // The mask for the exponent bits.
+  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+  // How many ULP's (Units in the Last Place) we want to tolerate when
+  // comparing two numbers.  The larger the value, the more error we
+  // allow.  A 0 value means that two numbers must be exactly the same
+  // to be considered equal.
+  //
+  // The maximum error of a single floating-point operation is 0.5
+  // units in the last place.  On Intel CPU's, all floating-point
+  // calculations are done with 80-bit precision, while double has 64
+  // bits.  Therefore, 4 should be enough for ordinary use.
+  //
+  // See the following article for more details on ULP:
+  // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+  static const size_t kMaxUlps = 4;
+
+  // Constructs a FloatingPoint from a raw floating-point number.
+  //
+  // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+  // around may change its bits, although the new value is guaranteed
+  // to be also a NAN.  Therefore, don't expect this constructor to
+  // preserve the bits in x when x is a NAN.
+  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+  // Static methods
+
+  // Reinterprets a bit pattern as a floating-point number.
+  //
+  // This function is needed to test the AlmostEquals() method.
+  static RawType ReinterpretBits(const Bits bits) {
+    FloatingPoint fp(0);
+    fp.u_.bits_ = bits;
+    return fp.u_.value_;
+  }
+
+  // Returns the floating-point number that represent positive infinity.
+  static RawType Infinity() {
+    return ReinterpretBits(kExponentBitMask);
+  }
+
+  // Returns the maximum representable finite floating-point number.
+  static RawType Max();
+
+  // Non-static methods
+
+  // Returns the bits that represents this number.
+  const Bits &bits() const { return u_.bits_; }
+
+  // Returns the exponent bits of this number.
+  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+  // Returns the fraction bits of this number.
+  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+  // Returns the sign bit of this number.
+  Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+  // Returns true iff this is NAN (not a number).
+  bool is_nan() const {
+    // It's a NAN if the exponent bits are all ones and the fraction
+    // bits are not entirely zeros.
+    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+  }
+
+  // Returns true iff this number is at most kMaxUlps ULP's away from
+  // rhs.  In particular, this function:
+  //
+  //   - returns false if either number is (or both are) NAN.
+  //   - treats really large numbers as almost equal to infinity.
+  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
+  bool AlmostEquals(const FloatingPoint& rhs) const {
+    // The IEEE standard says that any comparison operation involving
+    // a NAN must return false.
+    if (is_nan() || rhs.is_nan()) return false;
+
+    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+        <= kMaxUlps;
+  }
+
+ private:
+  // The data type used to store the actual floating-point number.
+  union FloatingPointUnion {
+    RawType value_;  // The raw floating-point number.
+    Bits bits_;      // The bits that represent the number.
+  };
+
+  // Converts an integer from the sign-and-magnitude representation to
+  // the biased representation.  More precisely, let N be 2 to the
+  // power of (kBitCount - 1), an integer x is represented by the
+  // unsigned number x + N.
+  //
+  // For instance,
+  //
+  //   -N + 1 (the most negative number representable using
+  //          sign-and-magnitude) is represented by 1;
+  //   0      is represented by N; and
+  //   N - 1  (the biggest number representable using
+  //          sign-and-magnitude) is represented by 2N - 1.
+  //
+  // Read http://en.wikipedia.org/wiki/Signed_number_representations
+  // for more details on signed number representations.
+  static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+    if (kSignBitMask & sam) {
+      // sam represents a negative number.
+      return ~sam + 1;
+    } else {
+      // sam represents a positive number.
+      return kSignBitMask | sam;
+    }
+  }
+
+  // Given two numbers in the sign-and-magnitude representation,
+  // returns the distance between them as an unsigned number.
+  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+                                                     const Bits &sam2) {
+    const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+    const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+  }
+
+  FloatingPointUnion u_;
+};
+
+// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
+// macro defined by <windows.h>.
+template <>
+inline float FloatingPoint<float>::Max() { return FLT_MAX; }
+template <>
+inline double FloatingPoint<double>::Max() { return DBL_MAX; }
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them.  The TypeId type is
+// used to hold such IDs.  The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+  // dummy_ must not have a const type.  Otherwise an overly eager
+  // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+  // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+  static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T.  Different values will be
+// returned for different types.  Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+  // The compiler is required to allocate a different
+  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+  // the template.  Therefore, the address of dummy_ is guaranteed to
+  // be unique.
+  return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test.  Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+  virtual ~TestFactoryBase() {}
+
+  // Creates a test instance to run. The instance is both created and destroyed
+  // within TestInfoImpl::Run()
+  virtual Test* CreateTest() = 0;
+
+ protected:
+  TestFactoryBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+  virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+                                            long hr);  // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+                                            long hr);  // NOLINT
+
+#endif  // GTEST_OS_WINDOWS
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   type_param        the name of the test's type parameter, or NULL if
+//                     this is not a typed or a type-parameterized test.
+//   value_param       text representation of the test's value parameter,
+//                     or NULL if this is not a type-parameterized test.
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name,
+    const char* name,
+    const char* type_param,
+    const char* value_param,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false.  None of pstr, *pstr, and prefix can be NULL.
+GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class GTEST_API_ TypedTestCasePState {
+ public:
+  TypedTestCasePState() : registered_(false) {}
+
+  // Adds the given test name to defined_test_names_ and return true
+  // if the test case hasn't been registered; otherwise aborts the
+  // program.
+  bool AddTestName(const char* file, int line, const char* case_name,
+                   const char* test_name) {
+    if (registered_) {
+      fprintf(stderr, "%s Test %s must be defined before "
+              "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+              FormatFileLocation(file, line).c_str(), test_name, case_name);
+      fflush(stderr);
+      posix::Abort();
+    }
+    defined_test_names_.insert(test_name);
+    return true;
+  }
+
+  // Verifies that registered_tests match the test names in
+  // defined_test_names_; returns registered_tests if successful, or
+  // aborts the program otherwise.
+  const char* VerifyRegisteredTestNames(
+      const char* file, int line, const char* registered_tests);
+
+ private:
+  bool registered_;
+  ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  if (comma == NULL) {
+    return NULL;
+  }
+  while (IsSpace(*(++comma))) {}
+  return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline std::string GetPrefixUntilComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  return comma == NULL ? str : std::string(str, comma);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test.  The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter.  It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+  // 'index' is the index of the test in the type list 'Types'
+  // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+  // Types).  Valid values for 'index' are [0, N - 1] where N is the
+  // length of Types.
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names, int index) {
+    typedef typename Types::Head Type;
+    typedef Fixture<Type> FixtureClass;
+    typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+    // First, registers the first type-parameterized test in the type
+    // list.
+    MakeAndRegisterTestInfo(
+        (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
+         + StreamableToString(index)).c_str(),
+        GetPrefixUntilComma(test_names).c_str(),
+        GetTypeName<Type>().c_str(),
+        NULL,  // No value parameter.
+        GetTypeId<FixtureClass>(),
+        TestClass::SetUpTestCase,
+        TestClass::TearDownTestCase,
+        new TestFactoryImpl<TestClass>);
+
+    // Next, recurses (at compile time) with the tail of the type list.
+    return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+        ::Register(prefix, case_name, test_names, index + 1);
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+                       const char* /*test_names*/, int /*index*/) {
+    return true;
+  }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test.  The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names) {
+    typedef typename Tests::Head Head;
+
+    // First, register the first test in 'Test' for each type in 'Types'.
+    TypeParameterizedTest<Fixture, Head, Types>::Register(
+        prefix, case_name, test_names, 0);
+
+    // Next, recurses (at compile time) with the tail of the test list.
+    return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+        ::Register(prefix, case_name, SkipComma(test_names));
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+                       const char* /*test_names*/) {
+    return true;
+  }
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
+    UnitTest* unit_test, int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+  ConstCharPtr(const char* str) : value(str) {}
+  operator bool() const { return true; }
+  const char* value;
+};
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution.  Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code).  Unlike rand_r(), it's portable.  An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random {
+ public:
+  static const UInt32 kMaxRange = 1u << 31;
+
+  explicit Random(UInt32 seed) : state_(seed) {}
+
+  void Reseed(UInt32 seed) { state_ = seed; }
+
+  // Generates a random number from [0, range).  Crashes if 'range' is
+  // 0 or greater than kMaxRange.
+  UInt32 Generate(UInt32 range);
+
+ private:
+  UInt32 state_;
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
+// compiler error iff T1 and T2 are different types.
+template <typename T1, typename T2>
+struct CompileAssertTypesEqual;
+
+template <typename T>
+struct CompileAssertTypesEqual<T, T> {
+};
+
+// Removes the reference from a type if it is a reference type,
+// otherwise leaves it unchanged.  This is the same as
+// tr1::remove_reference, which is not widely available yet.
+template <typename T>
+struct RemoveReference { typedef T type; };  // NOLINT
+template <typename T>
+struct RemoveReference<T&> { typedef T type; };  // NOLINT
+
+// A handy wrapper around RemoveReference that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_REFERENCE_(T) \
+    typename ::testing::internal::RemoveReference<T>::type
+
+// Removes const from a type if it is a const type, otherwise leaves
+// it unchanged.  This is the same as tr1::remove_const, which is not
+// widely available yet.
+template <typename T>
+struct RemoveConst { typedef T type; };  // NOLINT
+template <typename T>
+struct RemoveConst<const T> { typedef T type; };  // NOLINT
+
+// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
+// definition to fail to remove the const in 'const int[3]' and 'const
+// char[3][4]'.  The following specialization works around the bug.
+template <typename T, size_t N>
+struct RemoveConst<const T[N]> {
+  typedef typename RemoveConst<T>::type type[N];
+};
+
+#if defined(_MSC_VER) && _MSC_VER < 1400
+// This is the only specialization that allows VC++ 7.1 to remove const in
+// 'const int[3] and 'const int[3][4]'.  However, it causes trouble with GCC
+// and thus needs to be conditionally compiled.
+template <typename T, size_t N>
+struct RemoveConst<T[N]> {
+  typedef typename RemoveConst<T>::type type[N];
+};
+#endif
+
+// A handy wrapper around RemoveConst that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_CONST_(T) \
+    typename ::testing::internal::RemoveConst<T>::type
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+    GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+
+// Adds reference to a type if it is not a reference type,
+// otherwise leaves it unchanged.  This is the same as
+// tr1::add_reference, which is not widely available yet.
+template <typename T>
+struct AddReference { typedef T& type; };  // NOLINT
+template <typename T>
+struct AddReference<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper around AddReference that works when the argument T
+// depends on template parameters.
+#define GTEST_ADD_REFERENCE_(T) \
+    typename ::testing::internal::AddReference<T>::type
+
+// Adds a reference to const on top of T as necessary.  For example,
+// it transforms
+//
+//   char         ==> const char&
+//   const char   ==> const char&
+//   char&        ==> const char&
+//   const char&  ==> const char&
+//
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+    GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
+
+// ImplicitlyConvertible<From, To>::value is a compile-time bool
+// constant that's true iff type From can be implicitly converted to
+// type To.
+template <typename From, typename To>
+class ImplicitlyConvertible {
+ private:
+  // We need the following helper functions only for their types.
+  // They have no implementations.
+
+  // MakeFrom() is an expression whose type is From.  We cannot simply
+  // use From(), as the type From may not have a public default
+  // constructor.
+  static From MakeFrom();
+
+  // These two functions are overloaded.  Given an expression
+  // Helper(x), the compiler will pick the first version if x can be
+  // implicitly converted to type To; otherwise it will pick the
+  // second version.
+  //
+  // The first version returns a value of size 1, and the second
+  // version returns a value of size 2.  Therefore, by checking the
+  // size of Helper(x), which can be done at compile time, we can tell
+  // which version of Helper() is used, and hence whether x can be
+  // implicitly converted to type To.
+  static char Helper(To);
+  static char (&Helper(...))[2];  // NOLINT
+
+  // We have to put the 'public' section after the 'private' section,
+  // or MSVC refuses to compile the code.
+ public:
+  // MSVC warns about implicitly converting from double to int for
+  // possible loss of data, so we need to temporarily disable the
+  // warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4244)  // Temporarily disables warning 4244.
+
+  static const bool value =
+      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+# pragma warning(pop)           // Restores the warning state.
+#elif defined(__BORLANDC__)
+  // C++Builder cannot use member overload resolution during template
+  // instantiation.  The simplest workaround is to use its C++0x type traits
+  // functions (C++Builder 2009 and above only).
+  static const bool value = __is_convertible(From, To);
+#else
+  static const bool value =
+      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#endif  // _MSV_VER
+};
+template <typename From, typename To>
+const bool ImplicitlyConvertible<From, To>::value;
+
+// IsAProtocolMessage<T>::value is a compile-time bool constant that's
+// true iff T is type ProtocolMessage, proto2::Message, or a subclass
+// of those.
+template <typename T>
+struct IsAProtocolMessage
+    : public bool_constant<
+  ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
+  ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
+};
+
+// When the compiler sees expression IsContainerTest<C>(0), if C is an
+// STL-style container class, the first overload of IsContainerTest
+// will be viable (since both C::iterator* and C::const_iterator* are
+// valid types and NULL can be implicitly converted to them).  It will
+// be picked over the second overload as 'int' is a perfect match for
+// the type of argument 0.  If C::iterator or C::const_iterator is not
+// a valid type, the first overload is not viable, and the second
+// overload will be picked.  Therefore, we can determine whether C is
+// a container class by checking the type of IsContainerTest<C>(0).
+// The value of the expression is insignificant.
+//
+// Note that we look for both C::iterator and C::const_iterator.  The
+// reason is that C++ injects the name of a class as a member of the
+// class itself (e.g. you can refer to class iterator as either
+// 'iterator' or 'iterator::iterator').  If we look for C::iterator
+// only, for example, we would mistakenly think that a class named
+// iterator is an STL container.
+//
+// Also note that the simpler approach of overloading
+// IsContainerTest(typename C::const_iterator*) and
+// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
+typedef int IsContainer;
+template <class C>
+IsContainer IsContainerTest(int /* dummy */,
+                            typename C::iterator* /* it */ = NULL,
+                            typename C::const_iterator* /* const_it */ = NULL) {
+  return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+
+// EnableIf<condition>::type is void when 'Cond' is true, and
+// undefined when 'Cond' is false.  To use SFINAE to make a function
+// overload only apply when a particular expression is true, add
+// "typename EnableIf<expression>::type* = 0" as the last parameter.
+template<bool> struct EnableIf;
+template<> struct EnableIf<true> { typedef void type; };  // NOLINT
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0.  When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
+  return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat.  If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
+  for (size_t i = 0; i != size; i++) {
+    if (!internal::ArrayEq(lhs[i], rhs[i]))
+      return false;
+  }
+  return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem.  Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
+  for (Iter it = begin; it != end; ++it) {
+    if (internal::ArrayEq(*it, elem))
+      return it;
+  }
+  return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0.  When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N]) {
+  internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat.  If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to) {
+  for (size_t i = 0; i != size; i++) {
+    internal::CopyArray(from[i], to + i);
+  }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+enum RelationToSource {
+  kReference,  // The NativeArray references the native array.
+  kCopy        // The NativeArray makes a copy of the native array and
+               // owns the copy.
+};
+
+// Adapts a native array to a read-only STL-style container.  Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers.  New members
+// should be added as needed.  To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier).  It's the client's responsibility to satisfy
+// this requirement.  Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray {
+ public:
+  // STL-style container typedefs.
+  typedef Element value_type;
+  typedef Element* iterator;
+  typedef const Element* const_iterator;
+
+  // Constructs from a native array.
+  NativeArray(const Element* array, size_t count, RelationToSource relation) {
+    Init(array, count, relation);
+  }
+
+  // Copy constructor.
+  NativeArray(const NativeArray& rhs) {
+    Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+  }
+
+  ~NativeArray() {
+    // Ensures that the user doesn't instantiate NativeArray with a
+    // const or reference type.
+    static_cast<void>(StaticAssertTypeEqHelper<Element,
+        GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
+    if (relation_to_source_ == kCopy)
+      delete[] array_;
+  }
+
+  // STL-style container methods.
+  size_t size() const { return size_; }
+  const_iterator begin() const { return array_; }
+  const_iterator end() const { return array_ + size_; }
+  bool operator==(const NativeArray& rhs) const {
+    return size() == rhs.size() &&
+        ArrayEq(begin(), size(), rhs.begin());
+  }
+
+ private:
+  // Initializes this object; makes a copy of the input array if
+  // 'relation' is kCopy.
+  void Init(const Element* array, size_t a_size, RelationToSource relation) {
+    if (relation == kReference) {
+      array_ = array;
+    } else {
+      Element* const copy = new Element[a_size];
+      CopyArray(array, a_size, copy);
+      array_ = copy;
+    }
+    size_ = a_size;
+    relation_to_source_ = relation;
+  }
+
+  const Element* array_;
+  size_t size_;
+  RelationToSource relation_to_source_;
+
+  GTEST_DISALLOW_ASSIGN_(NativeArray);
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
+  ::testing::internal::AssertHelper(result_type, file, line, message) \
+    = ::testing::Message()
+
+#define GTEST_MESSAGE_(message, result_type) \
+  GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)
+
+#define GTEST_FATAL_FAILURE_(message) \
+  return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+  GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+  GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+  if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::ConstCharPtr gtest_msg = "") { \
+    bool gtest_caught_expected = false; \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (expected_exception const&) { \
+      gtest_caught_expected = true; \
+    } \
+    catch (...) { \
+      gtest_msg.value = \
+          "Expected: " #statement " throws an exception of type " \
+          #expected_exception ".\n  Actual: it throws a different type."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+    if (!gtest_caught_expected) { \
+      gtest_msg.value = \
+          "Expected: " #statement " throws an exception of type " \
+          #expected_exception ".\n  Actual: it throws nothing."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+      fail(gtest_msg.value)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (...) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+      fail("Expected: " #statement " doesn't throw an exception.\n" \
+           "  Actual: it throws.")
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    bool gtest_caught_any = false; \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (...) { \
+      gtest_caught_any = true; \
+    } \
+    if (!gtest_caught_any) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+      fail("Expected: " #statement " throws an exception.\n" \
+           "  Actual: it doesn't.")
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// represenation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const ::testing::AssertionResult gtest_ar_ = \
+      ::testing::AssertionResult(expression)) \
+    ; \
+  else \
+    fail(::testing::internal::GetBoolAssertionFailureMessage(\
+        gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+      fail("Expected: " #statement " doesn't generate new fatal " \
+           "failures in the current thread.\n" \
+           "  Actual: it does.")
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+  test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+  virtual void TestBody();\
+  static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+  ::test_info_ =\
+    ::testing::internal::MakeAndRegisterTestInfo(\
+        #test_case_name, #test_name, NULL, NULL, \
+        (parent_id), \
+        parent_class::SetUpTestCase, \
+        parent_class::TearDownTestCase, \
+        new ::testing::internal::TestFactoryImpl<\
+            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests.  It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+
+#include <stdio.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro.  It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status:  The integer exit information in the format specified
+//               by wait(2)
+// exit code:    The integer code passed to exit(3), _exit(2), or
+//               returned from main()
+class GTEST_API_ DeathTest {
+ public:
+  // Create returns false if there was an error determining the
+  // appropriate action to take for the current death test; for example,
+  // if the gtest_death_test_style flag is set to an invalid value.
+  // The LastMessage method will return a more detailed message in that
+  // case.  Otherwise, the DeathTest pointer pointed to by the "test"
+  // argument is set.  If the death test should be skipped, the pointer
+  // is set to NULL; otherwise, it is set to the address of a new concrete
+  // DeathTest object that controls the execution of the current test.
+  static bool Create(const char* statement, const RE* regex,
+                     const char* file, int line, DeathTest** test);
+  DeathTest();
+  virtual ~DeathTest() { }
+
+  // A helper class that aborts a death test when it's deleted.
+  class ReturnSentinel {
+   public:
+    explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+    ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+   private:
+    DeathTest* const test_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+  } GTEST_ATTRIBUTE_UNUSED_;
+
+  // An enumeration of possible roles that may be taken when a death
+  // test is encountered.  EXECUTE means that the death test logic should
+  // be executed immediately.  OVERSEE means that the program should prepare
+  // the appropriate environment for a child process to execute the death
+  // test, then wait for it to complete.
+  enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+  // An enumeration of the three reasons that a test might be aborted.
+  enum AbortReason {
+    TEST_ENCOUNTERED_RETURN_STATEMENT,
+    TEST_THREW_EXCEPTION,
+    TEST_DID_NOT_DIE
+  };
+
+  // Assumes one of the above roles.
+  virtual TestRole AssumeRole() = 0;
+
+  // Waits for the death test to finish and returns its status.
+  virtual int Wait() = 0;
+
+  // Returns true if the death test passed; that is, the test process
+  // exited during the test, its exit status matches a user-supplied
+  // predicate, and its stderr output matches a user-supplied regular
+  // expression.
+  // The user-supplied predicate may be a macro expression rather
+  // than a function pointer or functor, or else Wait and Passed could
+  // be combined.
+  virtual bool Passed(bool exit_status_ok) = 0;
+
+  // Signals that the death test did not die as expected.
+  virtual void Abort(AbortReason reason) = 0;
+
+  // Returns a human-readable outcome message regarding the outcome of
+  // the last death test.
+  static const char* LastMessage();
+
+  static void set_last_death_test_message(const std::string& message);
+
+ private:
+  // A string containing a description of the outcome of the last death test.
+  static std::string last_death_test_message_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests.  May be mocked out for testing.
+class DeathTestFactory {
+ public:
+  virtual ~DeathTestFactory() { }
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// Traps C++ exceptions escaping statement and reports them as test
+// failures. Note that trapping SEH exceptions is not implemented here.
+# if GTEST_HAS_EXCEPTIONS
+#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+  try { \
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+  } catch (const ::std::exception& gtest_exception) { \
+    fprintf(\
+        stderr, \
+        "\n%s: Caught std::exception-derived exception escaping the " \
+        "death test statement. Exception message: %s\n", \
+        ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
+        gtest_exception.what()); \
+    fflush(stderr); \
+    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+  } catch (...) { \
+    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+  }
+
+# else
+#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+  GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+
+# endif
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    const ::testing::internal::RE& gtest_regex = (regex); \
+    ::testing::internal::DeathTest* gtest_dt; \
+    if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+        __FILE__, __LINE__, &gtest_dt)) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+    } \
+    if (gtest_dt != NULL) { \
+      ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+          gtest_dt_ptr(gtest_dt); \
+      switch (gtest_dt->AssumeRole()) { \
+        case ::testing::internal::DeathTest::OVERSEE_TEST: \
+          if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+            goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+          } \
+          break; \
+        case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+          ::testing::internal::DeathTest::ReturnSentinel \
+              gtest_sentinel(gtest_dt); \
+          GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+          gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+          break; \
+        } \
+        default: \
+          break; \
+      } \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+      fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
+// NDEBUG mode. In this case we need the statements to be executed, the regex is
+// ignored, and the macro must accept a streamed message even though the message
+// is never printed.
+# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+     GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+  } else \
+    ::testing::Message()
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+  InternalRunDeathTestFlag(const std::string& a_file,
+                           int a_line,
+                           int an_index,
+                           int a_write_fd)
+      : file_(a_file), line_(a_line), index_(an_index),
+        write_fd_(a_write_fd) {}
+
+  ~InternalRunDeathTestFlag() {
+    if (write_fd_ >= 0)
+      posix::Close(write_fd_);
+  }
+
+  const std::string& file() const { return file_; }
+  int line() const { return line_; }
+  int index() const { return index_; }
+  int write_fd() const { return write_fd_; }
+
+ private:
+  std::string file_;
+  int line_;
+  int index_;
+  int write_fd_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#else  // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
+// systems that support death tests. This allows one to write such a macro
+// on a system that does not support death tests and be sure that it will
+// compile on a death-test supporting system.
+//
+// Parameters:
+//   statement -  A statement that a macro such as EXPECT_DEATH would test
+//                for program termination. This macro has to make sure this
+//                statement is compiled but not executed, to ensure that
+//                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+//                parameter iff EXPECT_DEATH compiles with it.
+//   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
+//                the output of statement.  This parameter has to be
+//                compiled but not evaluated by this macro, to ensure that
+//                this macro only accepts expressions that a macro such as
+//                EXPECT_DEATH would accept.
+//   terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+//                and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+//                This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+//                compile inside functions where ASSERT_DEATH doesn't
+//                compile.
+//
+//  The branch that has an always false condition is used to ensure that
+//  statement and regex are compiled (and thus syntactically correct) but
+//  never executed. The unreachable code macro protects the terminator
+//  statement from generating an 'unreachable code' warning in case
+//  statement unconditionally returns or throws. The Message constructor at
+//  the end allows the syntax of streaming additional messages into the
+//  macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+    if (::testing::internal::AlwaysTrue()) { \
+      GTEST_LOG_(WARNING) \
+          << "Death tests are not supported on this platform.\n" \
+          << "Statement '" #statement "' cannot be verified."; \
+    } else if (::testing::internal::AlwaysFalse()) { \
+      ::testing::internal::RE::PartialMatch(".*", (regex)); \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+      terminator; \
+    } else \
+      ::testing::Message()
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+namespace testing {
+
+// This flag controls the style of death tests.  Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process.  Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests.  IMPORTANT: This is an internal utility.  Using it may break the
+// implementation of death tests.  User code MUST NOT use it.
+GTEST_API_ bool InDeathTestChild();
+
+}  // namespace internal
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+//   1. It generates a warning if there is more than one active
+//   thread.  This is because it's safe to fork() or clone() only
+//   when there is a single thread.
+//
+//   2. The parent process clone()s a sub-process and runs the death
+//   test in it; the sub-process exits with code 0 at the end of the
+//   death test, if it hasn't exited already.
+//
+//   3. The parent process waits for the sub-process to terminate.
+//
+//   4. The parent process checks the exit code and error message of
+//   the sub-process.
+//
+// Examples:
+//
+//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+//   for (int i = 0; i < 5; i++) {
+//     EXPECT_DEATH(server.ProcessRequest(i),
+//                  "Invalid request .* in ProcessRequest()")
+//                  << "Failed to die on request " << i;
+//   }
+//
+//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+//   bool KilledBySIGHUP(int exit_code) {
+//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+//   }
+//
+//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
+//   which uses the POSIX extended regex syntax.
+//
+//   On other platforms (e.g. Windows), we only support a simple regex
+//   syntax implemented as part of Google Test.  This limited
+//   implementation should be enough most of the time when writing
+//   death tests; though it lacks many features you can find in PCRE
+//   or POSIX extended regex syntax.  For example, we don't support
+//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+//   repetition count ("x{5,7}"), among others.
+//
+//   Below is the syntax that we do support.  We chose it to be a
+//   subset of both PCRE and POSIX extended regex, so it's easy to
+//   learn wherever you come from.  In the following: 'A' denotes a
+//   literal character, period (.), or a single \\ escape sequence;
+//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
+//   natural numbers.
+//
+//     c     matches any literal character c
+//     \\d   matches any decimal digit
+//     \\D   matches any character that's not a decimal digit
+//     \\f   matches \f
+//     \\n   matches \n
+//     \\r   matches \r
+//     \\s   matches any ASCII whitespace, including \n
+//     \\S   matches any character that's not a whitespace
+//     \\t   matches \t
+//     \\v   matches \v
+//     \\w   matches any letter, _, or decimal digit
+//     \\W   matches any character that \\w doesn't match
+//     \\c   matches any literal character c, which must be a punctuation
+//     .     matches any single character except \n
+//     A?    matches 0 or 1 occurrences of A
+//     A*    matches 0 or many occurrences of A
+//     A+    matches 1 or many occurrences of A
+//     ^     matches the beginning of a string (not that of each line)
+//     $     matches the end of a string (not that of each line)
+//     xy    matches x followed by y
+//
+//   If you accidentally use PCRE or POSIX extended regex features
+//   not implemented by us, you will get a run-time failure.  In that
+//   case, please try to rewrite your regular expression within the
+//   above syntax.
+//
+//   This implementation is *not* meant to be as highly tuned or robust
+//   as a compiled regex library, but should perform well enough for a
+//   death test, which already incurs significant overhead by launching
+//   a child process.
+//
+// Known caveats:
+//
+//   A "threadsafe" style death test obtains the path to the test
+//   program from argv[0] and re-executes it in the sub-process.  For
+//   simplicity, the current implementation doesn't search the PATH
+//   when launching the sub-process.  This means that the user must
+//   invoke the test program via a path that contains at least one
+//   path separator (e.g. path/to/foo_test and
+//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
+//   is rarely a problem as people usually don't put the test binary
+//   directory in PATH.
+//
+// TODO(wan@google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+# define ASSERT_EXIT(statement, predicate, regex) \
+    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_EXIT(statement, predicate, regex) \
+    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+# define ASSERT_DEATH(statement, regex) \
+    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_DEATH(statement, regex) \
+    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode {
+ public:
+  explicit ExitedWithCode(int exit_code);
+  bool operator()(int exit_status) const;
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ExitedWithCode& other);
+
+  const int exit_code_;
+};
+
+# if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class GTEST_API_ KilledBySignal {
+ public:
+  explicit KilledBySignal(int signum);
+  bool operator()(int exit_status) const;
+ private:
+  const int signum_;
+};
+# endif  // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+//   if (sideeffect) {
+//     *sideeffect = 12;
+//   }
+//   LOG(DFATAL) << "death";
+//   return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+//   int sideeffect = 0;
+//   // Only asserts in dbg.
+//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+//   // opt-mode has sideeffect visible.
+//   EXPECT_EQ(12, sideeffect);
+// #else
+//   // dbg-mode no visible sideeffect.
+//   EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects.  A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+//   // Side-effects here will have an effect after this statement in
+//   // opt mode, but none in debug mode.
+//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+# ifdef NDEBUG
+
+#  define EXPECT_DEBUG_DEATH(statement, regex) \
+  GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+#  define ASSERT_DEBUG_DEATH(statement, regex) \
+  GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# else
+
+#  define EXPECT_DEBUG_DEATH(statement, regex) \
+  EXPECT_DEATH(statement, regex)
+
+#  define ASSERT_DEBUG_DEATH(statement, regex) \
+  ASSERT_DEATH(statement, regex)
+
+# endif  // NDEBUG for EXPECT_DEBUG_DEATH
+#endif  // GTEST_HAS_DEATH_TEST
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning.  This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+    EXPECT_DEATH(statement, regex)
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+    ASSERT_DEATH(statement, regex)
+#else
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+#endif
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+// This file was GENERATED by command:
+//     pump.py gtest-param-test.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+  // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+  // Inside a test, access the test parameter with the GetParam() method
+  // of the TestWithParam<T> class:
+  EXPECT_TRUE(foo.Blah(GetParam()));
+  ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+  ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a  summary of them, which
+// are all in the testing namespace:
+//
+//
+//  Range(begin, end [, step]) - Yields values {begin, begin+step,
+//                               begin+step+step, ...}. The values do not
+//                               include end. step defaults to 1.
+//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.
+//  ValuesIn(container)        - Yields values from a C-style array, an STL
+//  ValuesIn(begin,end)          container, or an iterator range [begin, end).
+//  Bool()                     - Yields sequence {false, true}.
+//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product
+//                               for the math savvy) of the values generated
+//                               by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+                        FooTest,
+                        Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+//    * InstantiationName/FooTest.DoesBlah/1 for "miny"
+//    * InstantiationName/FooTest.DoesBlah/2 for "moe"
+//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+  // You can inherit all the usual members for a non-parameterized test
+  // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+  // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+  // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+  // GetParam works just the same here as if you inherit from TestWithParam.
+  EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif  // 0
+
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+//   Unlike other linked_ptr implementations, in this implementation
+//   a linked_ptr object is thread-safe in the sense that:
+//     - it's safe to copy linked_ptr objects concurrently,
+//     - it's safe to copy *from* a linked_ptr and read its underlying
+//       raw pointer (e.g. via get()) concurrently, and
+//     - it's safe to write to two linked_ptrs that point to the same
+//       shared object concurrently.
+// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Many linked_ptr operations may change p.link_ for some linked_ptr
+  // variable p in the same circle as this object.  Therefore we need
+  // to prevent two such operations from occurring concurrently.
+  //
+  // Note that different types of linked_ptr objects can coexist in a
+  // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+  // linked_ptr<Derived2>).  Therefore we must use a single mutex to
+  // protect all linked_ptr objects.  This can create serious
+  // contention in production code, but is acceptable in a testing
+  // framework.
+
+  // Join an existing circle.
+  void join(linked_ptr_internal const* ptr)
+      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    linked_ptr_internal const* p = ptr;
+    while (p->next_ != ptr) p = p->next_;
+    p->next_ = this;
+    next_ = ptr;
+  }
+
+  // Leave whatever circle we're part of.  Returns true if we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  bool depart()
+      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+  linked_ptr(linked_ptr const& ptr) {  // NOLINT
+    assert(&ptr != this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+
+  bool operator==(T* p) const { return value_ == p; }
+  bool operator!=(T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// A user can teach this function how to print a class type T by
+// defining either operator<<() or PrintTo() in the namespace that
+// defines T.  More specifically, the FIRST defined function in the
+// following list will be used (assuming T is defined in namespace
+// foo):
+//
+//   1. foo::PrintTo(const T&, ostream*)
+//   2. operator<<(ostream&, const T&) defined in either foo or the
+//      global namespace.
+//
+// If none of the above is defined, it will print the debug string of
+// the value if it is a protocol buffer, or print the raw bytes in the
+// value otherwise.
+//
+// To aid debugging: when T is a reference type, the address of the
+// value is also printed; when T is a (const) char pointer, both the
+// pointer value and the NUL-terminated string it points to are
+// printed.
+//
+// We also provide some convenient wrappers:
+//
+//   // Prints a value to a string.  For a (const or not) char
+//   // pointer, the NUL-terminated string (but not the pointer) is
+//   // printed.
+//   std::string ::testing::PrintToString(const T& value);
+//
+//   // Prints a value tersely: for a reference type, the referenced
+//   // value (but not the address) is printed; for a (const or not) char
+//   // pointer, the NUL-terminated string (but not the pointer) is
+//   // printed.
+//   void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
+//
+//   // Prints value using the type inferred by the compiler.  The difference
+//   // from UniversalTersePrint() is that this function prints both the
+//   // pointer and the NUL-terminated string for a (const or not) char pointer.
+//   void ::testing::internal::UniversalPrint(const T& value, ostream*);
+//
+//   // Prints the fields of a tuple tersely to a string vector, one
+//   // element for each field. Tuple support must be enabled in
+//   // gtest-port.h.
+//   std::vector<string> UniversalTersePrintTupleFieldsToStrings(
+//       const Tuple& value);
+//
+// Known limitation:
+//
+// The print primitives print the elements of an STL-style container
+// using the compiler-inferred type of *iter where iter is a
+// const_iterator of the container.  When const_iterator is an input
+// iterator but not a forward iterator, this inferred type may not
+// match value_type, and the print output may be incorrect.  In
+// practice, this is rarely a problem as for most containers
+// const_iterator is a forward iterator.  We'll fix this if there's an
+// actual need for it.  Note that this fix cannot rely on value_type
+// being defined as many user-defined container types don't have
+// value_type.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <ostream>  // NOLINT
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace testing {
+
+// Definitions in the 'internal' and 'internal2' name spaces are
+// subject to change without notice.  DO NOT USE THEM IN USER CODE!
+namespace internal2 {
+
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+                                     size_t count,
+                                     ::std::ostream* os);
+
+// For selecting which printer to use when a given type has neither <<
+// nor PrintTo().
+enum TypeKind {
+  kProtobuf,              // a protobuf type
+  kConvertibleToInteger,  // a type implicitly convertible to BiggestInt
+                          // (e.g. a named or unnamed enum type)
+  kOtherType              // anything else
+};
+
+// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
+// by the universal printer to print a value of type T when neither
+// operator<< nor PrintTo() is defined for T, where kTypeKind is the
+// "kind" of T as defined by enum TypeKind.
+template <typename T, TypeKind kTypeKind>
+class TypeWithoutFormatter {
+ public:
+  // This default version is called when kTypeKind is kOtherType.
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
+                         sizeof(value), os);
+  }
+};
+
+// We print a protobuf using its ShortDebugString() when the string
+// doesn't exceed this many characters; otherwise we print it using
+// DebugString() for better readability.
+const size_t kProtobufOneLinerMaxLength = 50;
+
+template <typename T>
+class TypeWithoutFormatter<T, kProtobuf> {
+ public:
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    const ::testing::internal::string short_str = value.ShortDebugString();
+    const ::testing::internal::string pretty_str =
+        short_str.length() <= kProtobufOneLinerMaxLength ?
+        short_str : ("\n" + value.DebugString());
+    *os << ("<" + pretty_str + ">");
+  }
+};
+
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToInteger> {
+ public:
+  // Since T has no << operator or PrintTo() but can be implicitly
+  // converted to BiggestInt, we print it as a BiggestInt.
+  //
+  // Most likely T is an enum type (either named or unnamed), in which
+  // case printing it as an integer is the desired behavior.  In case
+  // T is not an enum, printing it as an integer is the best we can do
+  // given that it has no user-defined printer.
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    const internal::BiggestInt kBigInt = value;
+    *os << kBigInt;
+  }
+};
+
+// Prints the given value to the given ostream.  If the value is a
+// protocol message, its debug string is printed; if it's an enum or
+// of a type implicitly convertible to BiggestInt, it's printed as an
+// integer; otherwise the bytes in the value are printed.  This is
+// what UniversalPrinter<T>::Print() does when it knows nothing about
+// type T and T has neither << operator nor PrintTo().
+//
+// A user can override this behavior for a class type Foo by defining
+// a << operator in the namespace where Foo is defined.
+//
+// We put this operator in namespace 'internal2' instead of 'internal'
+// to simplify the implementation, as much code in 'internal' needs to
+// use << in STL, which would conflict with our own << were it defined
+// in 'internal'.
+//
+// Note that this operator<< takes a generic std::basic_ostream<Char,
+// CharTraits> type instead of the more restricted std::ostream.  If
+// we define it to take an std::ostream instead, we'll get an
+// "ambiguous overloads" compiler error when trying to print a type
+// Foo that supports streaming to std::basic_ostream<Char,
+// CharTraits>, as the compiler cannot tell whether
+// operator<<(std::ostream&, const T&) or
+// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
+// specific.
+template <typename Char, typename CharTraits, typename T>
+::std::basic_ostream<Char, CharTraits>& operator<<(
+    ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
+  TypeWithoutFormatter<T,
+      (internal::IsAProtocolMessage<T>::value ? kProtobuf :
+       internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
+       kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
+  return os;
+}
+
+}  // namespace internal2
+}  // namespace testing
+
+// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
+// magic needed for implementing UniversalPrinter won't work.
+namespace testing_internal {
+
+// Used to print a value that is not an STL-style container when the
+// user doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
+  // With the following statement, during unqualified name lookup,
+  // testing::internal2::operator<< appears as if it was declared in
+  // the nearest enclosing namespace that contains both
+  // ::testing_internal and ::testing::internal2, i.e. the global
+  // namespace.  For more details, refer to the C++ Standard section
+  // 7.3.4-1 [namespace.udir].  This allows us to fall back onto
+  // testing::internal2::operator<< in case T doesn't come with a <<
+  // operator.
+  //
+  // We cannot write 'using ::testing::internal2::operator<<;', which
+  // gcc 3.3 fails to compile due to a compiler bug.
+  using namespace ::testing::internal2;  // NOLINT
+
+  // Assuming T is defined in namespace foo, in the next statement,
+  // the compiler will consider all of:
+  //
+  //   1. foo::operator<< (thanks to Koenig look-up),
+  //   2. ::operator<< (as the current namespace is enclosed in ::),
+  //   3. testing::internal2::operator<< (thanks to the using statement above).
+  //
+  // The operator<< whose type matches T best will be picked.
+  //
+  // We deliberately allow #2 to be a candidate, as sometimes it's
+  // impossible to define #1 (e.g. when foo is ::std, defining
+  // anything in it is undefined behavior unless you are a compiler
+  // vendor.).
+  *os << value;
+}
+
+}  // namespace testing_internal
+
+namespace testing {
+namespace internal {
+
+// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
+// value to the given ostream.  The caller must ensure that
+// 'ostream_ptr' is not NULL, or the behavior is undefined.
+//
+// We define UniversalPrinter as a class template (as opposed to a
+// function template), as we need to partially specialize it for
+// reference types, which cannot be done with function templates.
+template <typename T>
+class UniversalPrinter;
+
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
+
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+template <typename C>
+void DefaultPrintTo(IsContainer /* dummy */,
+                    false_type /* is not a pointer */,
+                    const C& container, ::std::ostream* os) {
+  const size_t kMaxCount = 32;  // The maximum number of elements to print.
+  *os << '{';
+  size_t count = 0;
+  for (typename C::const_iterator it = container.begin();
+       it != container.end(); ++it, ++count) {
+    if (count > 0) {
+      *os << ',';
+      if (count == kMaxCount) {  // Enough has been printed.
+        *os << " ...";
+        break;
+      }
+    }
+    *os << ' ';
+    // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
+    // handle *it being a native array.
+    internal::UniversalPrint(*it, os);
+  }
+
+  if (count > 0) {
+    *os << ' ';
+  }
+  *os << '}';
+}
+
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it.  (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space.  Their representation is
+// implementation-defined.  Therefore they will be printed as raw
+// bytes.)
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+                    true_type /* is a pointer */,
+                    T* p, ::std::ostream* os) {
+  if (p == NULL) {
+    *os << "NULL";
+  } else {
+    // C++ doesn't allow casting from a function pointer to any object
+    // pointer.
+    //
+    // IsTrue() silences warnings: "Condition is always true",
+    // "unreachable code".
+    if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
+      // T is not a function type.  We just call << to print p,
+      // relying on ADL to pick up user-defined << for their pointer
+      // types, if any.
+      *os << p;
+    } else {
+      // T is a function type, so '*os << p' doesn't do what we want
+      // (it just prints p as bool).  We want to print p as a const
+      // void*.  However, we cannot cast it to const void* directly,
+      // even using reinterpret_cast, as earlier versions of gcc
+      // (e.g. 3.4.5) cannot compile the cast when p is a function
+      // pointer.  Casting to UInt64 first solves the problem.
+      *os << reinterpret_cast<const void*>(
+          reinterpret_cast<internal::UInt64>(p));
+    }
+  }
+}
+
+// Used to print a non-container, non-pointer value when the user
+// doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+                    false_type /* is not a pointer */,
+                    const T& value, ::std::ostream* os) {
+  ::testing_internal::DefaultPrintNonContainerTo(value, os);
+}
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it.  This is what
+// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
+// or overloaded for type T.
+//
+// A user can override this behavior for a class type Foo by defining
+// an overload of PrintTo() in the namespace where Foo is defined.  We
+// give the user this option as sometimes defining a << operator for
+// Foo is not desirable (e.g. the coding style may prevent doing it,
+// or there is already a << operator but it doesn't do what the user
+// wants).
+template <typename T>
+void PrintTo(const T& value, ::std::ostream* os) {
+  // DefaultPrintTo() is overloaded.  The type of its first two
+  // arguments determine which version will be picked.  If T is an
+  // STL-style container, the version for container will be called; if
+  // T is a pointer, the pointer version will be called; otherwise the
+  // generic version will be called.
+  //
+  // Note that we check for container types here, prior to we check
+  // for protocol message types in our operator<<.  The rationale is:
+  //
+  // For protocol messages, we want to give people a chance to
+  // override Google Mock's format by defining a PrintTo() or
+  // operator<<.  For STL containers, other formats can be
+  // incompatible with Google Mock's format for the container
+  // elements; therefore we check for container types here to ensure
+  // that our format is used.
+  //
+  // The second argument of DefaultPrintTo() is needed to bypass a bug
+  // in Symbian's C++ compiler that prevents it from picking the right
+  // overload between:
+  //
+  //   PrintTo(const T& x, ...);
+  //   PrintTo(T* x, ...);
+  DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::Print() how to print standard types (built-in
+// types, strings, plain arrays, and pointers).
+
+// Overloads for various char types.
+GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
+GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
+inline void PrintTo(char c, ::std::ostream* os) {
+  // When printing a plain char, we always treat it as unsigned.  This
+  // way, the output won't be affected by whether the compiler thinks
+  // char is signed or not.
+  PrintTo(static_cast<unsigned char>(c), os);
+}
+
+// Overloads for other simple built-in types.
+inline void PrintTo(bool x, ::std::ostream* os) {
+  *os << (x ? "true" : "false");
+}
+
+// Overload for wchar_t type.
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its decimal code (except for L'\0').
+// The L'\0' char is printed as "L'\\0'". The decimal code is printed
+// as signed integer when wchar_t is implemented by the compiler
+// as a signed type and is printed as an unsigned integer when wchar_t
+// is implemented as an unsigned type.
+GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const char*>(s), os);
+}
+
+// signed/unsigned char is often used for representing binary data, so
+// we print pointers to it as void* to be safe.
+inline void PrintTo(const signed char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+
+// MSVC can be configured to define wchar_t as a typedef of unsigned
+// short.  It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
+// type.  When wchar_t is a typedef, defining an overload for const
+// wchar_t* would cause unsigned short* be printed as a wide string,
+// possibly causing invalid memory accesses.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Overloads for wide C strings
+GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
+inline void PrintTo(wchar_t* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const wchar_t*>(s), os);
+}
+#endif
+
+// Overload for C arrays.  Multi-dimensional arrays are printed
+// properly.
+
+// Prints the given number of elements in an array, without printing
+// the curly braces.
+template <typename T>
+void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
+  UniversalPrint(a[0], os);
+  for (size_t i = 1; i != count; i++) {
+    *os << ", ";
+    UniversalPrint(a[i], os);
+  }
+}
+
+// Overloads for ::string and ::std::string.
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
+inline void PrintTo(const ::string& s, ::std::ostream* os) {
+  PrintStringTo(s, os);
+}
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
+inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
+  PrintStringTo(s, os);
+}
+
+// Overloads for ::wstring and ::std::wstring.
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
+  PrintWideStringTo(s, os);
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
+  PrintWideStringTo(s, os);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple.  Needed for printing function arguments,
+// which are packed as tuples.
+
+// Helper function for printing a tuple.  T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os);
+
+// Overloaded PrintTo() for tuples of various arities.  We support
+// tuples of up-to 10 fields.  The following implementation works
+// regardless of whether tr1::tuple is implemented using the
+// non-standard variadic template feature or not.
+
+inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1>
+void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2>
+void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10>
+void PrintTo(
+    const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
+    ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
+  *os << '(';
+  // We cannot use UniversalPrint(value.first, os) here, as T1 may be
+  // a reference type.  The same for printing value.second.
+  UniversalPrinter<T1>::Print(value.first, os);
+  *os << ", ";
+  UniversalPrinter<T2>::Print(value.second, os);
+  *os << ')';
+}
+
+// Implements printing a non-reference type T by letting the compiler
+// pick the right overload of PrintTo() for T.
+template <typename T>
+class UniversalPrinter {
+ public:
+  // MSVC warns about adding const to a function type, so we want to
+  // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4180)  // Temporarily disables warning 4180.
+#endif  // _MSC_VER
+
+  // Note: we deliberately don't call this PrintTo(), as that name
+  // conflicts with ::testing::internal::PrintTo in the body of the
+  // function.
+  static void Print(const T& value, ::std::ostream* os) {
+    // By default, ::testing::internal::PrintTo() is used for printing
+    // the value.
+    //
+    // Thanks to Koenig look-up, if T is a class and has its own
+    // PrintTo() function defined in its namespace, that function will
+    // be visible here.  Since it is more specific than the generic ones
+    // in ::testing::internal, it will be picked by the compiler in the
+    // following statement - exactly what we want.
+    PrintTo(value, os);
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)           // Restores the warning state.
+#endif  // _MSC_VER
+};
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+  if (len == 0) {
+    *os << "{}";
+  } else {
+    *os << "{ ";
+    const size_t kThreshold = 18;
+    const size_t kChunkSize = 8;
+    // If the array has more than kThreshold elements, we'll have to
+    // omit some details by printing only the first and the last
+    // kChunkSize elements.
+    // TODO(wan@google.com): let the user control the threshold using a flag.
+    if (len <= kThreshold) {
+      PrintRawArrayTo(begin, len, os);
+    } else {
+      PrintRawArrayTo(begin, kChunkSize, os);
+      *os << ", ..., ";
+      PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+    }
+    *os << " }";
+  }
+}
+// This overload prints a (const) char array compactly.
+GTEST_API_ void UniversalPrintArray(
+    const char* begin, size_t len, ::std::ostream* os);
+
+// This overload prints a (const) wchar_t array compactly.
+GTEST_API_ void UniversalPrintArray(
+    const wchar_t* begin, size_t len, ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]> {
+ public:
+  // Prints the given array, omitting some elements when there are too
+  // many.
+  static void Print(const T (&a)[N], ::std::ostream* os) {
+    UniversalPrintArray(a, N, os);
+  }
+};
+
+// Implements printing a reference type T&.
+template <typename T>
+class UniversalPrinter<T&> {
+ public:
+  // MSVC warns about adding const to a function type, so we want to
+  // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4180)  // Temporarily disables warning 4180.
+#endif  // _MSC_VER
+
+  static void Print(const T& value, ::std::ostream* os) {
+    // Prints the address of the value.  We use reinterpret_cast here
+    // as static_cast doesn't compile when T is a function type.
+    *os << "@" << reinterpret_cast<const void*>(&value) << " ";
+
+    // Then prints the value itself.
+    UniversalPrint(value, os);
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)           // Restores the warning state.
+#endif  // _MSC_VER
+};
+
+// Prints a value tersely: for a reference type, the referenced value
+// (but not the address) is printed; for a (const) char pointer, the
+// NUL-terminated string (but not the pointer) is printed.
+
+template <typename T>
+class UniversalTersePrinter {
+ public:
+  static void Print(const T& value, ::std::ostream* os) {
+    UniversalPrint(value, os);
+  }
+};
+template <typename T>
+class UniversalTersePrinter<T&> {
+ public:
+  static void Print(const T& value, ::std::ostream* os) {
+    UniversalPrint(value, os);
+  }
+};
+template <typename T, size_t N>
+class UniversalTersePrinter<T[N]> {
+ public:
+  static void Print(const T (&value)[N], ::std::ostream* os) {
+    UniversalPrinter<T[N]>::Print(value, os);
+  }
+};
+template <>
+class UniversalTersePrinter<const char*> {
+ public:
+  static void Print(const char* str, ::std::ostream* os) {
+    if (str == NULL) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(string(str), os);
+    }
+  }
+};
+template <>
+class UniversalTersePrinter<char*> {
+ public:
+  static void Print(char* str, ::std::ostream* os) {
+    UniversalTersePrinter<const char*>::Print(str, os);
+  }
+};
+
+#if GTEST_HAS_STD_WSTRING
+template <>
+class UniversalTersePrinter<const wchar_t*> {
+ public:
+  static void Print(const wchar_t* str, ::std::ostream* os) {
+    if (str == NULL) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(::std::wstring(str), os);
+    }
+  }
+};
+#endif
+
+template <>
+class UniversalTersePrinter<wchar_t*> {
+ public:
+  static void Print(wchar_t* str, ::std::ostream* os) {
+    UniversalTersePrinter<const wchar_t*>::Print(str, os);
+  }
+};
+
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os) {
+  UniversalTersePrinter<T>::Print(value, os);
+}
+
+// Prints a value using the type inferred by the compiler.  The
+// difference between this and UniversalTersePrint() is that for a
+// (const) char pointer, this prints both the pointer and the
+// NUL-terminated string.
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os) {
+  // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
+  // UniversalPrinter with T directly.
+  typedef T T1;
+  UniversalPrinter<T1>::Print(value, os);
+}
+
+#if GTEST_HAS_TR1_TUPLE
+typedef ::std::vector<string> Strings;
+
+// This helper template allows PrintTo() for tuples and
+// UniversalTersePrintTupleFieldsToStrings() to be defined by
+// induction on the number of tuple fields.  The idea is that
+// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
+// fields in tuple t, and can be defined in terms of
+// TuplePrefixPrinter<N - 1>.
+
+// The inductive case.
+template <size_t N>
+struct TuplePrefixPrinter {
+  // Prints the first N fields of a tuple.
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+    TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
+    *os << ", ";
+    UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
+        ::Print(::std::tr1::get<N - 1>(t), os);
+  }
+
+  // Tersely prints the first N fields of a tuple to a string vector,
+  // one element for each field.
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+    TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
+    ::std::stringstream ss;
+    UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+    strings->push_back(ss.str());
+  }
+};
+
+// Base cases.
+template <>
+struct TuplePrefixPrinter<0> {
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
+
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
+};
+// We have to specialize the entire TuplePrefixPrinter<> class
+// template here, even though the definition of
+// TersePrintPrefixToStrings() is the same as the generic version, as
+// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
+// support specializing a method template of a class template.
+template <>
+struct TuplePrefixPrinter<1> {
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+    UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
+        Print(::std::tr1::get<0>(t), os);
+  }
+
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+    ::std::stringstream ss;
+    UniversalTersePrint(::std::tr1::get<0>(t), &ss);
+    strings->push_back(ss.str());
+  }
+};
+
+// Helper function for printing a tuple.  T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os) {
+  *os << "(";
+  TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
+      PrintPrefixTo(t, os);
+  *os << ")";
+}
+
+// Prints the fields of a tuple tersely to a string vector, one
+// element for each field.  See the comment before
+// UniversalTersePrint() for how we define "tersely".
+template <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
+  Strings result;
+  TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+      TersePrintPrefixToStrings(value, &result);
+  return result;
+}
+#endif  // GTEST_HAS_TR1_TUPLE
+
+}  // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value) {
+  ::std::stringstream ss;
+  internal::UniversalTersePrinter<T>::Print(value, &ss);
+  return ss.str();
+}
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
+                                          const char* file, int line);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+  virtual ~ParamIteratorInterface() {}
+  // A pointer to the base generator instance.
+  // Used only for the purposes of iterator comparison
+  // to make sure that two iterators belong to the same generator.
+  virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+  // Advances iterator to point to the next element
+  // provided by the generator. The caller is responsible
+  // for not calling Advance() on an iterator equal to
+  // BaseGenerator()->End().
+  virtual void Advance() = 0;
+  // Clones the iterator object. Used for implementing copy semantics
+  // of ParamIterator<T>.
+  virtual ParamIteratorInterface* Clone() const = 0;
+  // Dereferences the current iterator and provides (read-only) access
+  // to the pointed value. It is the caller's responsibility not to call
+  // Current() on an iterator equal to BaseGenerator()->End().
+  // Used for implementing ParamGenerator<T>::operator*().
+  virtual const T* Current() const = 0;
+  // Determines whether the given iterator and other point to the same
+  // element in the sequence generated by the generator.
+  // Used for implementing ParamGenerator<T>::operator==().
+  virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+  typedef T value_type;
+  typedef const T& reference;
+  typedef ptrdiff_t difference_type;
+
+  // ParamIterator assumes ownership of the impl_ pointer.
+  ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+  ParamIterator& operator=(const ParamIterator& other) {
+    if (this != &other)
+      impl_.reset(other.impl_->Clone());
+    return *this;
+  }
+
+  const T& operator*() const { return *impl_->Current(); }
+  const T* operator->() const { return impl_->Current(); }
+  // Prefix version of operator++.
+  ParamIterator& operator++() {
+    impl_->Advance();
+    return *this;
+  }
+  // Postfix version of operator++.
+  ParamIterator operator++(int /*unused*/) {
+    ParamIteratorInterface<T>* clone = impl_->Clone();
+    impl_->Advance();
+    return ParamIterator(clone);
+  }
+  bool operator==(const ParamIterator& other) const {
+    return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+  }
+  bool operator!=(const ParamIterator& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  friend class ParamGenerator<T>;
+  explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+  scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+  typedef T ParamType;
+
+  virtual ~ParamGeneratorInterface() {}
+
+  // Generator interface definition
+  virtual ParamIteratorInterface<T>* Begin() const = 0;
+  virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+  typedef ParamIterator<T> iterator;
+
+  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+  ParamGenerator& operator=(const ParamGenerator& other) {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+  iterator begin() const { return iterator(impl_->Begin()); }
+  iterator end() const { return iterator(impl_->End()); }
+
+ private:
+  linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  RangeGenerator(T begin, T end, IncrementT step)
+      : begin_(begin), end_(end),
+        step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+  virtual ~RangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, begin_, 0, step_);
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, end_, end_index_, step_);
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+             IncrementT step)
+        : base_(base), value_(value), index_(index), step_(step) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      value_ = value_ + step_;
+      index_++;
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const T* Current() const { return &value_; }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const int other_index =
+          CheckedDowncastToActualType<const Iterator>(&other)->index_;
+      return index_ == other_index;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : ParamIteratorInterface<T>(),
+          base_(other.base_), value_(other.value_), index_(other.index_),
+          step_(other.step_) {}
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<T>* const base_;
+    T value_;
+    int index_;
+    const IncrementT step_;
+  };  // class RangeGenerator::Iterator
+
+  static int CalculateEndIndex(const T& begin,
+                               const T& end,
+                               const IncrementT& step) {
+    int end_index = 0;
+    for (T i = begin; i < end; i = i + step)
+      end_index++;
+    return end_index;
+  }
+
+  // No implementation - assignment is unsupported.
+  void operator=(const RangeGenerator& other);
+
+  const T begin_;
+  const T end_;
+  const IncrementT step_;
+  // The index for the end() iterator. All the elements in the generated
+  // sequence are indexed (0-based) to aid iterator comparison.
+  const int end_index_;
+};  // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  template <typename ForwardIterator>
+  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+      : container_(begin, end) {}
+  virtual ~ValuesInIteratorRangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, container_.begin());
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, container_.end());
+  }
+
+ private:
+  typedef typename ::std::vector<T> ContainerType;
+
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base,
+             typename ContainerType::const_iterator iterator)
+        : base_(base), iterator_(iterator) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      ++iterator_;
+      value_.reset();
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    // We need to use cached value referenced by iterator_ because *iterator_
+    // can return a temporary object (and of type other then T), so just
+    // having "return &*iterator_;" doesn't work.
+    // value_ is updated here and not in Advance() because Advance()
+    // can advance iterator_ beyond the end of the range, and we cannot
+    // detect that fact. The client code, on the other hand, is
+    // responsible for not calling Current() on an out-of-range iterator.
+    virtual const T* Current() const {
+      if (value_.get() == NULL)
+        value_.reset(new T(*iterator_));
+      return value_.get();
+    }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      return iterator_ ==
+          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+          // The explicit constructor call suppresses a false warning
+          // emitted by gcc when supplied with the -Wextra option.
+        : ParamIteratorInterface<T>(),
+          base_(other.base_),
+          iterator_(other.iterator_) {}
+
+    const ParamGeneratorInterface<T>* const base_;
+    typename ContainerType::const_iterator iterator_;
+    // A cached value of *iterator_. We keep it here to allow access by
+    // pointer in the wrapping iterator's operator->().
+    // value_ needs to be mutable to be accessed in Current().
+    // Use of scoped_ptr helps manage cached value's lifetime,
+    // which is bound by the lifespan of the iterator itself.
+    mutable scoped_ptr<const T> value_;
+  };  // class ValuesInIteratorRangeGenerator::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const ValuesInIteratorRangeGenerator& other);
+
+  const ContainerType container_;
+};  // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+  typedef typename TestClass::ParamType ParamType;
+  explicit ParameterizedTestFactory(ParamType parameter) :
+      parameter_(parameter) {}
+  virtual Test* CreateTest() {
+    TestClass::SetParam(&parameter_);
+    return new TestClass();
+  }
+
+ private:
+  const ParamType parameter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+  virtual ~TestMetaFactoryBase() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+    : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+  typedef typename TestCase::ParamType ParamType;
+
+  TestMetaFactory() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+    return new ParameterizedTestFactory<TestCase>(parameter);
+  }
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+  virtual ~ParameterizedTestCaseInfoBase() {}
+
+  // Base part of test case name for display purposes.
+  virtual const string& GetTestCaseName() const = 0;
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const = 0;
+  // UnitTest class invokes this method to register tests in this
+  // test case right before running them in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  virtual void RegisterTests() = 0;
+
+ protected:
+  ParameterizedTestCaseInfoBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+  // ParamType and GeneratorCreationFunc are private types but are required
+  // for declarations of public methods AddTestPattern() and
+  // AddTestCaseInstantiation().
+  typedef typename TestCase::ParamType ParamType;
+  // A function that returns an instance of appropriate generator type.
+  typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+  explicit ParameterizedTestCaseInfo(const char* name)
+      : test_case_name_(name) {}
+
+  // Test case base name for display purposes.
+  virtual const string& GetTestCaseName() const { return test_case_name_; }
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+  // TEST_P macro uses AddTestPattern() to record information
+  // about a single test in a LocalTestInfo structure.
+  // test_case_name is the base name of the test case (without invocation
+  // prefix). test_base_name is the name of an individual test without
+  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+  // test case base name and DoBar is test base name.
+  void AddTestPattern(const char* test_case_name,
+                      const char* test_base_name,
+                      TestMetaFactoryBase<ParamType>* meta_factory) {
+    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+                                                       test_base_name,
+                                                       meta_factory)));
+  }
+  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+  // about a generator.
+  int AddTestCaseInstantiation(const string& instantiation_name,
+                               GeneratorCreationFunc* func,
+                               const char* /* file */,
+                               int /* line */) {
+    instantiations_.push_back(::std::make_pair(instantiation_name, func));
+    return 0;  // Return value used only to run this method in namespace scope.
+  }
+  // UnitTest class invokes this method to register tests in this test case
+  // test cases right before running tests in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  // UnitTest has a guard to prevent from calling this method more then once.
+  virtual void RegisterTests() {
+    for (typename TestInfoContainer::iterator test_it = tests_.begin();
+         test_it != tests_.end(); ++test_it) {
+      linked_ptr<TestInfo> test_info = *test_it;
+      for (typename InstantiationContainer::iterator gen_it =
+               instantiations_.begin(); gen_it != instantiations_.end();
+               ++gen_it) {
+        const string& instantiation_name = gen_it->first;
+        ParamGenerator<ParamType> generator((*gen_it->second)());
+
+        string test_case_name;
+        if ( !instantiation_name.empty() )
+          test_case_name = instantiation_name + "/";
+        test_case_name += test_info->test_case_base_name;
+
+        int i = 0;
+        for (typename ParamGenerator<ParamType>::iterator param_it =
+                 generator.begin();
+             param_it != generator.end(); ++param_it, ++i) {
+          Message test_name_stream;
+          test_name_stream << test_info->test_base_name << "/" << i;
+          MakeAndRegisterTestInfo(
+              test_case_name.c_str(),
+              test_name_stream.GetString().c_str(),
+              NULL,  // No type parameter.
+              PrintToString(*param_it).c_str(),
+              GetTestCaseTypeId(),
+              TestCase::SetUpTestCase,
+              TestCase::TearDownTestCase,
+              test_info->test_meta_factory->CreateTestFactory(*param_it));
+        }  // for param_it
+      }  // for gen_it
+    }  // for test_it
+  }  // RegisterTests
+
+ private:
+  // LocalTestInfo structure keeps information about a single test registered
+  // with TEST_P macro.
+  struct TestInfo {
+    TestInfo(const char* a_test_case_base_name,
+             const char* a_test_base_name,
+             TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
+        test_case_base_name(a_test_case_base_name),
+        test_base_name(a_test_base_name),
+        test_meta_factory(a_test_meta_factory) {}
+
+    const string test_case_base_name;
+    const string test_base_name;
+    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+  };
+  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+  // Keeps pairs of <Instantiation name, Sequence generator creation function>
+  // received from INSTANTIATE_TEST_CASE_P macros.
+  typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
+      InstantiationContainer;
+
+  const string test_case_name_;
+  TestInfoContainer tests_;
+  InstantiationContainer instantiations_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+};  // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+  ParameterizedTestCaseRegistry() {}
+  ~ParameterizedTestCaseRegistry() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      delete *it;
+    }
+  }
+
+  // Looks up or creates and returns a structure containing information about
+  // tests and instantiations of a particular test case.
+  template <class TestCase>
+  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+      const char* test_case_name,
+      const char* file,
+      int line) {
+    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      if ((*it)->GetTestCaseName() == test_case_name) {
+        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+          // Complain about incorrect usage of Google Test facilities
+          // and terminate the program since we cannot guaranty correct
+          // test case setup and tear-down in this case.
+          ReportInvalidTestCaseType(test_case_name,  file, line);
+          posix::Abort();
+        } else {
+          // At this point we are sure that the object we found is of the same
+          // type we are looking for, so we downcast it to that type
+          // without further checks.
+          typed_test_info = CheckedDowncastToActualType<
+              ParameterizedTestCaseInfo<TestCase> >(*it);
+        }
+        break;
+      }
+    }
+    if (typed_test_info == NULL) {
+      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+      test_case_infos_.push_back(typed_test_info);
+    }
+    return typed_test_info;
+  }
+  void RegisterTests() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      (*it)->RegisterTests();
+    }
+  }
+
+ private:
+  typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+  TestCaseInfoContainer test_case_infos_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+// This file was GENERATED by command:
+//     pump.py gtest-param-util-generated.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+  explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray1& other);
+
+  const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray2& other);
+
+  const T1 v1_;
+  const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+  ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray3& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+  ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray4& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+  ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray5& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class ValueArray6 {
+ public:
+  ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray6& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class ValueArray7 {
+ public:
+  ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray7& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+  ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+      T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray8& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+  ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+      T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray9& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+  ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray10& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+class ValueArray11 {
+ public:
+  ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray11& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+class ValueArray12 {
+ public:
+  ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray12& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+  ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray13& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+  ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray14& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+  ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray15& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+class ValueArray16 {
+ public:
+  ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray16& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+class ValueArray17 {
+ public:
+  ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+      T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray17& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+  ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray18& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+  ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray19& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+  ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray20& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+class ValueArray21 {
+ public:
+  ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray21& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+class ValueArray22 {
+ public:
+  ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray22& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+  ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray23& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+  ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray24& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+  ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+      T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray25& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+class ValueArray26 {
+ public:
+  ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray26& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+class ValueArray27 {
+ public:
+  ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray27& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+  ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray28& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+  ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray29& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+  ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray30& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+class ValueArray31 {
+ public:
+  ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray31& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+class ValueArray32 {
+ public:
+  ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray32& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+  ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+      T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray33& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+  ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray34& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+  ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray35& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+class ValueArray36 {
+ public:
+  ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray36& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+class ValueArray37 {
+ public:
+  ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray37& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+  ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray38& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+  ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray39& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+  ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray40& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+class ValueArray41 {
+ public:
+  ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+      T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray41& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+class ValueArray42 {
+ public:
+  ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray42& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+  ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+      v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray43& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+  ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+      v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+      v43_(v43), v44_(v44) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray44& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+  ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+      v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray45& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+class ValueArray46 {
+ public:
+  ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray46& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+class ValueArray47 {
+ public:
+  ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+      v47_(v47) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray47& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+  ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+      v46_(v46), v47_(v47), v48_(v48) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray48& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+  ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+      T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_), static_cast<T>(v49_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray49& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+  ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+      T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray50& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+  const T50 v50_;
+};
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+  CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2)
+      : g1_(g1), g2_(g2) {}
+  virtual ~CartesianProductGenerator2() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current2_;
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator2::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator2& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+};  // class CartesianProductGenerator2
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+  CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  virtual ~CartesianProductGenerator3() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current3_;
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator3::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator3& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+};  // class CartesianProductGenerator3
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+  CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  virtual ~CartesianProductGenerator4() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current4_;
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator4::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator4& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+};  // class CartesianProductGenerator4
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+  CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  virtual ~CartesianProductGenerator5() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current5_;
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator5::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator5& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+};  // class CartesianProductGenerator5
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class CartesianProductGenerator6
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+        T6> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+  CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  virtual ~CartesianProductGenerator6() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current6_;
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator6::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator6& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+};  // class CartesianProductGenerator6
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class CartesianProductGenerator7
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+  CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  virtual ~CartesianProductGenerator7() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current7_;
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator7::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator7& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+};  // class CartesianProductGenerator7
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+  CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  virtual ~CartesianProductGenerator8() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current8_;
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator8::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator8& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+};  // class CartesianProductGenerator8
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+  CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  virtual ~CartesianProductGenerator9() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current9_;
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator9::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator9& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+};  // class CartesianProductGenerator9
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9, T10> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+  CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+      const ParamGenerator<T10>& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  virtual ~CartesianProductGenerator10() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9,
+      const ParamGenerator<T10>& g10,
+      const typename ParamGenerator<T10>::iterator& current10)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+          begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current10_;
+      if (current10_ == end10_) {
+        current10_ = begin10_;
+        ++current9_;
+      }
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_ &&
+          current10_ == typed_other->current10_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_),
+        begin10_(other.begin10_),
+        end10_(other.end10_),
+        current10_(other.current10_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_, *current10_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_ ||
+          current10_ == end10_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    const typename ParamGenerator<T10>::iterator begin10_;
+    const typename ParamGenerator<T10>::iterator end10_;
+    typename ParamGenerator<T10>::iterator current10_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator10::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator10& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+  const ParamGenerator<T10> g10_;
+};  // class CartesianProductGenerator10
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+      : g1_(g1), g2_(g2) {}
+  template <typename T1, typename T2>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+        new CartesianProductGenerator2<T1, T2>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder2& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+};  // class CartesianProductHolder2
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  template <typename T1, typename T2, typename T3>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+        new CartesianProductGenerator3<T1, T2, T3>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder3& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+};  // class CartesianProductHolder3
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  template <typename T1, typename T2, typename T3, typename T4>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+        new CartesianProductGenerator4<T1, T2, T3, T4>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder4& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+};  // class CartesianProductHolder4
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+        new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder5& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+};  // class CartesianProductHolder5
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+        new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder6& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+};  // class CartesianProductHolder6
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+      T7> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+        new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder7& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+};  // class CartesianProductHolder7
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+      T8> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+        new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder8& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+};  // class CartesianProductHolder8
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9> >(
+        new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder9& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+};  // class CartesianProductHolder9
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9, const Generator10& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9, typename T10>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9, T10> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9, T10> >(
+        new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+            T10>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_),
+        static_cast<ParamGenerator<T10> >(g10_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder10& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+  const Generator10 g10_;
+};  // class CartesianProductHolder10
+
+# endif  // GTEST_HAS_COMBINE
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+//   - returns a generator producing a sequence of values {start, start+1,
+//     start+2, ..., }.
+// Range(start, end, step)
+//   - returns a generator producing a sequence of values {start, start+step,
+//     start+step+step, ..., }.
+// Notes:
+//   * The generated sequences never include end. For example, Range(1, 5)
+//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+//     returns a generator producing {1, 3, 5, 7}.
+//   * start and end must have the same type. That type may be any integral or
+//     floating-point type or a user defined type satisfying these conditions:
+//     * It must be assignable (have operator=() defined).
+//     * It must have operator+() (operator+(int-compatible type) for
+//       two-operand version).
+//     * It must have operator<() defined.
+//     Elements in the resulting sequences will also have that type.
+//   * Condition start < end must be satisfied in order for resulting sequences
+//     to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+  return internal::ParamGenerator<T>(
+      new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+  return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+//   - returns a generator producing sequences with elements from
+//     a C-style array.
+// ValuesIn(const Container& container)
+//   - returns a generator producing sequences with elements from
+//     an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+//   - returns a generator producing sequences with elements from
+//     a range [begin, end) defined by a pair of STL-style iterators. These
+//     iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+//   ::std::vector< ::std::string> v;
+//   v.push_back("a");
+//   v.push_back("b");
+//   return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+//                         StlStringTest,
+//                         ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+//   ::std::list<char> list;
+//   list.push_back('a');
+//   list.push_back('b');
+//   return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+//                         CharTest,
+//                         ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+      ::value_type ParamType;
+  return internal::ParamGenerator<ParamType>(
+      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+  return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container) {
+  return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+//   - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+  return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+  return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+  return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+  return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5) {
+  return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6) {
+  return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7) {
+  return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+      v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+  return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+      v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+  return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+  return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+    T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11) {
+  return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+      T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+    T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12) {
+  return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13) {
+  return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+  return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+  return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16) {
+  return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17) {
+  return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18) {
+  return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+  return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+  return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+  return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22) {
+  return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23) {
+  return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24) {
+  return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+  return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+    T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26) {
+  return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+    T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27) {
+  return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+    T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28) {
+  return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29) {
+  return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+  return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+  return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32) {
+  return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33) {
+  return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34) {
+  return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+  return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+  return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37) {
+  return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38) {
+  return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+      v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38, T39 v39) {
+  return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+      v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+    T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+    T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+  return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+      v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+    T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+  return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+      v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+    T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42) {
+  return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+      v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+    T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43) {
+  return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+      v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43, T44 v44) {
+  return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+      v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+    T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+    T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+  return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+      v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+  return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+  return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+    T48 v48) {
+  return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+      v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+    T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+    T47 v47, T48 v48, T49 v49) {
+  return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+      v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+    T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+    T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+  return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+      v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+//   - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+//   virtual void SetUp() {
+//     external_flag = GetParam();
+//   }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+  return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+//   - returns a generator producing sequences with elements coming from
+//     the Cartesian product of elements from the sequences generated by
+//     gen1, gen2, ..., genN. The sequence elements will have a type of
+//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+//     of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+//     : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+//                         Combine(Values("cat", "dog"),
+//                                 Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+//     : public testing::TestWithParam<tuple<bool, bool> > {
+//   virtual void SetUp() {
+//     // Assigns external_flag_1 and external_flag_2 values from the tuple.
+//     tie(external_flag_1, external_flag_2) = GetParam();
+//   }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+//   // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+//                         Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+    const Generator1& g1, const Generator2& g2) {
+  return internal::CartesianProductHolder2<Generator1, Generator2>(
+      g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+  return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+      g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+    Generator4> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4) {
+  return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+      Generator4>(
+      g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+    Generator4, Generator5> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5) {
+  return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+      Generator4, Generator5>(
+      g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+  return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6>(
+      g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7) {
+  return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7>(
+      g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8) {
+  return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8>(
+      g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8,
+    Generator9> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+  return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9,
+    typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+    Generator10> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9,
+        const Generator10& g10) {
+  return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+      Generator10>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+# endif  // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+      : public test_case_name { \
+   public: \
+    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+    virtual void TestBody(); \
+   private: \
+    static int AddToRegistry() { \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+                  #test_case_name, \
+                  #test_name, \
+                  new ::testing::internal::TestMetaFactory< \
+                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+      return 0; \
+    } \
+    static int gtest_registering_dummy_; \
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+  }; \
+  int GTEST_TEST_CLASS_NAME_(test_case_name, \
+                             test_name)::gtest_registering_dummy_ = \
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+  ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+  int gtest_##prefix##test_case_name##_dummy_ = \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+                  #prefix, \
+                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
+                  __FILE__, __LINE__)
+
+}  // namespace testing
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class.  For example:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+//   // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+//   // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+  // The possible outcomes of a test part (i.e. an assertion or an
+  // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+  enum Type {
+    kSuccess,          // Succeeded.
+    kNonFatalFailure,  // Failed but the test can continue.
+    kFatalFailure      // Failed and the test should be terminated.
+  };
+
+  // C'tor.  TestPartResult does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestPartResult object.
+  TestPartResult(Type a_type,
+                 const char* a_file_name,
+                 int a_line_number,
+                 const char* a_message)
+      : type_(a_type),
+        file_name_(a_file_name == NULL ? "" : a_file_name),
+        line_number_(a_line_number),
+        summary_(ExtractSummary(a_message)),
+        message_(a_message) {
+  }
+
+  // Gets the outcome of the test part.
+  Type type() const { return type_; }
+
+  // Gets the name of the source file where the test part took place, or
+  // NULL if it's unknown.
+  const char* file_name() const {
+    return file_name_.empty() ? NULL : file_name_.c_str();
+  }
+
+  // Gets the line in the source file where the test part took place,
+  // or -1 if it's unknown.
+  int line_number() const { return line_number_; }
+
+  // Gets the summary of the failure message.
+  const char* summary() const { return summary_.c_str(); }
+
+  // Gets the message associated with the test part.
+  const char* message() const { return message_.c_str(); }
+
+  // Returns true iff the test part passed.
+  bool passed() const { return type_ == kSuccess; }
+
+  // Returns true iff the test part failed.
+  bool failed() const { return type_ != kSuccess; }
+
+  // Returns true iff the test part non-fatally failed.
+  bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+  // Returns true iff the test part fatally failed.
+  bool fatally_failed() const { return type_ == kFatalFailure; }
+
+ private:
+  Type type_;
+
+  // Gets the summary of the failure message by omitting the stack
+  // trace in it.
+  static std::string ExtractSummary(const char* message);
+
+  // The name of the source file where the test part took place, or
+  // "" if the source file is unknown.
+  std::string file_name_;
+  // The line in the source file where the test part took place, or -1
+  // if the line number is unknown.
+  int line_number_;
+  std::string summary_;  // The test failure summary.
+  std::string message_;  // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+  TestPartResultArray() {}
+
+  // Appends the given TestPartResult to the array.
+  void Append(const TestPartResult& result);
+
+  // Returns the TestPartResult at the given index (0-based).
+  const TestPartResult& GetTestPartResult(int index) const;
+
+  // Returns the number of TestPartResult objects in the array.
+  int size() const;
+
+ private:
+  std::vector<TestPartResult> array_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+  virtual ~TestPartResultReporterInterface() {}
+
+  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+    : public TestPartResultReporterInterface {
+ public:
+  HasNewFatalFailureHelper();
+  virtual ~HasNewFatalFailureHelper();
+  virtual void ReportTestPartResult(const TestPartResult& result);
+  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+  bool has_new_fatal_failure_;
+  TestPartResultReporterInterface* original_reporter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list.  You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+  ...
+  typedef std::list<T> List;
+  static T shared_;
+  T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list.  The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  // Since we are inside a derived class template, C++ requires use to
+  // visit the members of FooTest via 'this'.
+  TypeParam n = this->value_;
+
+  // To visit static members of the fixture, add the TestFixture::
+  // prefix.
+  n += TestFixture::shared_;
+
+  // To refer to typedefs in the fixture, add the "typename
+  // TestFixture::" prefix.
+  typename TestFixture::List values;
+  values.push_back(n);
+  ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif  // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type.  Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are.  The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have.  Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly.  Here's an example:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+  ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  TypeParam n = 0;
+  ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them.  The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+                           DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want.  If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name.  Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif  // 0
+
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define TYPED_TEST_CASE(CaseName, Types) \
+  typedef ::testing::internal::TypeList< Types >::type \
+      GTEST_TYPE_PARAMS_(CaseName)
+
+# define TYPED_TEST(CaseName, TestName) \
+  template <typename gtest_TypeParam_> \
+  class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+      : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
+      ::testing::internal::TypeParameterizedTest< \
+          CaseName, \
+          ::testing::internal::TemplateSel< \
+              GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+          GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+              "", #CaseName, #TestName, 0); \
+  template <typename gtest_TypeParam_> \
+  void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif  // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in.  The exact
+// name of the namespace is subject to change without notice.
+# define GTEST_CASE_NAMESPACE_(TestCaseName) \
+  gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+  gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+  gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+# define TYPED_TEST_CASE_P(CaseName) \
+  static ::testing::internal::TypedTestCasePState \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+# define TYPED_TEST_P(CaseName, TestName) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  template <typename gtest_TypeParam_> \
+  class TestName : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+          __FILE__, __LINE__, #CaseName, #TestName); \
+  } \
+  template <typename gtest_TypeParam_> \
+  void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+  } \
+  static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+          __FILE__, __LINE__, #__VA_ARGS__)
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+  bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
+      ::testing::internal::TypeParameterizedTestCase<CaseName, \
+          GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+          ::testing::internal::TypeList< Types >::type>::Register(\
+              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// Depending on the platform, different string classes are available.
+// On Linux, in addition to ::std::string, Google also makes use of
+// class ::string, which has the same interface as ::std::string, but
+// has a different implementation.
+//
+// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// ::string is available AND is a distinct type to ::std::string, or
+// define it to 0 to indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// heuristically.
+
+namespace testing {
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// When this flag is set with a "host:port" string, on supported
+// platforms test results are streamed to the specified port on
+// the specified host machine.
+GTEST_DECLARE_string_(stream_result_to);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class StreamingListenerTest;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class UnitTestRecordPropertyTestHelper;
+class WindowsDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+                                    const std::string& message);
+
+}  // namespace internal
+
+// The friend relationship of some of these classes is cyclic.
+// If we don't forward declare them the compiler might confuse the classes
+// in friendship clauses with same named classes on the scope.
+class Test;
+class TestCase;
+class TestInfo;
+class UnitTest;
+
+// A class for indicating whether an assertion was successful.  When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+//   1. Defining predicate functions to be used with Boolean test assertions
+//      EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+//   2. Defining predicate-format functions to be
+//      used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+//   testing::AssertionResult IsEven(int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess();
+//     else
+//       return testing::AssertionFailure() << n << " is odd";
+//   }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+//   Value of: IsEven(Fib(5))
+//     Actual: false (5 is odd)
+//   Expected: true
+//
+// instead of a more opaque
+//
+//   Value of: IsEven(Fib(5))
+//     Actual: false
+//   Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+//   testing::AssertionResult IsEven(int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess() << n << " is even";
+//     else
+//       return testing::AssertionFailure() << n << " is odd";
+//   }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+//   Value of: IsEven(Fib(6))
+//     Actual: true (8 is even)
+//   Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+//   // Verifies that Foo() returns an even number.
+//   EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+//   testing::AssertionResult IsEven(const char* expr, int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess();
+//     else
+//       return testing::AssertionFailure()
+//         << "Expected: " << expr << " is even\n  Actual: it's " << n;
+//   }
+//
+// If Foo() returns 5, you will see the following message:
+//
+//   Expected: Foo() is even
+//     Actual: it's 5
+//
+class GTEST_API_ AssertionResult {
+ public:
+  // Copy constructor.
+  // Used in EXPECT_TRUE/FALSE(assertion_result).
+  AssertionResult(const AssertionResult& other);
+  // Used in the EXPECT_TRUE/FALSE(bool_expression).
+  explicit AssertionResult(bool success) : success_(success) {}
+
+  // Returns true iff the assertion succeeded.
+  operator bool() const { return success_; }  // NOLINT
+
+  // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+  AssertionResult operator!() const;
+
+  // Returns the text streamed into this AssertionResult. Test assertions
+  // use it when they fail (i.e., the predicate's outcome doesn't match the
+  // assertion's expectation). When nothing has been streamed into the
+  // object, returns an empty string.
+  const char* message() const {
+    return message_.get() != NULL ?  message_->c_str() : "";
+  }
+  // TODO(vladl@google.com): Remove this after making sure no clients use it.
+  // Deprecated; please use message() instead.
+  const char* failure_message() const { return message(); }
+
+  // Streams a custom failure message into this object.
+  template <typename T> AssertionResult& operator<<(const T& value) {
+    AppendMessage(Message() << value);
+    return *this;
+  }
+
+  // Allows streaming basic output manipulators such as endl or flush into
+  // this object.
+  AssertionResult& operator<<(
+      ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
+    AppendMessage(Message() << basic_manipulator);
+    return *this;
+  }
+
+ private:
+  // Appends the contents of message to message_.
+  void AppendMessage(const Message& a_message) {
+    if (message_.get() == NULL)
+      message_.reset(new ::std::string);
+    message_->append(a_message.GetString().c_str());
+  }
+
+  // Stores result of the assertion predicate.
+  bool success_;
+  // Stores the message describing the condition in case the expectation
+  // construct is not satisfied with the predicate's outcome.
+  // Referenced via a pointer to avoid taking too much stack frame space
+  // with test assertions.
+  internal::scoped_ptr< ::std::string> message_;
+
+  GTEST_DISALLOW_ASSIGN_(AssertionResult);
+};
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F.  For example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { ... }
+//     virtual void TearDown() { ... }
+//     ...
+//   };
+//
+//   TEST_F(FooTest, Bar) { ... }
+//   TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+  friend class TestInfo;
+
+  // Defines types for pointers to functions that set up and tear down
+  // a test case.
+  typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+  typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+  // The d'tor is virtual as we intend to inherit from Test.
+  virtual ~Test();
+
+  // Sets up the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::SetUpTestCase() before running the first
+  // test in test case Foo.  Hence a sub-class can define its own
+  // SetUpTestCase() method to shadow the one defined in the super
+  // class.
+  static void SetUpTestCase() {}
+
+  // Tears down the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::TearDownTestCase() after running the last
+  // test in test case Foo.  Hence a sub-class can define its own
+  // TearDownTestCase() method to shadow the one defined in the super
+  // class.
+  static void TearDownTestCase() {}
+
+  // Returns true iff the current test has a fatal failure.
+  static bool HasFatalFailure();
+
+  // Returns true iff the current test has a non-fatal failure.
+  static bool HasNonfatalFailure();
+
+  // Returns true iff the current test has a (either fatal or
+  // non-fatal) failure.
+  static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+  // Logs a property for the current test, test case, or for the entire
+  // invocation of the test program when used outside of the context of a
+  // test case.  Only the last value for a given key is remembered.  These
+  // are public static so they can be called from utility functions that are
+  // not members of the test fixture.  Calls to RecordProperty made during
+  // lifespan of the test (from the moment its constructor starts to the
+  // moment its destructor finishes) will be output in XML as attributes of
+  // the <testcase> element.  Properties recorded from fixture's
+  // SetUpTestCase or TearDownTestCase are logged as attributes of the
+  // corresponding <testsuite> element.  Calls to RecordProperty made in the
+  // global context (before or after invocation of RUN_ALL_TESTS and from
+  // SetUp/TearDown method of Environment objects registered with Google
+  // Test) will be output as attributes of the <testsuites> element.
+  static void RecordProperty(const std::string& key, const std::string& value);
+  static void RecordProperty(const std::string& key, int value);
+
+ protected:
+  // Creates a Test object.
+  Test();
+
+  // Sets up the test fixture.
+  virtual void SetUp();
+
+  // Tears down the test fixture.
+  virtual void TearDown();
+
+ private:
+  // Returns true iff the current test has the same fixture class as
+  // the first test in the current test case.
+  static bool HasSameFixtureClass();
+
+  // Runs the test after the test fixture has been set up.
+  //
+  // A sub-class must implement this to define the test logic.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+  // Instead, use the TEST or TEST_F macro.
+  virtual void TestBody() = 0;
+
+  // Sets up, executes, and tears down the test.
+  void Run();
+
+  // Deletes self.  We deliberately pick an unusual name for this
+  // internal method to avoid clashing with names used in user TESTs.
+  void DeleteSelf_() { delete this; }
+
+  // Uses a GTestFlagSaver to save and restore all Google Test flags.
+  const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+  // Often a user mis-spells SetUp() as Setup() and spends a long time
+  // wondering why it is never called by Google Test.  The declaration of
+  // the following method is solely for catching such an error at
+  // compile time:
+  //
+  //   - The return type is deliberately chosen to be not void, so it
+  //   will be a conflict if a user declares void Setup() in his test
+  //   fixture.
+  //
+  //   - This method is private, so it will be another compiler error
+  //   if a user calls it from his test fixture.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION.
+  //
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+  // We disallow copying Tests.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+  // C'tor.  TestProperty does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestProperty object.
+  TestProperty(const std::string& a_key, const std::string& a_value) :
+    key_(a_key), value_(a_value) {
+  }
+
+  // Gets the user supplied key.
+  const char* key() const {
+    return key_.c_str();
+  }
+
+  // Gets the user supplied value.
+  const char* value() const {
+    return value_.c_str();
+  }
+
+  // Sets a new value, overriding the one supplied in the constructor.
+  void SetValue(const std::string& new_value) {
+    value_ = new_value;
+  }
+
+ private:
+  // The key supplied by the user.
+  std::string key_;
+  // The value supplied by the user.
+  std::string value_;
+};
+
+// The result of a single Test.  This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult {
+ public:
+  // Creates an empty TestResult.
+  TestResult();
+
+  // D'tor.  Do not inherit from TestResult.
+  ~TestResult();
+
+  // Gets the number of all test parts.  This is the sum of the number
+  // of successful test parts and the number of failed test parts.
+  int total_part_count() const;
+
+  // Returns the number of the test properties.
+  int test_property_count() const;
+
+  // Returns true iff the test passed (i.e. no test part failed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test failed.
+  bool Failed() const;
+
+  // Returns true iff the test fatally failed.
+  bool HasFatalFailure() const;
+
+  // Returns true iff the test has a non-fatal failure.
+  bool HasNonfatalFailure() const;
+
+  // Returns the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns the i-th test part result among all the results. i can range
+  // from 0 to test_property_count() - 1. If i is not in that range, aborts
+  // the program.
+  const TestPartResult& GetTestPartResult(int i) const;
+
+  // Returns the i-th test property. i can range from 0 to
+  // test_property_count() - 1. If i is not in that range, aborts the
+  // program.
+  const TestProperty& GetTestProperty(int i) const;
+
+ private:
+  friend class TestInfo;
+  friend class TestCase;
+  friend class UnitTest;
+  friend class internal::DefaultGlobalTestPartResultReporter;
+  friend class internal::ExecDeathTest;
+  friend class internal::TestResultAccessor;
+  friend class internal::UnitTestImpl;
+  friend class internal::WindowsDeathTest;
+
+  // Gets the vector of TestPartResults.
+  const std::vector<TestPartResult>& test_part_results() const {
+    return test_part_results_;
+  }
+
+  // Gets the vector of TestProperties.
+  const std::vector<TestProperty>& test_properties() const {
+    return test_properties_;
+  }
+
+  // Sets the elapsed time.
+  void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+  // Adds a test property to the list. The property is validated and may add
+  // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+  // key names). If a property is already recorded for the same key, the
+  // value will be updated, rather than storing multiple values for the same
+  // key.  xml_element specifies the element for which the property is being
+  // recorded and is used for validation.
+  void RecordProperty(const std::string& xml_element,
+                      const TestProperty& test_property);
+
+  // Adds a failure if the key is a reserved attribute of Google Test
+  // testcase tags.  Returns true if the property is valid.
+  // TODO(russr): Validate attribute names are legal and human readable.
+  static bool ValidateTestProperty(const std::string& xml_element,
+                                   const TestProperty& test_property);
+
+  // Adds a test part result to the list.
+  void AddTestPartResult(const TestPartResult& test_part_result);
+
+  // Returns the death test count.
+  int death_test_count() const { return death_test_count_; }
+
+  // Increments the death test count, returning the new count.
+  int increment_death_test_count() { return ++death_test_count_; }
+
+  // Clears the test part results.
+  void ClearTestPartResults();
+
+  // Clears the object.
+  void Clear();
+
+  // Protects mutable state of the property vector and of owned
+  // properties, whose values may be updated.
+  internal::Mutex test_properites_mutex_;
+
+  // The vector of TestPartResults
+  std::vector<TestPartResult> test_part_results_;
+  // The vector of TestProperties
+  std::vector<TestProperty> test_properties_;
+  // Running count of death tests.
+  int death_test_count_;
+  // The elapsed time, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+  // We disallow copying TestResult.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+};  // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+//   Test case name
+//   Test name
+//   Whether the test should be run
+//   A function pointer that creates the test object when invoked
+//   Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo {
+ public:
+  // Destructs a TestInfo object.  This function is not virtual, so
+  // don't inherit from TestInfo.
+  ~TestInfo();
+
+  // Returns the test case name.
+  const char* test_case_name() const { return test_case_name_.c_str(); }
+
+  // Returns the test name.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the name of the parameter type, or NULL if this is not a typed
+  // or a type-parameterized test.
+  const char* type_param() const {
+    if (type_param_.get() != NULL)
+      return type_param_->c_str();
+    return NULL;
+  }
+
+  // Returns the text representation of the value parameter, or NULL if this
+  // is not a value-parameterized test.
+  const char* value_param() const {
+    if (value_param_.get() != NULL)
+      return value_param_->c_str();
+    return NULL;
+  }
+
+  // Returns true if this test should run, that is if the test is not
+  // disabled (or it is disabled but the also_run_disabled_tests flag has
+  // been specified) and its full name matches the user-specified filter.
+  //
+  // Google Test allows the user to filter the tests by their full names.
+  // The full name of a test Bar in test case Foo is defined as
+  // "Foo.Bar".  Only the tests that match the filter will run.
+  //
+  // A filter is a colon-separated list of glob (not regex) patterns,
+  // optionally followed by a '-' and a colon-separated list of
+  // negative patterns (tests to exclude).  A test is run if it
+  // matches one of the positive patterns and does not match any of
+  // the negative patterns.
+  //
+  // For example, *A*:Foo.* is a filter that matches any string that
+  // contains the character 'A' or starts with "Foo.".
+  bool should_run() const { return should_run_; }
+
+  // Returns true iff this test will appear in the XML report.
+  bool is_reportable() const {
+    // For now, the XML report includes all tests matching the filter.
+    // In the future, we may trim tests that are excluded because of
+    // sharding.
+    return matches_filter_;
+  }
+
+  // Returns the result of the test.
+  const TestResult* result() const { return &result_; }
+
+ private:
+#if GTEST_HAS_DEATH_TEST
+  friend class internal::DefaultDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+  friend class Test;
+  friend class TestCase;
+  friend class internal::UnitTestImpl;
+  friend class internal::StreamingListenerTest;
+  friend TestInfo* internal::MakeAndRegisterTestInfo(
+      const char* test_case_name,
+      const char* name,
+      const char* type_param,
+      const char* value_param,
+      internal::TypeId fixture_class_id,
+      Test::SetUpTestCaseFunc set_up_tc,
+      Test::TearDownTestCaseFunc tear_down_tc,
+      internal::TestFactoryBase* factory);
+
+  // Constructs a TestInfo object. The newly constructed instance assumes
+  // ownership of the factory object.
+  TestInfo(const std::string& test_case_name,
+           const std::string& name,
+           const char* a_type_param,   // NULL if not a type-parameterized test
+           const char* a_value_param,  // NULL if not a value-parameterized test
+           internal::TypeId fixture_class_id,
+           internal::TestFactoryBase* factory);
+
+  // Increments the number of death tests encountered in this test so
+  // far.
+  int increment_death_test_count() {
+    return result_.increment_death_test_count();
+  }
+
+  // Creates the test object, runs it, records its result, and then
+  // deletes it.
+  void Run();
+
+  static void ClearTestResult(TestInfo* test_info) {
+    test_info->result_.Clear();
+  }
+
+  // These fields are immutable properties of the test.
+  const std::string test_case_name_;     // Test case name
+  const std::string name_;               // Test name
+  // Name of the parameter type, or NULL if this is not a typed or a
+  // type-parameterized test.
+  const internal::scoped_ptr<const ::std::string> type_param_;
+  // Text representation of the value parameter, or NULL if this is not a
+  // value-parameterized test.
+  const internal::scoped_ptr<const ::std::string> value_param_;
+  const internal::TypeId fixture_class_id_;   // ID of the test fixture class
+  bool should_run_;                 // True iff this test should run
+  bool is_disabled_;                // True iff this test is disabled
+  bool matches_filter_;             // True if this test matches the
+                                    // user-specified filter.
+  internal::TestFactoryBase* const factory_;  // The factory that creates
+                                              // the test object
+
+  // This field is mutable and needs to be reset before running the
+  // test for the second time.
+  TestResult result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test case, which consists of a vector of TestInfos.
+//
+// TestCase is not copyable.
+class GTEST_API_ TestCase {
+ public:
+  // Creates a TestCase with the given name.
+  //
+  // TestCase does NOT have a default constructor.  Always use this
+  // constructor to create a TestCase object.
+  //
+  // Arguments:
+  //
+  //   name:         name of the test case
+  //   a_type_param: the name of the test's type parameter, or NULL if
+  //                 this is not a type-parameterized test.
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  TestCase(const char* name, const char* a_type_param,
+           Test::SetUpTestCaseFunc set_up_tc,
+           Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Destructor of TestCase.
+  virtual ~TestCase();
+
+  // Gets the name of the TestCase.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the name of the parameter type, or NULL if this is not a
+  // type-parameterized test case.
+  const char* type_param() const {
+    if (type_param_.get() != NULL)
+      return type_param_->c_str();
+    return NULL;
+  }
+
+  // Returns true if any test in this test case should run.
+  bool should_run() const { return should_run_; }
+
+  // Gets the number of successful tests in this test case.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests in this test case.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests in this test case.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Get the number of tests in this test case that should run.
+  int test_to_run_count() const;
+
+  // Gets the number of all tests in this test case.
+  int total_test_count() const;
+
+  // Returns true iff the test case passed.
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test case failed.
+  bool Failed() const { return failed_test_count() > 0; }
+
+  // Returns the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns the i-th test among all the tests. i can range from 0 to
+  // total_test_count() - 1. If i is not in that range, returns NULL.
+  const TestInfo* GetTestInfo(int i) const;
+
+  // Returns the TestResult that holds test properties recorded during
+  // execution of SetUpTestCase and TearDownTestCase.
+  const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
+
+ private:
+  friend class Test;
+  friend class internal::UnitTestImpl;
+
+  // Gets the (mutable) vector of TestInfos in this TestCase.
+  std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+  // Gets the (immutable) vector of TestInfos in this TestCase.
+  const std::vector<TestInfo*>& test_info_list() const {
+    return test_info_list_;
+  }
+
+  // Returns the i-th test among all the tests. i can range from 0 to
+  // total_test_count() - 1. If i is not in that range, returns NULL.
+  TestInfo* GetMutableTestInfo(int i);
+
+  // Sets the should_run member.
+  void set_should_run(bool should) { should_run_ = should; }
+
+  // Adds a TestInfo to this test case.  Will delete the TestInfo upon
+  // destruction of the TestCase object.
+  void AddTestInfo(TestInfo * test_info);
+
+  // Clears the results of all tests in this test case.
+  void ClearResult();
+
+  // Clears the results of all tests in the given test case.
+  static void ClearTestCaseResult(TestCase* test_case) {
+    test_case->ClearResult();
+  }
+
+  // Runs every test in this TestCase.
+  void Run();
+
+  // Runs SetUpTestCase() for this TestCase.  This wrapper is needed
+  // for catching exceptions thrown from SetUpTestCase().
+  void RunSetUpTestCase() { (*set_up_tc_)(); }
+
+  // Runs TearDownTestCase() for this TestCase.  This wrapper is
+  // needed for catching exceptions thrown from TearDownTestCase().
+  void RunTearDownTestCase() { (*tear_down_tc_)(); }
+
+  // Returns true iff test passed.
+  static bool TestPassed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Passed();
+  }
+
+  // Returns true iff test failed.
+  static bool TestFailed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Failed();
+  }
+
+  // Returns true iff the test is disabled and will be reported in the XML
+  // report.
+  static bool TestReportableDisabled(const TestInfo* test_info) {
+    return test_info->is_reportable() && test_info->is_disabled_;
+  }
+
+  // Returns true iff test is disabled.
+  static bool TestDisabled(const TestInfo* test_info) {
+    return test_info->is_disabled_;
+  }
+
+  // Returns true iff this test will appear in the XML report.
+  static bool TestReportable(const TestInfo* test_info) {
+    return test_info->is_reportable();
+  }
+
+  // Returns true if the given test should run.
+  static bool ShouldRunTest(const TestInfo* test_info) {
+    return test_info->should_run();
+  }
+
+  // Shuffles the tests in this test case.
+  void ShuffleTests(internal::Random* random);
+
+  // Restores the test order to before the first shuffle.
+  void UnshuffleTests();
+
+  // Name of the test case.
+  std::string name_;
+  // Name of the parameter type, or NULL if this is not a typed or a
+  // type-parameterized test.
+  const internal::scoped_ptr<const ::std::string> type_param_;
+  // The vector of TestInfos in their original order.  It owns the
+  // elements in the vector.
+  std::vector<TestInfo*> test_info_list_;
+  // Provides a level of indirection for the test list to allow easy
+  // shuffling and restoring the test order.  The i-th element in this
+  // vector is the index of the i-th test in the shuffled test list.
+  std::vector<int> test_indices_;
+  // Pointer to the function that sets up the test case.
+  Test::SetUpTestCaseFunc set_up_tc_;
+  // Pointer to the function that tears down the test case.
+  Test::TearDownTestCaseFunc tear_down_tc_;
+  // True iff any test in this test case should run.
+  bool should_run_;
+  // Elapsed time, in milliseconds.
+  TimeInMillis elapsed_time_;
+  // Holds test properties recorded during execution of SetUpTestCase and
+  // TearDownTestCase.
+  TestResult ad_hoc_test_result_;
+
+  // We disallow copying TestCases.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment.  The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+//   1. You cannot safely throw from a destructor.  This is a problem
+//      as in some cases Google Test is used where exceptions are enabled, and
+//      we may want to implement ASSERT_* using exceptions where they are
+//      available.
+//   2. You cannot use ASSERT_* directly in a constructor or
+//      destructor.
+class Environment {
+ public:
+  // The d'tor is virtual as we need to subclass Environment.
+  virtual ~Environment() {}
+
+  // Override this to define how to set up the environment.
+  virtual void SetUp() {}
+
+  // Override this to define how to tear down the environment.
+  virtual void TearDown() {}
+ private:
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener {
+ public:
+  virtual ~TestEventListener() {}
+
+  // Fired before any test activity starts.
+  virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+  // Fired before each iteration of tests starts.  There may be more than
+  // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+  // index, starting from 0.
+  virtual void OnTestIterationStart(const UnitTest& unit_test,
+                                    int iteration) = 0;
+
+  // Fired before environment set-up for each iteration of tests starts.
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+  // Fired after environment set-up for each iteration of tests ends.
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+  // Fired before the test case starts.
+  virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+
+  // Fired before the test starts.
+  virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+  // Fired after a failed assertion or a SUCCEED() invocation.
+  virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+  // Fired after the test ends.
+  virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+  // Fired after the test case ends.
+  virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+
+  // Fired before environment tear-down for each iteration of tests starts.
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+  // Fired after environment tear-down for each iteration of tests ends.
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+  // Fired after each iteration of tests finishes.
+  virtual void OnTestIterationEnd(const UnitTest& unit_test,
+                                  int iteration) = 0;
+
+  // Fired after all test activities have ended.
+  virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build.  For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener {
+ public:
+  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+                                    int /*iteration*/) {}
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+  virtual void OnTestStart(const TestInfo& /*test_info*/) {}
+  virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
+  virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
+  virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+                                  int /*iteration*/) {}
+  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners {
+ public:
+  TestEventListeners();
+  ~TestEventListeners();
+
+  // Appends an event listener to the end of the list. Google Test assumes
+  // the ownership of the listener (i.e. it will delete the listener when
+  // the test program finishes).
+  void Append(TestEventListener* listener);
+
+  // Removes the given event listener from the list and returns it.  It then
+  // becomes the caller's responsibility to delete the listener. Returns
+  // NULL if the listener is not found in the list.
+  TestEventListener* Release(TestEventListener* listener);
+
+  // Returns the standard listener responsible for the default console
+  // output.  Can be removed from the listeners list to shut down default
+  // console output.  Note that removing this object from the listener list
+  // with Release transfers its ownership to the caller and makes this
+  // function return NULL the next time.
+  TestEventListener* default_result_printer() const {
+    return default_result_printer_;
+  }
+
+  // Returns the standard listener responsible for the default XML output
+  // controlled by the --gtest_output=xml flag.  Can be removed from the
+  // listeners list by users who want to shut down the default XML output
+  // controlled by this flag and substitute it with custom one.  Note that
+  // removing this object from the listener list with Release transfers its
+  // ownership to the caller and makes this function return NULL the next
+  // time.
+  TestEventListener* default_xml_generator() const {
+    return default_xml_generator_;
+  }
+
+ private:
+  friend class TestCase;
+  friend class TestInfo;
+  friend class internal::DefaultGlobalTestPartResultReporter;
+  friend class internal::NoExecDeathTest;
+  friend class internal::TestEventListenersAccessor;
+  friend class internal::UnitTestImpl;
+
+  // Returns repeater that broadcasts the TestEventListener events to all
+  // subscribers.
+  TestEventListener* repeater();
+
+  // Sets the default_result_printer attribute to the provided listener.
+  // The listener is also added to the listener list and previous
+  // default_result_printer is removed from it and deleted. The listener can
+  // also be NULL in which case it will not be added to the list. Does
+  // nothing if the previous and the current listener objects are the same.
+  void SetDefaultResultPrinter(TestEventListener* listener);
+
+  // Sets the default_xml_generator attribute to the provided listener.  The
+  // listener is also added to the listener list and previous
+  // default_xml_generator is removed from it and deleted. The listener can
+  // also be NULL in which case it will not be added to the list. Does
+  // nothing if the previous and the current listener objects are the same.
+  void SetDefaultXmlGenerator(TestEventListener* listener);
+
+  // Controls whether events will be forwarded by the repeater to the
+  // listeners in the list.
+  bool EventForwardingEnabled() const;
+  void SuppressEventForwarding();
+
+  // The actual list of listeners.
+  internal::TestEventRepeater* repeater_;
+  // Listener responsible for the standard result output.
+  TestEventListener* default_result_printer_;
+  // Listener responsible for the creation of the XML output file.
+  TestEventListener* default_xml_generator_;
+
+  // We disallow copying TestEventListeners.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestCases.
+//
+// This is a singleton class.  The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called.  This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest {
+ public:
+  // Gets the singleton UnitTest object.  The first time this method
+  // is called, a UnitTest object is constructed and returned.
+  // Consecutive calls will return the same object.
+  static UnitTest* GetInstance();
+
+  // Runs all tests in this UnitTest object and prints the result.
+  // Returns 0 if successful, or 1 otherwise.
+  //
+  // This method can only be called from the main thread.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  int Run() GTEST_MUST_USE_RESULT_;
+
+  // Returns the working directory when the first TEST() or TEST_F()
+  // was executed.  The UnitTest object owns the string.
+  const char* original_working_dir() const;
+
+  // Returns the TestCase object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestCase* current_test_case() const
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Returns the TestInfo object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestInfo* current_test_info() const
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Returns the random seed used at the start of the current test run.
+  int random_seed() const;
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns the ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
+      GTEST_LOCK_EXCLUDED_(mutex_);
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Gets the number of successful test cases.
+  int successful_test_case_count() const;
+
+  // Gets the number of failed test cases.
+  int failed_test_case_count() const;
+
+  // Gets the number of all test cases.
+  int total_test_case_count() const;
+
+  // Gets the number of all test cases that contain at least one test
+  // that should run.
+  int test_case_to_run_count() const;
+
+  // Gets the number of successful tests.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Gets the number of all tests.
+  int total_test_count() const;
+
+  // Gets the number of tests that should run.
+  int test_to_run_count() const;
+
+  // Gets the time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const;
+
+  // Gets the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const;
+
+  // Returns true iff the unit test passed (i.e. all test cases passed).
+  bool Passed() const;
+
+  // Returns true iff the unit test failed (i.e. some test case failed
+  // or something outside of all tests failed).
+  bool Failed() const;
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  const TestCase* GetTestCase(int i) const;
+
+  // Returns the TestResult containing information on test failures and
+  // properties logged outside of individual test cases.
+  const TestResult& ad_hoc_test_result() const;
+
+  // Returns the list of event listeners that can be used to track events
+  // inside Google Test.
+  TestEventListeners& listeners();
+
+ private:
+  // Registers and returns a global test environment.  When a test
+  // program is run, all global test environments will be set-up in
+  // the order they were registered.  After all tests in the program
+  // have finished, all global test environments will be torn-down in
+  // the *reverse* order they were registered.
+  //
+  // The UnitTest object takes ownership of the given environment.
+  //
+  // This method can only be called from the main thread.
+  Environment* AddEnvironment(Environment* env);
+
+  // Adds a TestPartResult to the current TestResult object.  All
+  // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+  // eventually call this to report their results.  The user code
+  // should use the assertion macros instead of calling this directly.
+  void AddTestPartResult(TestPartResult::Type result_type,
+                         const char* file_name,
+                         int line_number,
+                         const std::string& message,
+                         const std::string& os_stack_trace)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Adds a TestProperty to the current TestResult object when invoked from
+  // inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+  // from SetUpTestCase or TearDownTestCase, or to the global property set
+  // when invoked elsewhere.  If the result already contains a property with
+  // the same key, the value will be updated.
+  void RecordProperty(const std::string& key, const std::string& value);
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  TestCase* GetMutableTestCase(int i);
+
+  // Accessors for the implementation object.
+  internal::UnitTestImpl* impl() { return impl_; }
+  const internal::UnitTestImpl* impl() const { return impl_; }
+
+  // These classes and funcions are friends as they need to access private
+  // members of UnitTest.
+  friend class Test;
+  friend class internal::AssertHelper;
+  friend class internal::ScopedTrace;
+  friend class internal::StreamingListenerTest;
+  friend class internal::UnitTestRecordPropertyTestHelper;
+  friend Environment* AddGlobalTestEnvironment(Environment* env);
+  friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+  friend void internal::ReportFailureInUnknownLocation(
+      TestPartResult::Type result_type,
+      const std::string& message);
+
+  // Creates an empty UnitTest.
+  UnitTest();
+
+  // D'tor
+  virtual ~UnitTest();
+
+  // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+  // Google Test trace stack.
+  void PushGTestTrace(const internal::TraceInfo& trace)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Pops a trace from the per-thread Google Test trace stack.
+  void PopGTestTrace()
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Protects mutable state in *impl_.  This is mutable as some const
+  // methods need to lock it too.
+  mutable internal::Mutex mutex_;
+
+  // Opaque implementation object.  This field is never changed once
+  // the object is constructed.  We don't mark it as const here, as
+  // doing so will cause a warning in the constructor of UnitTest.
+  // Mutable state in *impl_ is protected by mutex_.
+  internal::UnitTestImpl* impl_;
+
+  // We disallow copying UnitTest.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main().  If you use gtest_main, you need to call this before main()
+// starts for it to take effect.  For example, you can define a global
+// variable like this:
+//
+//   testing::Environment* const foo_env =
+//       testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+  return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value.  In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object.  If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+  static ::std::string Format(const ToPrint& value) {
+    return ::testing::PrintToString(value);
+  }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+  static ::std::string Format(const ToPrint* value) {
+    return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+  }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType)                \
+  template <typename OtherOperand>                                      \
+  class FormatForComparison<CharType*, OtherOperand> {                  \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(static_cast<const void*>(value)); \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+  template <>                                                           \
+  class FormatForComparison<CharType*, OtherStringType> {               \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(value);                           \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#endif
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message.  The type (but not value)
+// of the other operand may affect the format.  This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+    const T1& value, const T2& /* other_operand */) {
+  return FormatForComparison<T1, T2>::Format(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            const T1& expected,
+                            const T2& actual) {
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4389)  // Temporarily disables warning on
+                                // signed/unsigned mismatch.
+#endif
+
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)          // Restores the warning state.
+#endif
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
+                                       const char* actual_expression,
+                                       BiggestInt expected,
+                                       BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ.  The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal.  The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+  // This templatized version is for the general case.
+  template <typename T1, typename T2>
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 const T1& expected,
+                                 const T2& actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // With this overloaded version, we allow anonymous enums to be used
+  // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+  // enums can be implicitly cast to BiggestInt.
+  //
+  // Even though its body looks the same as the above version, we
+  // cannot merge the two, as it will make anonymous enums unhappy.
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 BiggestInt expected,
+                                 BiggestInt actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal, like NULL, false, or 0.
+template <>
+class EqHelper<true> {
+ public:
+  // We define two overloaded versions of Compare().  The first
+  // version will be picked when the second argument to ASSERT_EQ() is
+  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+  // EXPECT_EQ(false, a_bool).
+  template <typename T1, typename T2>
+  static AssertionResult Compare(
+      const char* expected_expression,
+      const char* actual_expression,
+      const T1& expected,
+      const T2& actual,
+      // The following line prevents this overload from being considered if T2
+      // is not a pointer type.  We need this because ASSERT_EQ(NULL, my_ptr)
+      // expands to Compare("", "", NULL, my_ptr), which requires a conversion
+      // to match the Secret* in the other overload, which would otherwise make
+      // this template match better.
+      typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // This version will be picked when the second argument to ASSERT_EQ() is a
+  // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+  template <typename T>
+  static AssertionResult Compare(
+      const char* expected_expression,
+      const char* actual_expression,
+      // We used to have a second template parameter instead of Secret*.  That
+      // template parameter would deduce to 'long', making this a better match
+      // than the first overload even without the first overload's EnableIf.
+      // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
+      // non-pointer argument" (even a deduced integral argument), so the old
+      // implementation caused warnings in user code.
+      Secret* /* expected (NULL) */,
+      T* actual) {
+    // We already know that 'expected' is a null pointer.
+    return CmpHelperEQ(expected_expression, actual_expression,
+                       static_cast<T*>(NULL), actual);
+  }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   const T1& val1, const T2& val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    return AssertionFailure() \
+        << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+  }\
+}\
+GTEST_API_ AssertionResult CmpHelper##op_name(\
+    const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=);
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=);
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, <);
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=);
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, >);
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                                          const char* actual_expression,
+                                          const char* expected,
+                                          const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                              const char* actual_expression,
+                                              const char* expected,
+                                              const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const char* s1,
+                                          const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                              const char* s2_expression,
+                                              const char* s1,
+                                              const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                                          const char* actual_expression,
+                                          const wchar_t* expected,
+                                          const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const wchar_t* s1,
+                                          const wchar_t* s2);
+
+}  // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves.  They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+                                         const char* actual_expression,
+                                         RawType expected,
+                                         RawType actual) {
+  const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  ::std::stringstream expected_ss;
+  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+              << expected;
+
+  ::std::stringstream actual_ss;
+  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+            << actual;
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   StringStreamToString(&expected_ss),
+                   StringStreamToString(&actual_ss),
+                   false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+                                                const char* expr2,
+                                                const char* abs_error_expr,
+                                                double val1,
+                                                double val2,
+                                                double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper {
+ public:
+  // Constructor.
+  AssertHelper(TestPartResult::Type type,
+               const char* file,
+               int line,
+               const char* message);
+  ~AssertHelper();
+
+  // Message assignment is a semantic trick to enable assertion
+  // streaming; see the GTEST_MESSAGE_ macro below.
+  void operator=(const Message& message) const;
+
+ private:
+  // We put our data in a struct so that the size of the AssertHelper class can
+  // be as small as possible.  This is important because gcc is incapable of
+  // re-using stack space even for temporary variables, so every EXPECT_EQ
+  // reserves stack space for another AssertHelper.
+  struct AssertHelperData {
+    AssertHelperData(TestPartResult::Type t,
+                     const char* srcfile,
+                     int line_num,
+                     const char* msg)
+        : type(t), file(srcfile), line(line_num), message(msg) { }
+
+    TestPartResult::Type const type;
+    const char* const file;
+    int const line;
+    std::string const message;
+
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+  };
+
+  AssertHelperData* const data_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+}  // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The pure interface class that all value-parameterized tests inherit from.
+// A value-parameterized class must inherit from both ::testing::Test and
+// ::testing::WithParamInterface. In most cases that just means inheriting
+// from ::testing::TestWithParam, but more complicated test hierarchies
+// may need to inherit from Test and WithParamInterface at different levels.
+//
+// This interface has support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+//  protected:
+//   FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual ~FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void SetUp() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void TearDown {
+//     // Can use GetParam() here.
+//   }
+// };
+// TEST_P(FooTest, DoesBar) {
+//   // Can use GetParam() method here.
+//   Foo foo;
+//   ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface {
+ public:
+  typedef T ParamType;
+  virtual ~WithParamInterface() {}
+
+  // The current parameter value. Is also available in the test fixture's
+  // constructor. This member function is non-static, even though it only
+  // references static data, to reduce the opportunity for incorrect uses
+  // like writing 'WithParamInterface<bool>::GetParam()' for a test that
+  // uses a fixture whose parameter type is int.
+  const ParamType& GetParam() const {
+    GTEST_CHECK_(parameter_ != NULL)
+        << "GetParam() can only be called inside a value-parameterized test "
+        << "-- did you intend to write TEST_P instead of TEST_F?";
+    return *parameter_;
+  }
+
+ private:
+  // Sets parameter value. The caller is responsible for making sure the value
+  // remains alive and unchanged throughout the current test.
+  static void SetParam(const ParamType* parameter) {
+    parameter_ = parameter;
+  }
+
+  // Static value used for accessing parameter during a test lifetime.
+  static const ParamType* parameter_;
+
+  // TestClass must be a subclass of WithParamInterface<T> and Test.
+  template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = NULL;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T> {
+};
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied.  If not,
+// it behaves like ADD_FAILURE.  In particular:
+//
+//   EXPECT_TRUE  verifies that a Boolean condition is true.
+//   EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure.  People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a nonfatal failure at the given source file location with
+// a generic message.
+#define ADD_FAILURE_AT(file, line) \
+  GTEST_MESSAGE_AT_(file, line, "Failed", \
+                    ::testing::TestPartResult::kNonFatalFailure)
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+# define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+# define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+//    * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+//         Tests that the statement throws the expected exception.
+//    * {ASSERT|EXPECT}_NO_THROW(statement):
+//         Tests that the statement doesn't throw any exception.
+//    * {ASSERT|EXPECT}_ANY_THROW(statement):
+//         Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define EXPECT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
+// 'gen_gtest_pred_impl.py 5'.  DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+# error Do not include gtest_pred_impl.h directly.  Include gtest.h instead.
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+//   ASSERT_PRED_FORMAT1(pred_format, v1)
+//   ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+//   ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult.  See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+//   ASSERT_PRED1(pred, v1)
+//   ASSERT_PRED2(pred, v1, v2)
+//   ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce.  Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const ::testing::AssertionResult gtest_ar = (expression)) \
+    ; \
+  else \
+    on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+                                  const char* e1,
+                                  Pred pred,
+                                  const T1& v1) {
+  if (pred(v1)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, v1), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+                                             #v1, \
+                                             pred, \
+                                             v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2) {
+  if (pred(v1, v2)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             pred, \
+                                             v1, \
+                                             v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3) {
+  if (pred(v1, v2, v3)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4) {
+  if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ", "
+                            << e4 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3
+                            << "\n" << e4 << " evaluates to " << v4;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4,
+          typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  const char* e5,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4,
+                                  const T5& v5) {
+  if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ", "
+                            << e4 << ", "
+                            << e5 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3
+                            << "\n" << e4 << " evaluates to " << v4
+                            << "\n" << e5 << " evaluates to " << v5;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             #v5, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4, \
+                                             v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Macros for testing equalities and inequalities.
+//
+//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
+//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
+//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
+//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
+//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values.  The values must be compatible built-in types,
+// or you will get a compiler error.  By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+//   1. It is possible to make a user-defined type work with
+//   {ASSERT|EXPECT}_??(), but that requires overloading the
+//   comparison operators and is thus discouraged by the Google C++
+//   Usage Guide.  Therefore, you are advised to use the
+//   {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+//   equal.
+//
+//   2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+//   pointers (in particular, C strings).  Therefore, if you use it
+//   with two C strings, you are testing how their locations in memory
+//   are related, not how their content is related.  To compare two C
+//   strings by content, use {ASSERT|EXPECT}_STR*().
+//
+//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+//   what the actual value is when it fails, and similarly for the
+//   other comparisons.
+//
+//   4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+//   evaluate their arguments, which is undefined.
+//
+//   5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+//   EXPECT_NE(5, Foo());
+//   EXPECT_EQ(NULL, a_pointer);
+//   ASSERT_LT(i, array_size);
+//   ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define EXPECT_NE(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define GTEST_ASSERT_EQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define GTEST_ASSERT_NE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define GTEST_ASSERT_LE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define GTEST_ASSERT_LT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define GTEST_ASSERT_GE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define GTEST_ASSERT_GT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
+// ASSERT_XY(), which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_ASSERT_EQ
+# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_NE
+# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LE
+# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LT
+# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GE
+# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GT
+# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
+#endif
+
+// C-string Comparisons.  All tests treat NULL and any non-NULL string
+// as different.  Two NULLs are equal.
+//
+//    * {ASSERT|EXPECT}_STREQ(s1, s2):     Tests that s1 == s2
+//    * {ASSERT|EXPECT}_STRNE(s1, s2):     Tests that s1 != s2
+//    * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+//    * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+//         Tests that two float values are almost equal.
+//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+//         Tests that two double values are almost equal.
+//    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+//         Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands.  See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+  EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+  ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+//   EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+                                   float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                                    double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+# define EXPECT_HRESULT_SUCCEEDED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define ASSERT_HRESULT_SUCCEEDED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define EXPECT_HRESULT_FAILED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+# define ASSERT_HRESULT_FAILED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif  // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+//   * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+//   EXPECT_NO_FATAL_FAILURE(Process());
+//   ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope.  The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+  ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+    __FILE__, __LINE__, ::testing::Message() << (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type.  The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template.  This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated.  For example, given:
+//
+//   template <typename T> class Foo {
+//    public:
+//     void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+//   };
+//
+// the code:
+//
+//   void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated.  Instead, you need:
+//
+//   void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq() {
+  (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+  return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test".  For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro.  Example:
+//
+//   TEST(FooTest, InitializesCorrectly) {
+//     Foo foo;
+//     EXPECT_TRUE(foo.StatusIsOK());
+//   }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test.  This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X.  The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code.  GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_case_name, test_name)\
+  GTEST_TEST_(test_case_name, test_name, \
+              ::testing::Test, ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name.  The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier.  The user should put
+// his test code between braces after using this macro.  Example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { b_.AddElement(3); }
+//
+//     Foo a_;
+//     Foo b_;
+//   };
+//
+//   TEST_F(FooTest, InitializesCorrectly) {
+//     EXPECT_TRUE(a_.StatusIsOK());
+//   }
+//
+//   TEST_F(FooTest, ReturnsElementCountCorrectly) {
+//     EXPECT_EQ(0, a_.size());
+//     EXPECT_EQ(1, b_.size());
+//   }
+
+#define TEST_F(test_fixture, test_name)\
+  GTEST_TEST_(test_fixture, test_name, test_fixture, \
+              ::testing::internal::GetTypeId<test_fixture>())
+
+}  // namespace testing
+
+// Use this function in main() to run all tests.  It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+//
+// This function was formerly a macro; thus, it is in the global
+// namespace and has an all-caps name.
+int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
+
+inline int RUN_ALL_TESTS() {
+  return ::testing::UnitTest::GetInstance()->Run();
+}
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/libaudiofile/.gitignore b/libaudiofile/.gitignore
new file mode 100644
index 0000000..eb2ad4e
--- /dev/null
+++ b/libaudiofile/.gitignore
@@ -0,0 +1 @@
+UnitTests
diff --git a/libaudiofile/AIFF.cpp b/libaudiofile/AIFF.cpp
new file mode 100644
index 0000000..ce46adc
--- /dev/null
+++ b/libaudiofile/AIFF.cpp
@@ -0,0 +1,1220 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2003-2004, 2010-2013, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	AIFF.cpp
+
+	This file contains routines for reading and writing AIFF and
+	AIFF-C sound files.
+*/
+
+#include "config.h"
+#include "AIFF.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Instrument.h"
+#include "Marker.h"
+#include "Setup.h"
+#include "Tag.h"
+#include "Track.h"
+#include "byteorder.h"
+#include "extended.h"
+#include "util.h"
+
+const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS] =
+{
+	{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
+	{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
+	{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
+	{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
+	{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
+	{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
+	{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} },
+	{ AF_INST_SUSLOOPID, AU_PVTYPE_LONG, "Sustain loop id", {0} },
+	{ AF_INST_RELLOOPID, AU_PVTYPE_LONG, "Release loop id", {0} }
+};
+
+const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW,
+	AF_COMPRESSION_IMA
+};
+
+static const _AFfilesetup aiffDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_AIFF,		/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	1,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+#define AIFC_VERSION_1 0xa2805140
+
+struct _INST
+{
+	uint8_t		baseNote;
+	int8_t		detune;
+	uint8_t		lowNote, highNote;
+	uint8_t		lowVelocity, highVelocity;
+	int16_t		gain;
+
+	uint16_t	sustainLoopPlayMode;
+	uint16_t	sustainLoopBegin;
+	uint16_t	sustainLoopEnd;
+
+	uint16_t	releaseLoopPlayMode;
+	uint16_t	releaseLoopBegin;
+	uint16_t	releaseLoopEnd;
+};
+
+AIFFFile::AIFFFile()
+{
+	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
+
+	m_miscellaneousPosition = 0;
+	m_FVER_offset = 0;
+	m_COMM_offset = 0;
+	m_MARK_offset = 0;
+	m_INST_offset = 0;
+	m_AESD_offset = 0;
+	m_SSND_offset = 0;
+}
+
+/*
+	FVER chunks are only present in AIFF-C files.
+*/
+status AIFFFile::parseFVER(const Tag &type, size_t size)
+{
+	assert(type == "FVER");
+
+	uint32_t timestamp;
+	readU32(&timestamp);
+	/* timestamp holds the number of seconds since January 1, 1904. */
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse AES recording data.
+*/
+status AIFFFile::parseAESD(const Tag &type, size_t size)
+{
+	unsigned char aesChannelStatusData[24];
+
+	assert(type == "AESD");
+	assert(size == 24);
+
+	Track *track = getTrack();
+
+	track->hasAESData = true;
+
+	/*
+		Try to read 24 bytes of AES nonaudio data from the file.
+		Fail if the file disappoints.
+	*/
+	if (m_fh->read(aesChannelStatusData, 24) != 24)
+		return AF_FAIL;
+
+	memcpy(track->aesData, aesChannelStatusData, 24);
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse miscellaneous data chunks such as name, author, copyright,
+	and annotation chunks.
+*/
+status AIFFFile::parseMiscellaneous(const Tag &type, size_t size)
+{
+	int misctype = AF_MISC_UNRECOGNIZED;
+
+	assert(type == "NAME" ||
+		type == "AUTH" ||
+		type == "(c) " ||
+		type == "ANNO" ||
+		type == "APPL" ||
+		type == "MIDI");
+
+	/* Skip zero-length miscellaneous chunks. */
+	if (size == 0)
+		return AF_FAIL;
+
+	m_miscellaneousCount++;
+	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
+		m_miscellaneousCount * sizeof (Miscellaneous));
+
+	if (type == "NAME")
+		misctype = AF_MISC_NAME;
+	else if (type == "AUTH")
+		misctype = AF_MISC_AUTH;
+	else if (type == "(c) ")
+		misctype = AF_MISC_COPY;
+	else if (type == "ANNO")
+		misctype = AF_MISC_ANNO;
+	else if (type == "APPL")
+		misctype = AF_MISC_APPL;
+	else if (type == "MIDI")
+		misctype = AF_MISC_MIDI;
+
+	m_miscellaneous[m_miscellaneousCount - 1].id = m_miscellaneousCount;
+	m_miscellaneous[m_miscellaneousCount - 1].type = misctype;
+	m_miscellaneous[m_miscellaneousCount - 1].size = size;
+	m_miscellaneous[m_miscellaneousCount - 1].position = 0;
+	m_miscellaneous[m_miscellaneousCount - 1].buffer = _af_malloc(size);
+	m_fh->read(m_miscellaneous[m_miscellaneousCount - 1].buffer, size);
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse instrument chunks, which contain information about using
+	sound data as a sampled instrument.
+*/
+status AIFFFile::parseINST(const Tag &type, size_t size)
+{
+	uint8_t baseNote;
+	int8_t detune;
+	uint8_t lowNote, highNote, lowVelocity, highVelocity;
+	int16_t gain;
+
+	uint16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd;
+	uint16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd;
+
+	Instrument *instrument = (Instrument *) _af_calloc(1, sizeof (Instrument));
+	instrument->id = AF_DEFAULT_INST;
+	instrument->values = (AFPVu *) _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu));
+	instrument->loopCount = 2;
+	instrument->loops = (Loop *) _af_calloc(2, sizeof (Loop));
+
+	m_instrumentCount = 1;
+	m_instruments = instrument;
+
+	readU8(&baseNote);
+	readS8(&detune);
+	readU8(&lowNote);
+	readU8(&highNote);
+	readU8(&lowVelocity);
+	readU8(&highVelocity);
+	readS16(&gain);
+
+	instrument->values[0].l = baseNote;
+	instrument->values[1].l = detune;
+	instrument->values[2].l = lowVelocity;
+	instrument->values[3].l = highVelocity;
+	instrument->values[4].l = lowNote;
+	instrument->values[5].l = highNote;
+	instrument->values[6].l = gain;
+
+	instrument->values[7].l = 1;	/* sustain loop id */
+	instrument->values[8].l = 2;	/* release loop id */
+
+	readU16(&sustainLoopPlayMode);
+	readU16(&sustainLoopBegin);
+	readU16(&sustainLoopEnd);
+
+	readU16(&releaseLoopPlayMode);
+	readU16(&releaseLoopBegin);
+	readU16(&releaseLoopEnd);
+
+	instrument->loops[0].id = 1;
+	instrument->loops[0].mode = sustainLoopPlayMode;
+	instrument->loops[0].beginMarker = sustainLoopBegin;
+	instrument->loops[0].endMarker = sustainLoopEnd;
+	instrument->loops[0].trackid = AF_DEFAULT_TRACK;
+
+	instrument->loops[1].id = 2;
+	instrument->loops[1].mode = releaseLoopPlayMode;
+	instrument->loops[1].beginMarker = releaseLoopBegin;
+	instrument->loops[1].endMarker = releaseLoopEnd;
+	instrument->loops[1].trackid = AF_DEFAULT_TRACK;
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse marker chunks, which contain the positions and names of loop markers.
+*/
+status AIFFFile::parseMARK(const Tag &type, size_t size)
+{
+	assert(type == "MARK");
+
+	Track *track = getTrack();
+
+	uint16_t numMarkers;
+	readU16(&numMarkers);
+
+	track->markerCount = numMarkers;
+	if (numMarkers)
+		track->markers = _af_marker_new(numMarkers);
+
+	for (unsigned i=0; i<numMarkers; i++)
+	{
+		uint16_t markerID = 0;
+		uint32_t markerPosition = 0;
+		uint8_t sizeByte = 0;
+		char *markerName = NULL;
+
+		readU16(&markerID);
+		readU32(&markerPosition);
+		m_fh->read(&sizeByte, 1);
+		markerName = (char *) _af_malloc(sizeByte + 1);
+		m_fh->read(markerName, sizeByte);
+
+		markerName[sizeByte] = '\0';
+
+		/*
+			If sizeByte is even, then 1+sizeByte (the length
+			of the string) is odd.	Skip an extra byte to
+			make it even.
+		*/
+
+		if ((sizeByte % 2) == 0)
+			m_fh->seek(1, File::SeekFromCurrent);
+
+		track->markers[i].id = markerID;
+		track->markers[i].position = markerPosition;
+		track->markers[i].name = markerName;
+		track->markers[i].comment = _af_strdup("");
+	}
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse common data chunks, which contain information regarding the
+	sampling rate, the number of sample frames, and the number of
+	sound channels.
+*/
+status AIFFFile::parseCOMM(const Tag &type, size_t size)
+{
+	assert(type == "COMM");
+
+	Track *track = getTrack();
+
+	uint16_t numChannels;
+	uint32_t numSampleFrames;
+	uint16_t sampleSize;
+	unsigned char sampleRate[10];
+
+	readU16(&numChannels);
+	track->f.channelCount = numChannels;
+
+	if (!numChannels)
+	{
+		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
+		return AF_FAIL;
+	}
+
+	readU32(&numSampleFrames);
+	track->totalfframes = numSampleFrames;
+
+	readU16(&sampleSize);
+	track->f.sampleWidth = sampleSize;
+
+	m_fh->read(sampleRate, 10);
+	track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate);
+
+	track->f.compressionType = AF_COMPRESSION_NONE;
+	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+	track->f.framesPerPacket = 1;
+
+	if (isAIFFC())
+	{
+		Tag compressionID;
+		// Pascal strings are at most 255 bytes long.
+		char compressionName[256];
+
+		readTag(&compressionID);
+
+		// Read the Pascal-style string containing the name.
+		readPString(compressionName);
+
+		if (compressionID == "NONE" || compressionID == "twos")
+		{
+			track->f.compressionType = AF_COMPRESSION_NONE;
+		}
+		else if (compressionID == "in24")
+		{
+			track->f.compressionType = AF_COMPRESSION_NONE;
+			track->f.sampleWidth = 24;
+		}
+		else if (compressionID == "in32")
+		{
+			track->f.compressionType = AF_COMPRESSION_NONE;
+			track->f.sampleWidth = 32;
+		}
+		else if (compressionID == "ACE2" ||
+			compressionID == "ACE8" ||
+			compressionID == "MAC3" ||
+			compressionID == "MAC6")
+		{
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName);
+			return AF_FAIL;
+		}
+		else if (compressionID == "ulaw" || compressionID == "ULAW")
+		{
+			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.sampleWidth = 16;
+			track->f.bytesPerPacket = track->f.channelCount;
+		}
+		else if (compressionID == "alaw" || compressionID == "ALAW")
+		{
+			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.sampleWidth = 16;
+			track->f.bytesPerPacket = track->f.channelCount;
+		}
+		else if (compressionID == "fl32" || compressionID == "FL32")
+		{
+			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+			track->f.sampleWidth = 32;
+			track->f.compressionType = AF_COMPRESSION_NONE;
+		}
+		else if (compressionID == "fl64" || compressionID == "FL64")
+		{
+			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+			track->f.sampleWidth = 64;
+			track->f.compressionType = AF_COMPRESSION_NONE;
+		}
+		else if (compressionID == "sowt")
+		{
+			track->f.compressionType = AF_COMPRESSION_NONE;
+			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+		}
+		else if (compressionID == "ima4")
+		{
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.compressionType = AF_COMPRESSION_IMA;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+			initIMACompressionParams();
+
+			track->totalfframes *= 64;
+		}
+		else
+		{
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%s' not currently supported",
+				compressionID.name().c_str());
+			return AF_FAIL;
+		}
+	}
+
+	if (track->f.isUncompressed())
+		track->f.computeBytesPerPacketPCM();
+
+	if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
+		return AF_FAIL;
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse the stored sound chunk, which usually contains little more
+	than the sound data.
+*/
+status AIFFFile::parseSSND(const Tag &type, size_t size)
+{
+	assert(type == "SSND");
+
+	Track *track = getTrack();
+
+	uint32_t offset, blockSize;
+	readU32(&offset);
+	readU32(&blockSize);
+
+	track->data_size = size - 8 - offset;
+
+	track->fpos_first_frame = m_fh->tell() + offset;
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::readInit(AFfilesetup setup)
+{
+	uint32_t type, size, formtype;
+
+	bool hasCOMM = false;
+	bool hasFVER = false;
+	bool hasSSND = false;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	m_fh->read(&type, 4);
+	readU32(&size);
+	m_fh->read(&formtype, 4);
+
+	if (memcmp(&type, "FORM", 4) != 0 ||
+		(memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4)))
+		return AF_FAIL;
+
+	if (!allocateTrack())
+		return AF_FAIL;
+
+	/* Include the offset of the form type. */
+	size_t index = 4;
+	while (index < size)
+	{
+		Tag chunkid;
+		uint32_t chunksize = 0;
+		status result = AF_SUCCEED;
+
+		readTag(&chunkid);
+		readU32(&chunksize);
+
+		if (chunkid == "COMM")
+		{
+			hasCOMM = true;
+			result = parseCOMM(chunkid, chunksize);
+		}
+		else if (chunkid == "FVER")
+		{
+			hasFVER = true;
+			parseFVER(chunkid, chunksize);
+		}
+		else if (chunkid == "INST")
+		{
+			parseINST(chunkid, chunksize);
+		}
+		else if (chunkid == "MARK")
+		{
+			parseMARK(chunkid, chunksize);
+		}
+		else if (chunkid == "AESD")
+		{
+			parseAESD(chunkid, chunksize);
+		}
+		else if (chunkid == "NAME" ||
+			chunkid == "AUTH" ||
+			chunkid == "(c) " ||
+			chunkid == "ANNO" ||
+			chunkid == "APPL" ||
+			chunkid == "MIDI")
+		{
+			parseMiscellaneous(chunkid, chunksize);
+		}
+		/*
+			The sound data chunk is required if there are more than
+			zero sample frames.
+		*/
+		else if (chunkid == "SSND")
+		{
+			if (hasSSND)
+			{
+				_af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk");
+				return AF_FAIL;
+			}
+			hasSSND = true;
+			result = parseSSND(chunkid, chunksize);
+		}
+
+		if (result == AF_FAIL)
+			return AF_FAIL;
+
+		index += chunksize + 8;
+
+		/* all chunks must be aligned on an even number of bytes */
+		if ((index % 2) != 0)
+			index++;
+
+		m_fh->seek(index + 8, File::SeekFromBeginning);
+	}
+
+	if (!hasCOMM)
+	{
+		_af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk");
+	}
+
+	if (isAIFFC() && !hasFVER)
+	{
+		_af_error(AF_BAD_HEADER, "FVER chunk is required in AIFF-C");
+	}
+
+	/* The file has been successfully parsed. */
+	return AF_SUCCEED;
+}
+
+bool AIFFFile::recognizeAIFF(File *fh)
+{
+	uint8_t buffer[8];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
+		return false;
+	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFF", 4) != 0)
+		return false;
+
+	return true;
+}
+
+bool AIFFFile::recognizeAIFFC(File *fh)
+{
+	uint8_t buffer[8];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
+		return false;
+	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFC", 4) != 0)
+		return false;
+
+	return true;
+}
+
+AFfilesetup AIFFFile::completeSetup(AFfilesetup setup)
+{
+	bool	isAIFF = setup->fileFormat == AF_FILE_AIFF;
+
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "AIFF/AIFF-C file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+		{
+			_af_error(AF_BAD_FILEFMT, "AIFF/AIFF-C format does not support unsigned data");
+			return AF_NULL_FILESETUP;
+		}
+		else if (isAIFF && track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+		{
+			_af_error(AF_BAD_FILEFMT, "AIFF format supports only two's complement integer data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+	else
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+			track->f.sampleWidth);
+
+	/* Check sample width if writing two's complement. Otherwise ignore. */
+	if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
+		(track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
+	{
+		_af_error(AF_BAD_WIDTH,
+			"invalid sample width %d for AIFF/AIFF-C file "
+			"(must be 1-32)", track->f.sampleWidth);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (isAIFF && track->f.compressionType != AF_COMPRESSION_NONE)
+	{
+		_af_error(AF_BAD_FILESETUP,
+			"AIFF does not support compression; use AIFF-C");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
+		track->f.compressionType != AF_COMPRESSION_IMA)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in AIFF-C");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed() &&
+		track->byteOrderSet &&
+		track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
+		track->f.isByteOrderSignificant())
+	{
+		_af_error(AF_BAD_BYTEORDER,
+			"AIFF/AIFF-C format supports only big-endian data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+	if (setup->instrumentSet)
+	{
+		if (setup->instrumentCount != 0 && setup->instrumentCount != 1)
+		{
+			_af_error(AF_BAD_NUMINSTS, "AIFF/AIFF-C file must have 0 or 1 instrument chunk");
+			return AF_NULL_FILESETUP;
+		}
+		if (setup->instruments != 0 &&
+			setup->instruments[0].loopCount != 2)
+		{
+			_af_error(AF_BAD_NUMLOOPS, "AIFF/AIFF-C file with instrument must also have 2 loops");
+			return AF_NULL_FILESETUP;
+		}
+	}
+
+	if (setup->miscellaneousSet)
+	{
+		for (int i=0; i<setup->miscellaneousCount; i++)
+		{
+			switch (setup->miscellaneous[i].type)
+			{
+				case AF_MISC_COPY:
+				case AF_MISC_AUTH:
+				case AF_MISC_NAME:
+				case AF_MISC_ANNO:
+				case AF_MISC_APPL:
+				case AF_MISC_MIDI:
+					break;
+
+				default:
+					_af_error(AF_BAD_MISCTYPE, "invalid miscellaneous type %d for AIFF/AIFF-C file", setup->miscellaneous[i].type);
+					return AF_NULL_FILESETUP;
+			}
+		}
+	}
+
+	return _af_filesetup_copy(setup, &aiffDefaultFileSetup, true);
+}
+
+bool AIFFFile::isInstrumentParameterValid(AUpvlist list, int i)
+{
+	int param, type;
+
+	AUpvgetparam(list, i, &param);
+	AUpvgetvaltype(list, i, &type);
+	if (type != AU_PVTYPE_LONG)
+		return false;
+
+	long lval;
+	AUpvgetval(list, i, &lval);
+
+	switch (param)
+	{
+		case AF_INST_MIDI_BASENOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_NUMCENTS_DETUNE:
+			return ((lval >= -50) && (lval <= 50));
+
+		case AF_INST_MIDI_LOVELOCITY:
+			return ((lval >= 1) && (lval <= 127));
+
+		case AF_INST_MIDI_HIVELOCITY:
+			return ((lval >= 1) && (lval <= 127));
+
+		case AF_INST_MIDI_LONOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_MIDI_HINOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_NUMDBS_GAIN:
+		case AF_INST_SUSLOOPID:
+		case AF_INST_RELLOOPID:
+			return true;
+
+		default:
+			return false;
+			break;
+	}
+
+	return true;
+}
+
+int AIFFFile::getVersion()
+{
+	if (isAIFFC())
+		return AIFC_VERSION_1;
+	return 0;
+}
+
+status AIFFFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	initCompressionParams();
+
+	uint32_t fileSize = 0;
+	m_fh->write("FORM", 4);
+	writeU32(&fileSize);
+
+	if (isAIFFC())
+		m_fh->write("AIFC", 4);
+	else
+		m_fh->write("AIFF", 4);
+
+	if (isAIFFC())
+		writeFVER();
+
+	writeCOMM();
+	writeMARK();
+	writeINST();
+	writeAESD();
+	writeMiscellaneous();
+	writeSSND();
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::update()
+{
+	/* Get the length of the file. */
+	uint32_t length = m_fh->length();
+	length -= 8;
+
+	/* Set the length of the FORM chunk. */
+	m_fh->seek(4, File::SeekFromBeginning);
+	writeU32(&length);
+
+	if (isAIFFC())
+		writeFVER();
+
+	writeCOMM();
+	writeMARK();
+	writeINST();
+	writeAESD();
+	writeMiscellaneous();
+	writeSSND();
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::writeCOMM()
+{
+	/*
+		If COMM_offset hasn't been set yet, set it to the
+		current offset.
+	*/
+	if (m_COMM_offset == 0)
+		m_COMM_offset = m_fh->tell();
+	else
+		m_fh->seek(m_COMM_offset, File::SeekFromBeginning);
+
+	Track *track = getTrack();
+
+	Tag compressionTag;
+	/* Pascal strings can occupy only 255 bytes (+ a size byte). */
+	char compressionName[256];
+
+	if (isAIFFC())
+	{
+		if (track->f.compressionType == AF_COMPRESSION_NONE)
+		{
+			if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
+			{
+				compressionTag = "NONE";
+				strcpy(compressionName, "not compressed");
+			}
+			else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+			{
+				compressionTag = "fl32";
+				strcpy(compressionName, "32-bit Floating Point");
+			}
+			else if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+			{
+				compressionTag = "fl64";
+				strcpy(compressionName, "64-bit Floating Point");
+			}
+			/*
+				We disallow unsigned sample data for
+				AIFF files in _af_aiff_complete_setup,
+				so the next condition should never be
+				satisfied.
+			*/
+			else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+			{
+				_af_error(AF_BAD_SAMPFMT,
+					"AIFF/AIFF-C format does not support unsigned data");
+				assert(0);
+				return AF_FAIL;
+			}
+		}
+		else if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+		{
+			compressionTag = "ulaw";
+			strcpy(compressionName, "CCITT G.711 u-law");
+		}
+		else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+		{
+			compressionTag = "alaw";
+			strcpy(compressionName, "CCITT G.711 A-law");
+		}
+		else if (track->f.compressionType == AF_COMPRESSION_IMA)
+		{
+			compressionTag = "ima4";
+			strcpy(compressionName, "IMA 4:1 compression");
+		}
+	}
+
+	m_fh->write("COMM", 4);
+
+	/*
+		For AIFF-C files, the length of the COMM chunk is 22
+		plus the length of the compression name plus the size
+		byte.  If the length of the data is an odd number of
+		bytes, add a zero pad byte at the end, but don't
+		include the pad byte in the chunk's size.
+	*/
+	uint32_t chunkSize;
+	if (isAIFFC())
+		chunkSize = 22 + strlen(compressionName) + 1;
+	else
+		chunkSize = 18;
+	writeU32(&chunkSize);
+
+	/* number of channels, 2 bytes */
+	uint16_t channelCount = track->f.channelCount;
+	writeU16(&channelCount);
+
+	/* number of sample frames, 4 bytes */
+	uint32_t frameCount = track->totalfframes;
+	if (track->f.compressionType == AF_COMPRESSION_IMA)
+		frameCount = track->totalfframes / track->f.framesPerPacket;
+	writeU32(&frameCount);
+
+	/* sample size, 2 bytes */
+	uint16_t sampleSize = track->f.sampleWidth;
+	writeU16(&sampleSize);
+
+	/* sample rate, 10 bytes */
+	uint8_t sampleRate[10];
+	_af_convert_to_ieee_extended(track->f.sampleRate, sampleRate);
+	m_fh->write(sampleRate, 10);
+
+	if (isAIFFC())
+	{
+		writeTag(&compressionTag);
+		writePString(compressionName);
+	}
+
+	return AF_SUCCEED;
+}
+
+/*
+	The AESD chunk contains information pertinent to audio recording
+	devices.
+*/
+status AIFFFile::writeAESD()
+{
+	Track *track = getTrack();
+
+	if (!track->hasAESData)
+		return AF_SUCCEED;
+
+	if (m_AESD_offset == 0)
+		m_AESD_offset = m_fh->tell();
+	else
+		m_fh->seek(m_AESD_offset, File::SeekFromBeginning);
+
+	if (m_fh->write("AESD", 4) < 4)
+		return AF_FAIL;
+
+	uint32_t size = 24;
+	if (!writeU32(&size))
+		return AF_FAIL;
+
+	if (m_fh->write(track->aesData, 24) < 24)
+		return AF_FAIL;
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::writeSSND()
+{
+	Track *track = getTrack();
+
+	if (m_SSND_offset == 0)
+		m_SSND_offset = m_fh->tell();
+	else
+		m_fh->seek(m_SSND_offset, File::SeekFromBeginning);
+
+	m_fh->write("SSND", 4);
+
+	uint32_t chunkSize = track->data_size + 8;
+	writeU32(&chunkSize);
+
+	uint32_t zero = 0;
+	/* data offset */
+	writeU32(&zero);
+	/* block size */
+	writeU32(&zero);
+
+	if (track->fpos_first_frame == 0)
+		track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::writeINST()
+{
+	uint32_t length = 20;
+
+	struct _INST instrumentdata;
+
+	instrumentdata.sustainLoopPlayMode =
+		afGetLoopMode(this, AF_DEFAULT_INST, 1);
+	instrumentdata.sustainLoopBegin =
+		afGetLoopStart(this, AF_DEFAULT_INST, 1);
+	instrumentdata.sustainLoopEnd =
+		afGetLoopEnd(this, AF_DEFAULT_INST, 1);
+
+	instrumentdata.releaseLoopPlayMode =
+		afGetLoopMode(this, AF_DEFAULT_INST, 2);
+	instrumentdata.releaseLoopBegin =
+		afGetLoopStart(this, AF_DEFAULT_INST, 2);
+	instrumentdata.releaseLoopEnd =
+		afGetLoopEnd(this, AF_DEFAULT_INST, 2);
+
+	m_fh->write("INST", 4);
+	writeU32(&length);
+
+	instrumentdata.baseNote =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
+	writeU8(&instrumentdata.baseNote);
+	instrumentdata.detune =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
+	writeS8(&instrumentdata.detune);
+	instrumentdata.lowNote =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
+	writeU8(&instrumentdata.lowNote);
+	instrumentdata.highNote =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
+	writeU8(&instrumentdata.highNote);
+	instrumentdata.lowVelocity =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
+	writeU8(&instrumentdata.lowVelocity);
+	instrumentdata.highVelocity =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
+	writeU8(&instrumentdata.highVelocity);
+
+	instrumentdata.gain =
+		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
+	writeS16(&instrumentdata.gain);
+
+	writeU16(&instrumentdata.sustainLoopPlayMode);
+	writeU16(&instrumentdata.sustainLoopBegin);
+	writeU16(&instrumentdata.sustainLoopEnd);
+
+	writeU16(&instrumentdata.releaseLoopPlayMode);
+	writeU16(&instrumentdata.releaseLoopBegin);
+	writeU16(&instrumentdata.releaseLoopEnd);
+
+	return AF_SUCCEED;
+}
+
+status AIFFFile::writeMARK()
+{
+	Track *track = getTrack();
+	if (!track->markerCount)
+		return AF_SUCCEED;
+
+	if (m_MARK_offset == 0)
+		m_MARK_offset = m_fh->tell();
+	else
+		m_fh->seek(m_MARK_offset, File::SeekFromBeginning);
+
+	Tag markTag("MARK");
+	uint32_t length = 0;
+
+	writeTag(&markTag);
+	writeU32(&length);
+
+	AFfileoffset chunkStartPosition = m_fh->tell();
+
+	uint16_t numMarkers = track->markerCount;
+	writeU16(&numMarkers);
+
+	for (unsigned i=0; i<numMarkers; i++)
+	{
+		uint16_t id = track->markers[i].id;
+		writeU16(&id);
+
+		uint32_t position = track->markers[i].position;
+		writeU32(&position);
+
+		const char *name = track->markers[i].name;
+		assert(name);
+
+		// Write the name as a Pascal-style string.
+		writePString(name);
+	}
+
+	AFfileoffset chunkEndPosition = m_fh->tell();
+	length = chunkEndPosition - chunkStartPosition;
+
+	m_fh->seek(chunkStartPosition - 4, File::SeekFromBeginning);
+
+	writeU32(&length);
+	m_fh->seek(chunkEndPosition, File::SeekFromBeginning);
+
+	return AF_SUCCEED;
+}
+
+/*
+	The FVER chunk, if present, is always the first chunk in the file.
+*/
+status AIFFFile::writeFVER()
+{
+	uint32_t chunkSize, timeStamp;
+
+	assert(isAIFFC());
+
+	if (m_FVER_offset == 0)
+		m_FVER_offset = m_fh->tell();
+	else
+		m_fh->seek(m_FVER_offset, File::SeekFromBeginning);
+
+	m_fh->write("FVER", 4);
+
+	chunkSize = 4;
+	writeU32(&chunkSize);
+
+	timeStamp = AIFC_VERSION_1;
+	writeU32(&timeStamp);
+
+	return AF_SUCCEED;
+}
+
+/*
+	WriteMiscellaneous writes all the miscellaneous data chunks in a
+	file handle structure to an AIFF or AIFF-C file.
+*/
+status AIFFFile::writeMiscellaneous()
+{
+	if (m_miscellaneousPosition == 0)
+		m_miscellaneousPosition = m_fh->tell();
+	else
+		m_fh->seek(m_miscellaneousPosition, File::SeekFromBeginning);
+
+	for (int i=0; i<m_miscellaneousCount; i++)
+	{
+		Miscellaneous *misc = &m_miscellaneous[i];
+		Tag chunkType;
+		uint32_t chunkSize;
+		uint8_t padByte = 0;
+
+		switch (misc->type)
+		{
+			case AF_MISC_NAME:
+				chunkType = "NAME"; break;
+			case AF_MISC_AUTH:
+				chunkType = "AUTH"; break;
+			case AF_MISC_COPY:
+				chunkType = "(c) "; break;
+			case AF_MISC_ANNO:
+				chunkType = "ANNO"; break;
+			case AF_MISC_MIDI:
+				chunkType = "MIDI"; break;
+			case AF_MISC_APPL:
+				chunkType = "APPL"; break;
+		}
+
+		writeTag(&chunkType);
+
+		chunkSize = misc->size;
+		writeU32(&chunkSize);
+		/*
+			Write the miscellaneous buffer and then a pad byte
+			if necessary.  If the buffer is null, skip the space
+			for now.
+		*/
+		if (misc->buffer != NULL)
+			m_fh->write(misc->buffer, misc->size);
+		else
+			m_fh->seek(misc->size, File::SeekFromCurrent);
+
+		if (misc->size % 2 != 0)
+			writeU8(&padByte);
+	}
+
+	return AF_SUCCEED;
+}
+
+void AIFFFile::initCompressionParams()
+{
+	Track *track = getTrack();
+	if (track->f.compressionType == AF_COMPRESSION_IMA)
+		initIMACompressionParams();
+}
+
+void AIFFFile::initIMACompressionParams()
+{
+	Track *track = getTrack();
+
+	track->f.bytesPerPacket = 34 * track->f.channelCount;
+	track->f.framesPerPacket = 64;
+
+	AUpvlist pv = AUpvnew(1);
+	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = _AF_IMA_ADPCM_TYPE_QT;
+	AUpvsetval(pv, 0, &l);
+
+	track->f.compressionParams = pv;
+}
+
+// Read a Pascal-style string.
+bool AIFFFile::readPString(char s[256])
+{
+	uint8_t length;
+	if (m_fh->read(&length, 1) != 1)
+		return false;
+	if (m_fh->read(s, length) != static_cast<ssize_t>(length))
+		return false;
+	s[length] = '\0';
+	return true;
+}
+
+// Write a Pascal-style string.
+bool AIFFFile::writePString(const char *s)
+{
+	size_t length = strlen(s);
+	if (length > 255)
+		return false;
+	uint8_t sizeByte = static_cast<uint8_t>(length);
+	if (m_fh->write(&sizeByte, 1) != 1)
+		return false;
+	if (m_fh->write(s, length) != (ssize_t) length)
+		return false;
+	/*
+		Add a pad byte if the length of the Pascal-style string
+		(including the size byte) is odd.
+	*/
+	if ((length % 2) == 0)
+	{
+		uint8_t zero = 0;
+		if (m_fh->write(&zero, 1) != 1)
+			return false;
+	}
+	return true;
+}
diff --git a/libaudiofile/AIFF.h b/libaudiofile/AIFF.h
new file mode 100644
index 0000000..1d6fdf5
--- /dev/null
+++ b/libaudiofile/AIFF.h
@@ -0,0 +1,92 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2003-2004, 2010-2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	AIFF.h
+
+	This file contains structures and constants related to the AIFF
+	and AIFF-C formats.
+*/
+
+#ifndef AIFF_H
+#define AIFF_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+#define _AF_AIFF_NUM_INSTPARAMS 9
+extern const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS];
+#define _AF_AIFFC_NUM_COMPTYPES 3
+extern const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES];
+
+class AIFFFile : public _AFfilehandle
+{
+public:
+	AIFFFile();
+
+	static bool recognizeAIFF(File *fh);
+	static bool recognizeAIFFC(File *fh);
+
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	int getVersion() OVERRIDE;
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+
+	status update() OVERRIDE;
+
+	bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;
+
+private:
+	AFfileoffset m_miscellaneousPosition;
+	AFfileoffset m_FVER_offset;
+	AFfileoffset m_COMM_offset;
+	AFfileoffset m_MARK_offset;
+	AFfileoffset m_INST_offset;
+	AFfileoffset m_AESD_offset;
+	AFfileoffset m_SSND_offset;
+
+	status parseFVER(const Tag &type, size_t size);
+	status parseAESD(const Tag &type, size_t size);
+	status parseMiscellaneous(const Tag &type, size_t size);
+	status parseINST(const Tag &type, size_t size);
+	status parseMARK(const Tag &type, size_t size);
+	status parseCOMM(const Tag &type, size_t size);
+	status parseSSND(const Tag &type, size_t size);
+
+	status writeCOMM();
+	status writeSSND();
+	status writeMARK();
+	status writeINST();
+	status writeFVER();
+	status writeAESD();
+	status writeMiscellaneous();
+
+	void initCompressionParams();
+	void initIMACompressionParams();
+
+	bool isAIFFC() const { return m_fileFormat == AF_FILE_AIFFC; }
+
+	bool readPString(char s[256]);
+	bool writePString(const char *);
+};
+
+#endif
diff --git a/libaudiofile/AVR.cpp b/libaudiofile/AVR.cpp
new file mode 100644
index 0000000..7952672
--- /dev/null
+++ b/libaudiofile/AVR.cpp
@@ -0,0 +1,343 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	AVR.cpp
+
+	This file contains routines for reading and writing AVR (Audio
+	Visual Research) sound files.
+*/
+
+#include "config.h"
+#include "AVR.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+
+static const _AFfilesetup avrDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_AVR,		/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+AVRFile::AVRFile()
+{
+	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
+}
+
+bool AVRFile::recognize(File *fh)
+{
+	uint32_t	magic;
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(&magic, 4) != 4 || memcmp(&magic, "2BIT", 4) != 0)
+		return false;
+
+	return true;
+}
+
+status AVRFile::readInit(AFfilesetup setup)
+{
+	uint32_t	magic;
+	char		name[8];
+	uint16_t	mono, resolution, sign, loop, midi;
+	uint32_t	rate, size, loopStart, loopEnd;
+	char		reserved[26];
+	char		user[64];
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	if (m_fh->read(&magic, 4) != 4)
+	{
+		_af_error(AF_BAD_READ, "could not read AVR file header");
+		return AF_FAIL;
+	}
+
+	if (memcmp(&magic, "2BIT", 4) != 0)
+	{
+		_af_error(AF_BAD_FILEFMT, "file is not AVR format");
+		return AF_FAIL;
+	}
+
+	/* Read name. */
+	m_fh->read(name, 8);
+
+	readU16(&mono);
+	readU16(&resolution);
+	readU16(&sign);
+	readU16(&loop);
+	readU16(&midi);
+
+	readU32(&rate);
+	readU32(&size);
+	readU32(&loopStart);
+	readU32(&loopEnd);
+
+	m_fh->read(reserved, 26);
+	m_fh->read(user, 64);
+
+	Track *track = allocateTrack();
+	if (!track)
+		return AF_FAIL;
+
+	/* Use only low-order three bytes of sample rate. */
+	track->f.sampleRate = rate & 0xffffff;
+
+	if (sign == 0)
+		track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+	else if (sign == 0xffff)
+		track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+	else
+	{
+		_af_error(AF_BAD_SAMPFMT, "bad sample format in AVR file");
+		return AF_FAIL;
+	}
+
+	if (resolution != 8 && resolution != 16)
+	{
+		_af_error(AF_BAD_WIDTH, "bad sample width %d in AVR file",
+			resolution);
+		return AF_FAIL;
+	}
+	track->f.sampleWidth = resolution;
+
+	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+	if (mono == 0)
+		track->f.channelCount = 1;
+	else if (mono == 0xffff)
+		track->f.channelCount = 2;
+	else
+	{
+		_af_error(AF_BAD_CHANNELS,
+			"invalid number of channels in AVR file");
+		return AF_FAIL;
+	}
+
+	track->f.compressionType = AF_COMPRESSION_NONE;
+
+	track->f.framesPerPacket = 1;
+	track->f.computeBytesPerPacketPCM();
+
+	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+	track->fpos_first_frame = m_fh->tell();
+	track->totalfframes = size;
+	track->data_size = track->totalfframes * track->f.bytesPerFrame(false);
+
+	/* The file has been parsed successfully. */
+	return AF_SUCCEED;
+}
+
+AFfilesetup AVRFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "AVR files must have exactly 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	/* AVR allows only unsigned and two's complement integer data. */
+	if (track->f.sampleFormat != AF_SAMPFMT_UNSIGNED &&
+		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+	{
+		_af_error(AF_BAD_FILEFMT, "AVR format does supports only unsigned and two's complement integer data");
+		return AF_NULL_FILESETUP;
+	}
+
+	/* For now we support only 8- and 16-bit samples. */
+	if (track->f.sampleWidth != 8 && track->f.sampleWidth != 16)
+	{
+		_af_error(AF_BAD_WIDTH, "invalid sample width %d for AVR file (only 8- and 16-bit sample widths are allowed)", track->f.sampleWidth);
+		return AF_NULL_FILESETUP;
+	}
+
+	/* AVR does not support compression. */
+	if (track->f.compressionType != AF_COMPRESSION_NONE)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression not supported for AVR files");
+		return AF_NULL_FILESETUP;
+	}
+
+	/* AVR audio data is big-endian. */
+	if (track->f.byteOrder != AF_BYTEORDER_BIGENDIAN)
+	{
+		if (track->byteOrderSet)
+		{
+			_af_error(AF_BAD_BYTEORDER,
+				"AVR format supports only big-endian data");
+			return AF_NULL_FILESETUP;
+		}
+		else
+			track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "AVR files do not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "AVR format does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "AVR format does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "AVR format does not support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &avrDefaultFileSetup, false);
+}
+
+status AVRFile::update()
+{
+	uint32_t	size, loopStart, loopEnd;
+
+	Track *track = getTrack();
+
+	/* Seek to the position of the size field. */
+	m_fh->seek(26, File::SeekFromBeginning);
+
+	size = track->totalfframes;
+
+	/* For the case of no loops, loopStart = 0 and loopEnd = size. */
+	loopStart = 0;
+	loopEnd = size;
+
+	writeU32(&size);
+	writeU32(&loopStart);
+	writeU32(&loopEnd);
+
+	return AF_SUCCEED;
+}
+
+static char *af_basename (char *filename)
+{
+	char	*base;
+	base = strrchr(filename, '/');
+	if (base == NULL)
+		return filename;
+	else
+		return base + 1;
+}
+
+status AVRFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	if (m_fh->seek(0, File::SeekFromBeginning) != 0)
+	{
+		_af_error(AF_BAD_LSEEK, "bad seek");
+		return AF_FAIL;
+	}
+
+	Track *track = getTrack();
+
+	char name[8];
+	uint16_t mono, resolution, sign, loop, midi;
+	uint32_t rate, size, loopStart, loopEnd;
+	char reserved[26];
+	char user[64];
+
+	m_fh->write("2BIT", 4);
+	memset(name, 0, 8);
+	if (m_fileName != NULL)
+		strncpy(name, af_basename(m_fileName), 8);
+	m_fh->write(name, 8);
+
+	if (track->f.channelCount == 1)
+		mono = 0x0;
+	else
+		mono = 0xffff;
+	writeU16(&mono);
+
+	resolution = track->f.sampleWidth;
+	writeU16(&resolution);
+
+	if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+		sign = 0x0;
+	else
+		sign = 0xffff;
+	writeU16(&sign);
+
+	/* We do not currently support loops. */
+	loop = 0;
+	writeU16(&loop);
+	midi = 0xffff;
+	writeU16(&midi);
+
+	rate = track->f.sampleRate;
+	/* Set the high-order byte of rate to 0xff. */
+	rate |= 0xff000000;
+	size = track->totalfframes;
+	loopStart = 0;
+	loopEnd = size;
+
+	writeU32(&rate);
+	writeU32(&size);
+	writeU32(&loopStart);
+	writeU32(&loopEnd);
+
+	memset(reserved, 0, 26);
+	m_fh->write(reserved, 26);
+
+	memset(user, 0, 64);
+	m_fh->write(user, 64);
+
+	if (track->fpos_first_frame == 0)
+		track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/AVR.h b/libaudiofile/AVR.h
new file mode 100644
index 0000000..4339055
--- /dev/null
+++ b/libaudiofile/AVR.h
@@ -0,0 +1,47 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	AVR.h
+
+	This file contains headers and constants related to the AVR
+	(Audio Visual Research) sound file format.
+*/
+
+#ifndef AVR_H
+#define AVR_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+class AVRFile : public _AFfilehandle
+{
+public:
+	AVRFile();
+
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+};
+
+#endif
diff --git a/libaudiofile/AudioFormat.cpp b/libaudiofile/AudioFormat.cpp
new file mode 100644
index 0000000..3ac457c
--- /dev/null
+++ b/libaudiofile/AudioFormat.cpp
@@ -0,0 +1,164 @@
+/*
+	Audio File Library
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "AudioFormat.h"
+
+#include "afinternal.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "units.h"
+#include "util.h"
+#include <assert.h>
+#include <stdio.h>
+
+size_t AudioFormat::bytesPerSample(bool stretch3to4) const
+{
+	switch (sampleFormat)
+	{
+		case AF_SAMPFMT_FLOAT:
+			return sizeof (float);
+		case AF_SAMPFMT_DOUBLE:
+			return sizeof (double);
+		default:
+		{
+			int size = (sampleWidth + 7) / 8;
+			if (compressionType == AF_COMPRESSION_NONE &&
+				size == 3 && stretch3to4)
+				size = 4;
+			return size;
+		}
+	}
+}
+
+size_t AudioFormat::bytesPerFrame(bool stretch3to4) const
+{
+	return bytesPerSample(stretch3to4) * channelCount;
+}
+
+size_t AudioFormat::bytesPerSample() const
+{
+	return bytesPerSample(!isPacked());
+}
+
+size_t AudioFormat::bytesPerFrame() const
+{
+	return bytesPerFrame(!isPacked());
+}
+
+bool AudioFormat::isInteger() const
+{
+	return sampleFormat == AF_SAMPFMT_TWOSCOMP ||
+		sampleFormat == AF_SAMPFMT_UNSIGNED;
+}
+
+bool AudioFormat::isSigned() const
+{
+	return sampleFormat == AF_SAMPFMT_TWOSCOMP;
+}
+
+bool AudioFormat::isUnsigned() const
+{
+	return sampleFormat == AF_SAMPFMT_UNSIGNED;
+}
+
+bool AudioFormat::isFloat() const
+{
+	return sampleFormat == AF_SAMPFMT_FLOAT ||
+		sampleFormat == AF_SAMPFMT_DOUBLE;
+}
+
+bool AudioFormat::isCompressed() const
+{
+	return compressionType != AF_COMPRESSION_NONE;
+}
+
+bool AudioFormat::isUncompressed() const
+{
+	return compressionType == AF_COMPRESSION_NONE;
+}
+
+void AudioFormat::computeBytesPerPacketPCM()
+{
+	assert(isUncompressed());
+	int bytesPerSample = (sampleWidth + 7) / 8;
+	bytesPerPacket = bytesPerSample * channelCount;
+}
+
+std::string AudioFormat::description() const
+{
+	std::string d;
+	char s[1024];
+	/* sampleRate, channelCount */
+	sprintf(s, "{ %7.2f Hz %d ch ", sampleRate, channelCount);
+	d += s;
+
+	/* sampleFormat, sampleWidth */
+	switch (sampleFormat)
+	{
+		case AF_SAMPFMT_TWOSCOMP:
+			sprintf(s, "%db 2 ", sampleWidth);
+			break;
+		case AF_SAMPFMT_UNSIGNED:
+			sprintf(s, "%db u ", sampleWidth);
+			break;
+		case AF_SAMPFMT_FLOAT:
+			sprintf(s, "flt ");
+			break;
+		case AF_SAMPFMT_DOUBLE:
+			sprintf(s, "dbl ");
+			break;
+		default:
+			assert(false);
+			break;
+	}
+
+	d += s;
+
+	/* pcm */
+	sprintf(s, "(%.30g+-%.30g [%.30g,%.30g]) ",
+		pcm.intercept, pcm.slope,
+		pcm.minClip, pcm.maxClip);
+	d += s;
+
+	/* byteOrder */
+	switch (byteOrder)
+	{
+		case AF_BYTEORDER_BIGENDIAN:
+			d += "big ";
+			break;
+		case AF_BYTEORDER_LITTLEENDIAN:
+			d += "little ";
+			break;
+		default:
+			assert(false);
+			break;
+	}
+
+	if (isCompressed())
+	{
+		const CompressionUnit *unit = _af_compression_unit_from_id(compressionType);
+		assert(unit);
+		d += "compression: ";
+		d += unit->label;
+	}
+
+	return d;
+}
diff --git a/libaudiofile/AudioFormat.h b/libaudiofile/AudioFormat.h
new file mode 100644
index 0000000..e6efc25
--- /dev/null
+++ b/libaudiofile/AudioFormat.h
@@ -0,0 +1,71 @@
+/*
+	Audio File Library
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef AUDIOFORMAT_H
+#define AUDIOFORMAT_H
+
+#include "aupvlist.h"
+
+#include <sys/types.h>
+#include <string>
+
+struct PCMInfo
+{
+	double slope, intercept, minClip, maxClip;
+};
+
+struct AudioFormat
+{
+	double sampleRate;		/* sampling rate in Hz */
+	int sampleFormat;		/* AF_SAMPFMT_... */
+	int sampleWidth;		/* sample width in bits */
+	int byteOrder;		/* AF_BYTEORDER_... */
+
+	PCMInfo pcm;		/* parameters of PCM data */
+
+	int channelCount;		/* number of channels */
+
+	int compressionType;	/* AF_COMPRESSION_... */
+	AUpvlist compressionParams;	/* NULL if no compression */
+
+	bool packed : 1;
+
+	size_t framesPerPacket;
+	size_t bytesPerPacket;
+
+	size_t bytesPerSample(bool stretch3to4) const;
+	size_t bytesPerFrame(bool stretch3to4) const;
+	size_t bytesPerSample() const;
+	size_t bytesPerFrame() const;
+	bool isInteger() const;
+	bool isSigned() const;
+	bool isUnsigned() const;
+	bool isFloat() const;
+	bool isCompressed() const;
+	bool isUncompressed() const;
+	bool isPacked() const { return packed; }
+	bool isByteOrderSignificant() const { return sampleWidth > 8; }
+
+	void computeBytesPerPacketPCM();
+
+	std::string description() const;
+};
+
+#endif
diff --git a/libaudiofile/Buffer.cpp b/libaudiofile/Buffer.cpp
new file mode 100644
index 0000000..84b0848
--- /dev/null
+++ b/libaudiofile/Buffer.cpp
@@ -0,0 +1,54 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "Buffer.h"
+
+#include <string.h>
+
+Buffer::Buffer() : m_data(0), m_size(0)
+{
+}
+
+Buffer::Buffer(size_t size) : m_data(0), m_size(0)
+{
+	if (size)
+		m_data = ::operator new(size);
+	if (m_data)
+	{
+		m_size = size;
+	}
+}
+
+Buffer::Buffer(const void *data, size_t size) : m_data(0), m_size(0)
+{
+	if (size)
+		m_data = ::operator new(size);
+	if (m_data)
+	{
+		::memcpy(m_data, data, m_size);
+		m_size = size;
+	}
+}
+
+Buffer::~Buffer()
+{
+	::operator delete(m_data);
+}
diff --git a/libaudiofile/Buffer.h b/libaudiofile/Buffer.h
new file mode 100644
index 0000000..a40a411
--- /dev/null
+++ b/libaudiofile/Buffer.h
@@ -0,0 +1,46 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef Buffer_h
+#define Buffer_h
+
+#include "Shared.h"
+
+#include <sys/types.h>
+
+class Buffer : public Shared<Buffer>
+{
+public:
+	Buffer();
+	Buffer(size_t size);
+	Buffer(const void *data, size_t size);
+	~Buffer();
+
+	void *data() { return m_data; }
+	const void *data() const { return m_data; }
+
+	size_t size() const { return m_size; }
+
+private:
+	void *m_data;
+	size_t m_size;
+};
+
+#endif
diff --git a/libaudiofile/CAF.cpp b/libaudiofile/CAF.cpp
new file mode 100644
index 0000000..5752117
--- /dev/null
+++ b/libaudiofile/CAF.cpp
@@ -0,0 +1,738 @@
+/*
+	Audio File Library
+	Copyright (C) 2011-2013, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "CAF.h"
+
+#include "Buffer.h"
+#include "File.h"
+#include "PacketTable.h"
+#include "Setup.h"
+#include "Tag.h"
+#include "Track.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <string>
+#include <vector>
+
+const int _af_caf_compression_types[_AF_CAF_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW,
+	AF_COMPRESSION_IMA,
+	AF_COMPRESSION_ALAC
+};
+
+enum
+{
+	kCAFLinearPCMFormatFlagIsFloat = (1L << 0),
+	kCAFLinearPCMFormatFlagIsLittleEndian = (1L << 1)
+};
+
+enum
+{
+	kALACFormatFlag_16BitSourceData = 1,
+	kALACFormatFlag_20BitSourceData = 2,
+	kALACFormatFlag_24BitSourceData = 3,
+	kALACFormatFlag_32BitSourceData = 4
+};
+
+static const unsigned kALACDefaultFramesPerPacket = 4096;
+
+static const _AFfilesetup cafDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	// valid
+	AF_FILE_CAF,			// fileFormat
+	true,					// trackSet
+	true,					// instrumentSet
+	true,					// miscellaneousSet
+	1,						// trackCount
+	NULL,					// tracks
+	1,						// instrumentCount
+	NULL,					// instruments
+	0,						// miscellaneousCount
+	NULL					// miscellaneous
+};
+
+CAFFile::CAFFile() :
+	m_dataOffset(-1),
+	m_cookieDataOffset(-1)
+{
+	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
+}
+
+CAFFile::~CAFFile()
+{
+}
+
+bool CAFFile::recognize(File *file)
+{
+	file->seek(0, File::SeekFromBeginning);
+	uint8_t buffer[8];
+	if (file->read(buffer, 8) != 8 || memcmp(buffer, "caff", 4) != 0)
+		return false;
+	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
+	if (memcmp(buffer + 4, versionAndFlags, 4) != 0)
+		return false;
+	return true;
+}
+
+status CAFFile::readInit(AFfilesetup setup)
+{
+	m_fh->seek(8, File::SeekFromBeginning);
+
+	if (!allocateTrack())
+		return AF_FAIL;
+
+	off_t currentOffset = m_fh->tell();
+	off_t fileLength = m_fh->length();
+
+	while (currentOffset < fileLength)
+	{
+		Tag chunkType;
+		int64_t chunkLength;
+		if (!readTag(&chunkType) ||
+			!readS64(&chunkLength))
+			return AF_FAIL;
+
+		currentOffset += 12;
+
+		if (chunkType == "data" && chunkLength == -1)
+			chunkLength = fileLength - currentOffset;
+		else if (chunkLength < 0)
+			_af_error(AF_BAD_HEADER,
+				"invalid chunk length %jd for chunk type %s\n",
+				static_cast<intmax_t>(chunkLength), chunkType.name().c_str());
+
+		if (chunkType == "desc")
+		{
+			if (parseDescription(chunkType, chunkLength) == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkType == "data")
+		{
+			if (parseData(chunkType, chunkLength) == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkType == "pakt")
+		{
+			if (parsePacketTable(chunkType, chunkLength) == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkType == "kuki")
+		{
+			if (parseCookieData(chunkType, chunkLength) == AF_FAIL)
+				return AF_FAIL;
+		}
+
+		currentOffset = m_fh->seek(currentOffset + chunkLength,
+			File::SeekFromBeginning);
+	}
+
+	return AF_SUCCEED;
+}
+
+status CAFFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	initCompressionParams();
+
+	Tag caff("caff");
+	if (!writeTag(&caff)) return AF_FAIL;
+	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
+	if (m_fh->write(versionAndFlags, 4) != 4) return AF_FAIL;
+
+	if (writeDescription() == AF_FAIL)
+		return AF_FAIL;
+	if (writeCookieData() == AF_FAIL)
+		return AF_FAIL;
+	if (writeData(false) == AF_FAIL)
+		return AF_FAIL;
+
+	return AF_SUCCEED;
+}
+
+AFfilesetup CAFFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "CAF file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		if (track->f.isUnsigned())
+		{
+			_af_error(AF_BAD_FILEFMT, "CAF format does not support unsigned data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+	else
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+			track->f.sampleWidth);
+
+	if (track->f.isSigned() && (track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
+	{
+		_af_error(AF_BAD_WIDTH,
+			"invalid sample width %d for CAF file (must be 1-32)",
+			track->f.sampleWidth);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (!track->byteOrderSet)
+		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
+		track->f.compressionType != AF_COMPRESSION_IMA &&
+		track->f.compressionType != AF_COMPRESSION_ALAC)
+	{
+		_af_error(AF_BAD_COMPTYPE,
+			"compression format %d not supported in CAF file",
+			track->f.compressionType);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "CAF does not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &cafDefaultFileSetup, true);
+}
+
+status CAFFile::update()
+{
+	if (writeCookieData() == AF_FAIL)
+		return AF_FAIL;
+	if (writeData(true) == AF_FAIL)
+		return AF_FAIL;
+	if (writePacketTable() == AF_FAIL)
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status CAFFile::parseDescription(const Tag &, int64_t)
+{
+	double sampleRate;
+	Tag formatID;
+	uint32_t formatFlags;
+	uint32_t bytesPerPacket;
+	uint32_t framesPerPacket;
+	uint32_t channelsPerFrame;
+	uint32_t bitsPerChannel;
+	if (!readDouble(&sampleRate) ||
+		!readTag(&formatID) ||
+		!readU32(&formatFlags) ||
+		!readU32(&bytesPerPacket) ||
+		!readU32(&framesPerPacket) ||
+		!readU32(&channelsPerFrame) ||
+		!readU32(&bitsPerChannel))
+		return AF_FAIL;
+
+	if (!channelsPerFrame)
+	{
+		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
+		return AF_FAIL;
+	}
+
+	Track *track = getTrack();
+	track->f.channelCount = channelsPerFrame;
+	track->f.sampleWidth = bitsPerChannel;
+	track->f.sampleRate = sampleRate;
+	track->f.framesPerPacket = 1;
+
+	if (formatID == "lpcm")
+	{
+		track->f.compressionType = AF_COMPRESSION_NONE;
+		if (formatFlags & kCAFLinearPCMFormatFlagIsFloat)
+		{
+			if (bitsPerChannel != 32 && bitsPerChannel != 64)
+			{
+				_af_error(AF_BAD_WIDTH, "invalid bits per sample %d for floating-point audio data", bitsPerChannel);
+				return AF_FAIL;
+			}
+			track->f.sampleFormat = bitsPerChannel == 32 ? AF_SAMPFMT_FLOAT :
+				AF_SAMPFMT_DOUBLE;
+		}
+		else
+		{
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+		}
+		track->f.byteOrder = (formatFlags & kCAFLinearPCMFormatFlagIsLittleEndian) ?
+			AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;
+
+		if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
+			return AF_FAIL;
+
+		track->f.computeBytesPerPacketPCM();
+		return AF_SUCCEED;
+	}
+	else if (formatID == "ulaw")
+	{
+		track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+		track->f.bytesPerPacket = channelsPerFrame;
+		return AF_SUCCEED;
+	}
+	else if (formatID == "alaw")
+	{
+		track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+		track->f.bytesPerPacket = channelsPerFrame;
+		return AF_SUCCEED;
+	}
+	else if (formatID == "ima4")
+	{
+		track->f.compressionType = AF_COMPRESSION_IMA;
+		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+		initIMACompressionParams();
+		return AF_SUCCEED;
+	}
+	else if (formatID == "alac")
+	{
+		track->f.compressionType = AF_COMPRESSION_ALAC;
+		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+		switch (formatFlags)
+		{
+			case kALACFormatFlag_16BitSourceData:
+				track->f.sampleWidth = 16; break;
+			case kALACFormatFlag_20BitSourceData:
+				track->f.sampleWidth = 20; break;
+			case kALACFormatFlag_24BitSourceData:
+				track->f.sampleWidth = 24; break;
+			case kALACFormatFlag_32BitSourceData:
+				track->f.sampleWidth = 32; break;
+			default:
+				_af_error(AF_BAD_CODEC_TYPE,
+					"unsupported format flags for ALAC: %u", formatFlags);
+				return AF_FAIL;
+		}
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+			track->f.sampleWidth);
+		track->f.framesPerPacket = framesPerPacket;
+		track->f.bytesPerPacket = 0;
+		return AF_SUCCEED;
+	}
+	else
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "Compression type %s not supported",
+			formatID.name().c_str());
+		return AF_FAIL;
+	}
+}
+
+status CAFFile::parseData(const Tag &tag, int64_t length)
+{
+	uint32_t editCount;
+	if (!readU32(&editCount))
+		return AF_FAIL;
+
+	Track *track = getTrack();
+	if (length == -1)
+		track->data_size = m_fh->length() - m_fh->tell();
+	else
+		track->data_size = length - 4;
+	track->fpos_first_frame = m_fh->tell();
+
+	track->computeTotalFileFrames();
+	return AF_SUCCEED;
+}
+
+static uint32_t readBERInteger(const uint8_t *input, size_t *numBytes)
+{
+	uint32_t result = 0;
+	uint8_t data;
+	size_t size = 0;
+	do
+	{
+		data = input[size];
+		result = (result << 7) | (data & 0x7f);
+		if (++size > 5)
+			return 0;
+	} while ((data & 0x80) && size < *numBytes);
+	*numBytes = size;
+	return result;
+}
+
+static void encodeBERInteger(uint32_t value, uint8_t *buffer, size_t *numBytes)
+{
+	if ((value & 0x7f) == value)
+	{
+		*numBytes = 1;
+		buffer[0] = value;
+	}
+	else if ((value & 0x3fff) == value)
+	{
+		*numBytes = 2;
+		buffer[0] = (value >> 7) | 0x80;
+		buffer[1] = value & 0x7f;
+	}
+	else if ((value & 0x1fffff) == value)
+	{
+		*numBytes = 3;
+		buffer[0] = (value >> 14) | 0x80;
+		buffer[1] = ((value >> 7) & 0x7f) | 0x80;
+		buffer[2] = value & 0x7f;
+	}
+	else if ((value & 0x0fffffff) == value)
+	{
+		*numBytes = 4;
+		buffer[0] = (value >> 21) | 0x80;
+		buffer[1] = ((value >> 14) & 0x7f) | 0x80;
+		buffer[2] = ((value >> 7) & 0x7f) | 0x80;
+		buffer[3] = value & 0x7f;
+	}
+	else
+	{
+		*numBytes = 5;
+		buffer[0] = (value >> 28) | 0x80;
+		buffer[1] = ((value >> 21) & 0x7f) | 0x80;
+		buffer[2] = ((value >> 14) & 0x7f) | 0x80;
+		buffer[3] = ((value >> 7) & 0x7f) | 0x80;
+		buffer[4] = value & 0x7f;
+	}
+}
+
+status CAFFile::parsePacketTable(const Tag &tag, int64_t length)
+{
+	if (length < 24)
+		return AF_FAIL;
+
+	int64_t numPackets;
+	int64_t numValidFrames;
+	int32_t primingFrames;
+	int32_t remainderFrames;
+	if (!readS64(&numPackets) ||
+		!readS64(&numValidFrames) ||
+		!readS32(&primingFrames) ||
+		!readS32(&remainderFrames))
+	{
+		return AF_FAIL;
+	}
+
+	if (!numPackets)
+		return AF_SUCCEED;
+
+	int64_t tableLength = length - 24;
+
+	SharedPtr<Buffer> buffer = new Buffer(tableLength);
+	if (m_fh->read(buffer->data(), tableLength) != tableLength)
+		return AF_FAIL;
+
+	SharedPtr<PacketTable> packetTable = new PacketTable(numValidFrames,
+		primingFrames, remainderFrames);
+
+	const uint8_t *data = static_cast<const uint8_t *>(buffer->data());
+	size_t position = 0;
+	while (position < buffer->size())
+	{
+		size_t sizeRemaining = buffer->size() - position;
+		uint32_t bytesPerPacket = readBERInteger(data + position, &sizeRemaining);
+		if (bytesPerPacket == 0)
+			break;
+		packetTable->append(bytesPerPacket);
+		position += sizeRemaining;
+	}
+
+	assert(numPackets == packetTable->numPackets());
+
+	Track *track = getTrack();
+	track->m_packetTable = packetTable;
+	track->totalfframes = numValidFrames;
+
+	return AF_SUCCEED;
+}
+
+status CAFFile::parseCookieData(const Tag &tag, int64_t length)
+{
+	m_codecData = new Buffer(length);
+	if (m_fh->read(m_codecData->data(), length) != length)
+		return AF_FAIL;
+
+	AUpvlist pv = AUpvnew(2);
+
+	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = length;
+	AUpvsetval(pv, 0, &l);
+
+	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
+	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
+	void *v = m_codecData->data();
+	AUpvsetval(pv, 1, &v);
+
+	Track *track = getTrack();
+	track->f.compressionParams = pv;
+
+	return AF_SUCCEED;
+}
+
+status CAFFile::writeDescription()
+{
+	Track *track = getTrack();
+
+	Tag desc("desc");
+	int64_t chunkLength = 32;
+	double sampleRate = track->f.sampleRate;
+	Tag formatID("lpcm");
+	uint32_t formatFlags = 0;
+	if (track->f.byteOrder == AF_BYTEORDER_LITTLEENDIAN)
+		formatFlags |= kCAFLinearPCMFormatFlagIsLittleEndian;
+	if (track->f.isFloat())
+		formatFlags |= kCAFLinearPCMFormatFlagIsFloat;
+	uint32_t bytesPerPacket = track->f.bytesPerFrame(false);
+	uint32_t framesPerPacket = 1;
+	uint32_t channelsPerFrame = track->f.channelCount;
+	uint32_t bitsPerChannel = track->f.sampleWidth;
+
+	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+	{
+		formatID = "ulaw";
+		formatFlags = 0;
+		bytesPerPacket = channelsPerFrame;
+		bitsPerChannel = 8;
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+	{
+		formatID = "alaw";
+		formatFlags = 0;
+		bytesPerPacket = channelsPerFrame;
+		bitsPerChannel = 8;
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_IMA)
+	{
+		formatID = "ima4";
+		formatFlags = 0;
+		bytesPerPacket = track->f.bytesPerPacket;
+		framesPerPacket = track->f.framesPerPacket;
+		bitsPerChannel = 16;
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
+	{
+		formatID = "alac";
+		switch (track->f.sampleWidth)
+		{
+			case 16: formatFlags = kALACFormatFlag_16BitSourceData; break;
+			case 20: formatFlags = kALACFormatFlag_20BitSourceData; break;
+			case 24: formatFlags = kALACFormatFlag_24BitSourceData; break;
+			case 32: formatFlags = kALACFormatFlag_32BitSourceData; break;
+		}
+		bytesPerPacket = track->f.bytesPerPacket;
+		framesPerPacket = track->f.framesPerPacket;
+	}
+
+	if (!writeTag(&desc) ||
+		!writeS64(&chunkLength) ||
+		!writeDouble(&sampleRate) ||
+		!writeTag(&formatID) ||
+		!writeU32(&formatFlags) ||
+		!writeU32(&bytesPerPacket) ||
+		!writeU32(&framesPerPacket) ||
+		!writeU32(&channelsPerFrame) ||
+		!writeU32(&bitsPerChannel))
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status CAFFile::writeData(bool update)
+{
+	Track *track = getTrack();
+
+	if (m_dataOffset == -1)
+		m_dataOffset = m_fh->tell();
+	else
+		m_fh->seek(m_dataOffset, File::SeekFromBeginning);
+
+	Tag data("data");
+	int64_t dataLength = -1;
+	uint32_t editCount = 0;
+	if (update)
+		dataLength = track->data_size + 4;
+
+	if (!writeTag(&data) ||
+		!writeS64(&dataLength) ||
+		!writeU32(&editCount))
+		return AF_FAIL;
+	if (track->fpos_first_frame == 0)
+		track->fpos_first_frame = m_fh->tell();
+	return AF_SUCCEED;
+}
+
+status CAFFile::writePacketTable()
+{
+	Track *track = getTrack();
+
+	m_fh->seek(track->fpos_after_data, File::SeekFromBeginning);
+
+	SharedPtr<PacketTable> packetTable = track->m_packetTable;
+	if (!packetTable)
+		return AF_SUCCEED;
+
+	int64_t numPackets = packetTable->numPackets();
+	int64_t numValidFrames = packetTable->numValidFrames();
+	int32_t primingFrames = packetTable->primingFrames();
+	int32_t remainderFrames = packetTable->remainderFrames();
+
+	SharedPtr<Buffer> buffer = new Buffer(packetTable->numPackets() * 5);
+
+	uint8_t *data = static_cast<uint8_t *>(buffer->data());
+	size_t position = 0;
+	for (unsigned i=0; i<packetTable->numPackets(); i++)
+	{
+		uint32_t bytesPerPacket = packetTable->bytesPerPacket(i);
+		size_t numBytes = 0;
+		encodeBERInteger(bytesPerPacket, data + position, &numBytes);
+		position += numBytes;
+	}
+
+	Tag pakt("pakt");
+	int64_t packetTableLength = 24 + position;
+
+	if (!writeTag(&pakt) ||
+		!writeS64(&packetTableLength) ||
+		!writeS64(&numPackets) ||
+		!writeS64(&numValidFrames) ||
+		!writeS32(&primingFrames) ||
+		!writeS32(&remainderFrames) ||
+		m_fh->write(buffer->data(), position) != static_cast<ssize_t>(position))
+	{
+		return AF_FAIL;
+	}
+
+	return AF_SUCCEED;
+}
+
+status CAFFile::writeCookieData()
+{
+	if (!m_codecData)
+		return AF_SUCCEED;
+
+	if (m_cookieDataOffset == -1)
+		m_cookieDataOffset = m_fh->tell();
+	else
+		m_fh->seek(m_cookieDataOffset, File::SeekFromBeginning);
+
+	Tag kuki("kuki");
+	int64_t cookieDataLength = m_codecData->size();
+	if (!writeTag(&kuki) ||
+		!writeS64(&cookieDataLength) ||
+		m_fh->write(m_codecData->data(), m_codecData->size()) != static_cast<ssize_t>(m_codecData->size()))
+	{
+		return AF_FAIL;
+	}
+
+	return AF_SUCCEED;
+}
+
+void CAFFile::initCompressionParams()
+{
+	Track *track = getTrack();
+	if (track->f.compressionType == AF_COMPRESSION_IMA)
+		initIMACompressionParams();
+	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
+		initALACCompressionParams();
+}
+
+void CAFFile::initIMACompressionParams()
+{
+	Track *track = getTrack();
+
+	track->f.bytesPerPacket = 34 * track->f.channelCount;
+	track->f.framesPerPacket = 64;
+
+	AUpvlist pv = AUpvnew(1);
+	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = _AF_IMA_ADPCM_TYPE_QT;
+	AUpvsetval(pv, 0, &l);
+
+	track->f.compressionParams = pv;
+}
+
+void CAFFile::initALACCompressionParams()
+{
+	if (m_access == _AF_READ_ACCESS)
+		return;
+
+	Track *track = getTrack();
+
+	track->f.bytesPerPacket = 0;
+	track->f.framesPerPacket = kALACDefaultFramesPerPacket;
+
+	const unsigned kALACSpecificConfigSize = 24;
+	const unsigned kChannelAtomSize = 12;
+	const unsigned kALACAudioChannelLayoutSize = 12;
+
+	unsigned codecDataSize = kALACSpecificConfigSize;
+	if (track->f.channelCount > 2)
+		codecDataSize += kChannelAtomSize + kALACAudioChannelLayoutSize;
+	m_codecData = new Buffer(codecDataSize);
+	memset(m_codecData->data(), 0, m_codecData->size());
+
+	AUpvlist pv = AUpvnew(2);
+
+	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = codecDataSize;
+	AUpvsetval(pv, 0, &l);
+
+	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
+	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
+	void *v = m_codecData->data();
+	AUpvsetval(pv, 1, &v);
+
+	track->f.compressionParams = pv;
+
+	track->m_packetTable = new PacketTable();
+}
diff --git a/libaudiofile/CAF.h b/libaudiofile/CAF.h
new file mode 100644
index 0000000..5f42087
--- /dev/null
+++ b/libaudiofile/CAF.h
@@ -0,0 +1,68 @@
+/*
+	Audio File Library
+	Copyright (C) 2011-2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef CAF_H
+#define CAF_H
+
+#include "Compiler.h"
+#include "File.h"
+#include "FileHandle.h"
+#include "Tag.h"
+#include <stdint.h>
+
+#define _AF_CAF_NUM_COMPTYPES 4
+extern const int _af_caf_compression_types[_AF_CAF_NUM_COMPTYPES];
+
+class Buffer;
+
+class CAFFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	CAFFile();
+	~CAFFile();
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+	AFfileoffset m_dataOffset;
+	AFfileoffset m_cookieDataOffset;
+	SharedPtr<Buffer> m_codecData;
+
+	status parseDescription(const Tag &, int64_t);
+	status parseData(const Tag &, int64_t);
+	status parsePacketTable(const Tag &, int64_t);
+	status parseCookieData(const Tag &, int64_t);
+
+	status writeDescription();
+	status writeData(bool update);
+	status writePacketTable();
+	status writeCookieData();
+
+	void initCompressionParams();
+	void initIMACompressionParams();
+	void initALACCompressionParams();
+};
+
+#endif
diff --git a/libaudiofile/Compiler.h b/libaudiofile/Compiler.h
new file mode 100644
index 0000000..446ec00
--- /dev/null
+++ b/libaudiofile/Compiler.h
@@ -0,0 +1,43 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#if defined(__GNUC__) && !defined(__clang__)
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#define GCC_VERSION_AT_LEAST(major, minor, patch) \
+	(GCC_VERSION >= (major * 10000 + minor * 100 + patch))
+#if GCC_VERSION_AT_LEAST(4, 7, 0) && defined(__cplusplus) && __cplusplus >= 201103L
+#define OVERRIDE override
+#endif
+#endif
+
+#if defined(__clang__)
+#if __has_extension(cxx_override_control)
+#define OVERRRIDE override
+#endif
+#endif
+
+#ifndef OVERRIDE
+#define OVERRIDE
+#endif
+
+#endif
diff --git a/libaudiofile/FLACFile.cpp b/libaudiofile/FLACFile.cpp
new file mode 100644
index 0000000..df11b8b
--- /dev/null
+++ b/libaudiofile/FLACFile.cpp
@@ -0,0 +1,303 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "FLACFile.h"
+
+#include "File.h"
+#include "Setup.h"
+#include "Track.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include <string.h>
+
+const int _af_flac_compression_types[_AF_FLAC_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_FLAC
+};
+
+const _AFfilesetup flacDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,
+	AF_FILE_FLAC,
+	true,
+	true,
+	true,
+	1,		// trackCount
+	NULL,	// tracks
+	0,		// instrumentCount
+	NULL,	// instruments
+	0,		// miscellaneousCount
+	NULL	// miscellaneous
+};
+
+bool FLACFile::recognize(File *file)
+{
+	file->seek(0, File::SeekFromBeginning);
+	uint8_t buffer[4];
+	if (file->read(buffer, 4) != 4 || memcmp(buffer, "fLaC", 4) != 0)
+		return false;
+	return true;
+}
+
+FLACFile::FLACFile()
+{
+}
+
+FLACFile::~FLACFile()
+{
+}
+
+#if ENABLE(FLAC)
+
+AFfilesetup FLACFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "FLAC file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet &&
+		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+	{
+		_af_error(AF_BAD_SAMPFMT,
+			"FLAC files support only signed integer audio data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->sampleWidthSet &&
+		track->f.sampleWidth != 16 && track->f.sampleWidth != 24)
+	{
+		_af_error(AF_BAD_WIDTH,
+			"FLAC files support only 16- or 24-bit audio data");
+		return AF_NULL_FILESETUP;
+	}
+
+	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
+
+	track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+	if (track->compressionSet &&
+		track->f.compressionType != AF_COMPRESSION_FLAC)
+	{
+		_af_error(AF_BAD_COMPTYPE, "Only FLAC compression supported in FLAC files");
+		return AF_NULL_FILESETUP;
+	}
+
+	track->f.compressionType = AF_COMPRESSION_FLAC;
+
+	if (track->markersSet && track->markerCount)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "FLAC does not yet support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "FLAC does not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount)
+	{
+		_af_error(AF_BAD_FILESETUP, "FLAC does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "FLAC does not yet support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &flacDefaultFileSetup, true);
+}
+
+status FLACFile::readInit(AFfilesetup)
+{
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+
+	if (FLAC__stream_decoder_init_stream(decoder,
+		readCallback,
+		seekCallback,
+		tellCallback,
+		lengthCallback,
+		eofCallback,
+		writeCallback,
+		metadataCallback,
+		errorCallback,
+		this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+	{
+		_af_error(AF_BAD_HEADER, "could not read FLAC file");
+		return AF_FAIL;
+	}
+
+	if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		return AF_FAIL;
+
+	FLAC__uint64 position;
+	if (!FLAC__stream_decoder_get_decode_position(decoder, &position))
+		return AF_FAIL;
+
+	Track *track = getTrack();
+	if (track)
+	{
+		track->fpos_first_frame = static_cast<off_t>(position);
+		track->data_size = m_fh->length() - track->fpos_first_frame;
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+
+	if (!track)
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status FLACFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	return AF_SUCCEED;
+}
+
+status FLACFile::update()
+{
+	return AF_SUCCEED;
+}
+
+void FLACFile::parseStreamInfo(const FLAC__StreamMetadata_StreamInfo &streamInfo)
+{
+	Track *track = allocateTrack();
+
+	track->f.channelCount = streamInfo.channels;
+	track->f.sampleRate = streamInfo.sample_rate;
+
+	track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+	track->f.framesPerPacket = 0;
+	track->f.bytesPerPacket = 0;
+
+	track->f.compressionType = AF_COMPRESSION_FLAC;
+	track->f.compressionParams = NULL;
+
+	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, streamInfo.bits_per_sample);
+
+	track->totalfframes = streamInfo.total_samples;
+}
+
+FLAC__StreamDecoderReadStatus FLACFile::readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	ssize_t result = flac->m_fh->read(buffer, *bytes);
+	if (result > 0)
+	{
+		*bytes = result;
+		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+
+	*bytes = 0;
+	return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+FLAC__StreamDecoderSeekStatus FLACFile::seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	if (flac->m_fh->seek(static_cast<off_t>(absoluteByteOffset), File::SeekFromBeginning) < 0)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus FLACFile::tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	off_t result = flac->m_fh->tell();
+	if (result < 0)
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	*absoluteByteOffset = static_cast<FLAC__uint64>(result);
+	return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+FLAC__StreamDecoderLengthStatus FLACFile::lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	off_t result = flac->m_fh->length();
+	if (result < 0)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	*length = result;
+	return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+FLAC__bool FLACFile::eofCallback(const FLAC__StreamDecoder *, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	return flac->m_fh->tell() == flac->m_fh->length();
+}
+
+FLAC__StreamDecoderWriteStatus FLACFile::writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData)
+{
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void FLACFile::metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData)
+{
+	FLACFile *flac = static_cast<FLACFile *>(clientData);
+	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
+		flac->parseStreamInfo(metadata->data.stream_info);
+}
+
+void FLACFile::errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData)
+{
+	_af_error(AF_BAD_FILEFMT, "error %d parsing FLAC file", status);
+}
+
+#else
+
+AFfilesetup FLACFile::completeSetup(AFfilesetup)
+{
+	_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
+	return AF_NULL_FILESETUP;
+}
+
+status FLACFile::readInit(AFfilesetup)
+{
+	_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
+	return AF_FAIL;
+}
+
+status FLACFile::writeInit(AFfilesetup)
+{
+	return AF_FAIL;
+}
+
+status FLACFile::update()
+{
+	return AF_FAIL;
+}
+
+#endif
diff --git a/libaudiofile/FLACFile.h b/libaudiofile/FLACFile.h
new file mode 100644
index 0000000..f074b23
--- /dev/null
+++ b/libaudiofile/FLACFile.h
@@ -0,0 +1,64 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef FLACFile_h
+#define FLACFile_h
+
+#include "Compiler.h"
+#include "FileHandle.h"
+#include "Features.h"
+
+#if ENABLE(FLAC)
+#include <FLAC/format.h>
+#include <FLAC/stream_decoder.h>
+#endif
+
+#define _AF_FLAC_NUM_COMPTYPES 1
+extern const int _af_flac_compression_types[_AF_FLAC_NUM_COMPTYPES];
+
+class FLACFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	FLACFile();
+	~FLACFile();
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+#if ENABLE(FLAC)
+	void parseStreamInfo(const FLAC__StreamMetadata_StreamInfo &);
+
+	static FLAC__StreamDecoderReadStatus readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData);
+	static FLAC__StreamDecoderSeekStatus seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData);
+	static FLAC__StreamDecoderTellStatus tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData);
+	static FLAC__StreamDecoderLengthStatus lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData);
+	static FLAC__bool eofCallback(const FLAC__StreamDecoder *, void *clientData);
+	static FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData);
+	static void metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData);
+	static void errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData);
+#endif
+};
+
+#endif
diff --git a/libaudiofile/Features.h b/libaudiofile/Features.h
new file mode 100644
index 0000000..c0c9a94
--- /dev/null
+++ b/libaudiofile/Features.h
@@ -0,0 +1,26 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef Features_h
+#define Features_h
+
+#define ENABLE(FEATURE) (defined ENABLE_##FEATURE && ENABLE_##FEATURE)
+
+#endif
diff --git a/libaudiofile/File.cpp b/libaudiofile/File.cpp
new file mode 100644
index 0000000..1a4f16d
--- /dev/null
+++ b/libaudiofile/File.cpp
@@ -0,0 +1,197 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "File.h"
+
+#include "Compiler.h"
+#include "af_vfs.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+class FilePOSIX : public File
+{
+public:
+	FilePOSIX(int fd, AccessMode mode) : File(mode), m_fd(fd) { }
+	virtual ~FilePOSIX() { close(); }
+
+	virtual int close() OVERRIDE;
+	virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
+	virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
+	virtual off_t length() OVERRIDE;
+	virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
+	virtual off_t tell() OVERRIDE;
+
+private:
+	int m_fd;
+};
+
+class FileVF : public File
+{
+public:
+	FileVF(AFvirtualfile *vf, AccessMode mode) : File(mode), m_vf(vf) { }
+	virtual ~FileVF() { close(); }
+
+	virtual int close() OVERRIDE;
+	virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
+	virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
+	virtual off_t length() OVERRIDE;
+	virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
+	virtual off_t tell() OVERRIDE;
+
+private:
+	AFvirtualfile *m_vf;
+};
+
+File *File::open(const char *path, File::AccessMode mode)
+{
+	int flags = 0;
+	if (mode == ReadAccess)
+		flags = O_RDONLY;
+	else if (mode == WriteAccess)
+		flags = O_CREAT | O_WRONLY | O_TRUNC;
+#if defined(WIN32) || defined(__CYGWIN__)
+	flags |= O_BINARY;
+#endif
+	int fd = ::open(path, flags, 0666);
+	if (fd == -1)
+		return NULL;
+	File *file = new FilePOSIX(fd, mode);
+	return file;
+}
+
+File *File::create(int fd, File::AccessMode mode)
+{
+	return new FilePOSIX(fd, mode);
+}
+
+File *File::create(AFvirtualfile *vf, File::AccessMode mode)
+{
+	return new FileVF(vf, mode);
+}
+
+File::~File()
+{
+}
+
+bool File::canSeek()
+{
+	return seek(0, File::SeekFromCurrent) != -1;
+}
+
+int FilePOSIX::close()
+{
+	if (m_fd == -1)
+		return 0;
+
+	int result = ::close(m_fd);
+	m_fd = -1;
+	return result;
+}
+
+ssize_t FilePOSIX::read(void *data, size_t nbytes)
+{
+	return ::read(m_fd, data, nbytes);
+}
+
+ssize_t FilePOSIX::write(const void *data, size_t nbytes)
+{
+	return ::write(m_fd, data, nbytes);
+}
+
+off_t FilePOSIX::length()
+{
+	off_t current = tell();
+	if (current == -1)
+		return -1;
+	off_t length = seek(0, SeekFromEnd);
+	if (length == -1)
+		return -1;
+	seek(current, SeekFromBeginning);
+	return length;
+}
+
+off_t FilePOSIX::seek(off_t offset, File::SeekOrigin origin)
+{
+	int whence;
+	switch (origin)
+	{
+		case SeekFromBeginning: whence = SEEK_SET; break;
+		case SeekFromCurrent: whence = SEEK_CUR; break;
+		case SeekFromEnd: whence = SEEK_END; break;
+		default: assert(false); return -1;
+	}
+	return ::lseek(m_fd, offset, whence);
+}
+
+off_t FilePOSIX::tell()
+{
+	return seek(0, File::SeekFromCurrent);
+}
+
+int FileVF::close()
+{
+	if (m_vf)
+		af_virtual_file_destroy(m_vf);
+	m_vf = 0;
+	return 0;
+}
+
+ssize_t FileVF::read(void *data, size_t nbytes)
+{
+	return m_vf->read(m_vf, data, nbytes);
+}
+
+ssize_t FileVF::write(const void *data, size_t nbytes)
+{
+	return m_vf->write(m_vf, data, nbytes);
+}
+
+off_t FileVF::length()
+{
+	return m_vf->length(m_vf);
+}
+
+off_t FileVF::seek(off_t offset, SeekOrigin origin)
+{
+	if (origin == SeekFromEnd)
+		offset += length();
+	return m_vf->seek(m_vf, offset, origin == SeekFromCurrent);
+}
+
+off_t FileVF::tell()
+{
+	return m_vf->tell(m_vf);
+}
diff --git a/libaudiofile/File.h b/libaudiofile/File.h
new file mode 100644
index 0000000..ce4f61c
--- /dev/null
+++ b/libaudiofile/File.h
@@ -0,0 +1,77 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FILE_H
+#define FILE_H
+
+#include "Shared.h"
+#include <sys/types.h>
+
+typedef struct _AFvirtualfile AFvirtualfile;
+
+class File : public Shared<File>
+{
+public:
+	enum AccessMode
+	{
+		ReadAccess,
+		WriteAccess
+	};
+
+	enum SeekOrigin
+	{
+		SeekFromBeginning,
+		SeekFromCurrent,
+		SeekFromEnd
+	};
+
+	static File *open(const char *path, AccessMode mode);
+	static File *create(int fd, AccessMode mode);
+	static File *create(AFvirtualfile *vf, AccessMode mode);
+
+	virtual ~File();
+	virtual int close() = 0;
+	virtual ssize_t read(void *data, size_t nbytes) = 0;
+	virtual ssize_t write(const void *data, size_t nbytes) = 0;
+	virtual off_t length() = 0;
+	virtual off_t seek(off_t offset, SeekOrigin origin) = 0;
+	virtual off_t tell() = 0;
+
+	bool canSeek();
+
+	AccessMode accessMode() const { return m_accessMode; }
+
+private:
+	AccessMode m_accessMode;
+
+protected:
+	File(AccessMode mode) : m_accessMode(mode) { }
+};
+
+#endif // FILE_H
diff --git a/libaudiofile/FileHandle.cpp b/libaudiofile/FileHandle.cpp
new file mode 100644
index 0000000..8562d4b
--- /dev/null
+++ b/libaudiofile/FileHandle.cpp
@@ -0,0 +1,488 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "FileHandle.h"
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#include "AIFF.h"
+#include "AVR.h"
+#include "CAF.h"
+#include "FLACFile.h"
+#include "IFF.h"
+#include "IRCAM.h"
+#include "NeXT.h"
+#include "NIST.h"
+#include "Raw.h"
+#include "SampleVision.h"
+#include "VOC.h"
+#include "WAVE.h"
+
+#include "File.h"
+#include "Instrument.h"
+#include "Setup.h"
+#include "Tag.h"
+#include "Track.h"
+#include "units.h"
+#include "util.h"
+
+static void freeInstParams (AFPVu *values, int fileFormat)
+{
+	if (!values)
+		return;
+
+	int parameterCount = _af_units[fileFormat].instrumentParameterCount;
+
+	for (int i=0; i<parameterCount; i++)
+	{
+		if (_af_units[fileFormat].instrumentParameters[i].type == AU_PVTYPE_PTR)
+			free(values[i].v);
+	}
+
+	free(values);
+}
+
+_AFfilehandle *_AFfilehandle::create(int fileFormat)
+{
+	switch (fileFormat)
+	{
+		case AF_FILE_RAWDATA:
+			return new RawFile();
+		case AF_FILE_AIFF:
+		case AF_FILE_AIFFC:
+			return new AIFFFile();
+		case AF_FILE_NEXTSND:
+			return new NeXTFile();
+		case AF_FILE_WAVE:
+			return new WAVEFile();
+		case AF_FILE_BICSF:
+			return new IRCAMFile();
+		case AF_FILE_AVR:
+			return new AVRFile();
+		case AF_FILE_IFF_8SVX:
+			return new IFFFile();
+		case AF_FILE_SAMPLEVISION:
+			return new SampleVisionFile();
+		case AF_FILE_VOC:
+			return new VOCFile();
+		case AF_FILE_NIST_SPHERE:
+			return new NISTFile();
+		case AF_FILE_CAF:
+			return new CAFFile();
+		case AF_FILE_FLAC:
+			return new FLACFile();
+		default:
+			return NULL;
+	}
+}
+
+_AFfilehandle::_AFfilehandle()
+{
+	m_valid = _AF_VALID_FILEHANDLE;
+	m_access = 0;
+	m_seekok = false;
+	m_fh = NULL;
+	m_fileName = NULL;
+	m_fileFormat = AF_FILE_UNKNOWN;
+	m_trackCount = 0;
+	m_tracks = NULL;
+	m_instrumentCount = 0;
+	m_instruments = NULL;
+	m_miscellaneousCount = 0;
+	m_miscellaneous = NULL;
+	m_formatByteOrder = 0;
+}
+
+_AFfilehandle::~_AFfilehandle()
+{
+	m_valid = 0;
+
+	free(m_fileName);
+
+	delete [] m_tracks;
+	m_tracks = NULL;
+	m_trackCount = 0;
+
+	if (m_instruments)
+	{
+		for (int i=0; i<m_instrumentCount; i++)
+		{
+			free(m_instruments[i].loops);
+			m_instruments[i].loops = NULL;
+			m_instruments[i].loopCount = 0;
+
+			freeInstParams(m_instruments[i].values, m_fileFormat);
+			m_instruments[i].values = NULL;
+		}
+
+		free(m_instruments);
+		m_instruments = NULL;
+	}
+	m_instrumentCount = 0;
+
+	if (m_miscellaneous)
+	{
+		for (int i=0; i<m_miscellaneousCount; i++)
+			free(m_miscellaneous[i].buffer);
+		free(m_miscellaneous);
+		m_miscellaneous = NULL;
+	}
+	m_miscellaneousCount = 0;
+}
+
+Track *_AFfilehandle::allocateTrack()
+{
+	assert(!m_trackCount);
+	assert(!m_tracks);
+
+	m_trackCount = 1;
+	m_tracks = new Track[1];
+	return m_tracks;
+}
+
+Track *_AFfilehandle::getTrack(int trackID)
+{
+	for (int i=0; i<m_trackCount; i++)
+		if (m_tracks[i].id == trackID)
+			return &m_tracks[i];
+
+	_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);
+
+	return NULL;
+}
+
+bool _AFfilehandle::checkCanRead()
+{
+	if (m_access != _AF_READ_ACCESS)
+	{
+		_af_error(AF_BAD_NOREADACC, "file not opened for read access");
+		return false;
+	}
+
+	return true;
+}
+
+bool _AFfilehandle::checkCanWrite()
+{
+	if (m_access != _AF_WRITE_ACCESS)
+	{
+		_af_error(AF_BAD_NOWRITEACC, "file not opened for write access");
+		return false;
+	}
+
+	return true;
+}
+
+Instrument *_AFfilehandle::getInstrument(int instrumentID)
+{
+	for (int i = 0; i < m_instrumentCount; i++)
+		if (m_instruments[i].id == instrumentID)
+			return &m_instruments[i];
+
+	_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
+	return NULL;
+}
+
+Miscellaneous *_AFfilehandle::getMiscellaneous(int miscellaneousID)
+{
+	for (int i=0; i<m_miscellaneousCount; i++)
+	{
+		if (m_miscellaneous[i].id == miscellaneousID)
+			return &m_miscellaneous[i];
+	}
+
+	_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);
+
+	return NULL;
+}
+
+status _AFfilehandle::initFromSetup(AFfilesetup setup)
+{
+	if (copyTracksFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+	if (copyInstrumentsFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+	if (copyMiscellaneousFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status _AFfilehandle::copyTracksFromSetup(AFfilesetup setup)
+{
+	if ((m_trackCount = setup->trackCount) == 0)
+	{
+		m_tracks = NULL;
+		return AF_SUCCEED;
+	}
+
+	m_tracks = new Track[m_trackCount];
+	if (!m_tracks)
+		return AF_FAIL;
+
+	for (int i=0; i<m_trackCount; i++)
+	{
+		Track *track = &m_tracks[i];
+		TrackSetup *trackSetup = &setup->tracks[i];
+
+		track->id = trackSetup->id;
+		track->f = trackSetup->f;
+
+		if (track->copyMarkers(trackSetup) == AF_FAIL)
+			return AF_FAIL;
+
+		track->hasAESData = trackSetup->aesDataSet;
+	}
+
+	return AF_SUCCEED;
+}
+
+status _AFfilehandle::copyInstrumentsFromSetup(AFfilesetup setup)
+{
+	if ((m_instrumentCount = setup->instrumentCount) == 0)
+	{
+		m_instruments = NULL;
+		return AF_SUCCEED;
+	}
+
+	m_instruments = static_cast<Instrument *>(_af_calloc(m_instrumentCount,
+		sizeof (Instrument)));
+	if (!m_instruments)
+		return AF_FAIL;
+
+	for (int i=0; i<m_instrumentCount; i++)
+	{
+		m_instruments[i].id = setup->instruments[i].id;
+
+		// Copy loops.
+		if ((m_instruments[i].loopCount = setup->instruments[i].loopCount) == 0)
+		{
+			m_instruments[i].loops = NULL;
+		}
+		else
+		{
+			m_instruments[i].loops =
+				static_cast<Loop *>(_af_calloc(m_instruments[i].loopCount,
+					sizeof (Loop)));
+			if (!m_instruments[i].loops)
+				return AF_FAIL;
+			for (int j=0; j<m_instruments[i].loopCount; j++)
+			{
+				Loop *loop = &m_instruments[i].loops[j];
+				loop->id = setup->instruments[i].loops[j].id;
+				loop->mode = AF_LOOP_MODE_NOLOOP;
+				loop->count = 0;
+				loop->trackid = AF_DEFAULT_TRACK;
+				loop->beginMarker = 2*j + 1;
+				loop->endMarker = 2*j + 2;
+			}
+		}
+
+		int instParamCount;
+		// Copy instrument parameters.
+		if ((instParamCount = _af_units[setup->fileFormat].instrumentParameterCount) == 0)
+		{
+			m_instruments[i].values = NULL;
+		}
+		else
+		{
+			m_instruments[i].values =
+				static_cast<AFPVu *>(_af_calloc(instParamCount, sizeof (AFPVu)));
+			if (!m_instruments[i].values)
+				return AF_FAIL;
+			for (int j=0; j<instParamCount; j++)
+			{
+				m_instruments[i].values[j] = _af_units[setup->fileFormat].instrumentParameters[j].defaultValue;
+			}
+		}
+	}
+
+	return AF_SUCCEED;
+}
+
+status _AFfilehandle::copyMiscellaneousFromSetup(AFfilesetup setup)
+{
+	if ((m_miscellaneousCount = setup->miscellaneousCount) == 0)
+	{
+		m_miscellaneous = NULL;
+		return AF_SUCCEED;
+	}
+
+	m_miscellaneous = static_cast<Miscellaneous *>(_af_calloc(m_miscellaneousCount,
+		sizeof (Miscellaneous)));
+	if (!m_miscellaneous)
+		return AF_FAIL;
+
+	for (int i=0; i<m_miscellaneousCount; i++)
+	{
+		m_miscellaneous[i].id = setup->miscellaneous[i].id;
+		m_miscellaneous[i].type = setup->miscellaneous[i].type;
+		m_miscellaneous[i].size = setup->miscellaneous[i].size;
+		m_miscellaneous[i].position = 0;
+		m_miscellaneous[i].buffer = NULL;
+	}
+
+	return AF_SUCCEED;
+}
+
+template <typename T>
+static bool readValue(File *f, T *value)
+{
+	return f->read(value, sizeof (*value)) == sizeof (*value);
+}
+
+template <typename T>
+static bool writeValue(File *f, const T *value)
+{
+	return f->write(value, sizeof (*value)) == sizeof (*value);
+}
+
+template <typename T>
+static T swapValue(T value, int order)
+{
+	if (order == AF_BYTEORDER_BIGENDIAN)
+		return bigToHost(value);
+	else if (order == AF_BYTEORDER_LITTLEENDIAN)
+		return littleToHost(value);
+	return value;
+}
+
+template <typename T>
+static bool readSwap(File *f, T *value, int order)
+{
+	if (!readValue(f, value)) return false;
+	*value = swapValue(*value, order);
+	return true;
+}
+
+template <typename T>
+static bool writeSwap(File *f, const T *value, int order)
+{
+	T t = swapValue(*value, order);
+	return writeValue(f, &t);
+}
+
+bool _AFfilehandle::readU8(uint8_t *v) { return readValue(m_fh, v); }
+bool _AFfilehandle::readS8(int8_t *v) { return readValue(m_fh, v); }
+
+bool _AFfilehandle::readU16(uint16_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readS16(int16_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readU32(uint32_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readS32(int32_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readU64(uint64_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readS64(int64_t *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readFloat(float *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readDouble(double *v)
+{
+	return readSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeU8(const uint8_t *v) { return writeValue(m_fh, v); }
+bool _AFfilehandle::writeS8(const int8_t *v) { return writeValue(m_fh, v); }
+
+bool _AFfilehandle::writeU16(const uint16_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeS16(const int16_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeU32(const uint32_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeS32(const int32_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeU64(const uint64_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeS64(const int64_t *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeFloat(const float *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::writeDouble(const double *v)
+{
+	return writeSwap(m_fh, v, m_formatByteOrder);
+}
+
+bool _AFfilehandle::readTag(Tag *t)
+{
+	uint32_t v;
+	if (m_fh->read(&v, sizeof (v)) == sizeof (v))
+	{
+		*t = Tag(v);
+		return true;
+	}
+	return false;
+}
+
+bool _AFfilehandle::writeTag(const Tag *t)
+{
+	uint32_t v = t->value();
+	return m_fh->write(&v, sizeof (v)) == sizeof (v);
+}
diff --git a/libaudiofile/FileHandle.h b/libaudiofile/FileHandle.h
new file mode 100644
index 0000000..c9d9700
--- /dev/null
+++ b/libaudiofile/FileHandle.h
@@ -0,0 +1,114 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef FILEHANDLE_H
+#define FILEHANDLE_H
+
+#include "afinternal.h"
+#include <stdint.h>
+
+class File;
+class Tag;
+struct Instrument;
+struct Miscellaneous;
+struct Track;
+
+struct _AFfilehandle
+{
+	static _AFfilehandle *create(int fileFormat);
+
+	int m_valid;	// _AF_VALID_FILEHANDLE
+	int m_access;	// _AF_READ_ACCESS or _AF_WRITE_ACCESS
+
+	bool m_seekok;
+
+	File *m_fh;
+
+	char *m_fileName;
+
+	int m_fileFormat;
+
+	int m_trackCount;
+	Track *m_tracks;
+
+	int m_instrumentCount;
+	Instrument *m_instruments;
+
+	int m_miscellaneousCount;
+	Miscellaneous *m_miscellaneous;
+
+private:
+	int m_formatByteOrder;
+
+	status copyTracksFromSetup(AFfilesetup setup);
+	status copyInstrumentsFromSetup(AFfilesetup setup);
+	status copyMiscellaneousFromSetup(AFfilesetup setup);
+
+public:
+	virtual ~_AFfilehandle();
+
+	virtual int getVersion() { return 0; }
+	virtual status readInit(AFfilesetup) = 0;
+	virtual status writeInit(AFfilesetup) = 0;
+	virtual status update() = 0;
+	virtual bool isInstrumentParameterValid(AUpvlist, int) { return false; }
+
+	bool checkCanRead();
+	bool checkCanWrite();
+
+	Track *allocateTrack();
+	Track *getTrack(int trackID = AF_DEFAULT_TRACK);
+	Instrument *getInstrument(int instrumentID);
+	Miscellaneous *getMiscellaneous(int miscellaneousID);
+
+protected:
+	_AFfilehandle();
+
+	status initFromSetup(AFfilesetup setup);
+
+	void setFormatByteOrder(int byteOrder) { m_formatByteOrder = byteOrder; }
+
+	bool readU8(uint8_t *);
+	bool readS8(int8_t *);
+	bool readU16(uint16_t *);
+	bool readS16(int16_t *);
+	bool readU32(uint32_t *);
+	bool readS32(int32_t *);
+	bool readU64(uint64_t *);
+	bool readS64(int64_t *);
+	bool readFloat(float *);
+	bool readDouble(double *);
+
+	bool writeU8(const uint8_t *);
+	bool writeS8(const int8_t *);
+	bool writeU16(const uint16_t *);
+	bool writeS16(const int16_t *);
+	bool writeU32(const uint32_t *);
+	bool writeS32(const int32_t *);
+	bool writeU64(const uint64_t *);
+	bool writeS64(const int64_t *);
+	bool writeFloat(const float *);
+	bool writeDouble(const double *);
+
+	bool readTag(Tag *t);
+	bool writeTag(const Tag *t);
+};
+
+#endif
diff --git a/libaudiofile/IFF.cpp b/libaudiofile/IFF.cpp
new file mode 100644
index 0000000..124c580
--- /dev/null
+++ b/libaudiofile/IFF.cpp
@@ -0,0 +1,491 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	IFF.cpp
+
+	This file contains routines for reading and writing IFF/8SVX
+	sound files.
+*/
+
+#include "config.h"
+#include "IFF.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Marker.h"
+#include "Setup.h"
+#include "Tag.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+
+static const _AFfilesetup iffDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_IFF_8SVX,	/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+bool IFFFile::recognize(File *fh)
+{
+	uint8_t buffer[8];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
+		return false;
+	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "8SVX", 4) != 0)
+		return false;
+
+	return true;
+}
+
+IFFFile::IFFFile()
+{
+	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
+
+	m_miscellaneousPosition = 0;
+	m_VHDR_offset = 0;
+	m_BODY_offset = 0;
+}
+
+/*
+	Parse miscellaneous data chunks such as name, author, copyright,
+	and annotation chunks.
+*/
+status IFFFile::parseMiscellaneous(const Tag &type, size_t size)
+{
+	int misctype = AF_MISC_UNRECOGNIZED;
+
+	assert(type == "NAME" || type == "AUTH" ||
+		type == "(c) " || type == "ANNO");
+
+	/* Skip zero-length miscellaneous chunks. */
+	if (size == 0)
+		return AF_FAIL;
+
+	m_miscellaneousCount++;
+	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
+		m_miscellaneousCount * sizeof (Miscellaneous));
+
+	if (type == "NAME")
+		misctype = AF_MISC_NAME;
+	else if (type == "AUTH")
+		misctype = AF_MISC_AUTH;
+	else if (type == "(c) ")
+		misctype = AF_MISC_COPY;
+	else if (type == "ANNO")
+		misctype = AF_MISC_ANNO;
+
+	m_miscellaneous[m_miscellaneousCount - 1].id = m_miscellaneousCount;
+	m_miscellaneous[m_miscellaneousCount - 1].type = misctype;
+	m_miscellaneous[m_miscellaneousCount - 1].size = size;
+	m_miscellaneous[m_miscellaneousCount - 1].position = 0;
+	m_miscellaneous[m_miscellaneousCount - 1].buffer = _af_malloc(size);
+	m_fh->read(m_miscellaneous[m_miscellaneousCount - 1].buffer, size);
+
+	return AF_SUCCEED;
+}
+
+/*
+	Parse voice header chunk.
+*/
+status IFFFile::parseVHDR(const Tag &type, size_t size)
+{
+	assert(type == "VHDR");
+
+	Track *track = getTrack();
+
+	uint32_t oneShotSamples, repeatSamples, samplesPerRepeat;
+	uint16_t sampleRate;
+	uint8_t octaves, compression;
+	uint32_t volume;
+
+	readU32(&oneShotSamples);
+	readU32(&repeatSamples);
+	readU32(&samplesPerRepeat);
+	readU16(&sampleRate);
+	readU8(&octaves);
+	readU8(&compression);
+	readU32(&volume);
+
+	track->f.sampleWidth = 8; 
+	track->f.sampleRate = sampleRate;
+	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+	track->f.compressionType = AF_COMPRESSION_NONE;
+	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+	track->f.channelCount = 1;
+
+	track->f.framesPerPacket = 1;
+	track->f.computeBytesPerPacketPCM();
+
+	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+	return AF_SUCCEED;
+}
+
+status IFFFile::parseBODY(const Tag &type, size_t size)
+{
+	Track *track = getTrack();
+
+	/*
+		IFF/8SVX files have only one audio channel with one
+		byte per sample, so the number of frames is equal to
+		the number of bytes.
+	*/
+	track->totalfframes = size;
+	track->data_size = size;
+
+	/* Sound data follows. */
+	track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
+
+status IFFFile::readInit(AFfilesetup setup)
+{
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	Tag type;
+	uint32_t size;
+	Tag formtype;
+
+	readTag(&type);
+	readU32(&size);
+	readTag(&formtype);
+
+	if (type != "FORM" || formtype != "8SVX")
+		return AF_FAIL;
+
+	/* IFF/8SVX files have only one track. */
+	Track *track = allocateTrack();
+	if (!track)
+		return AF_FAIL;
+
+	/* Set the index to include the form type ('8SVX' in this case). */
+	size_t index = 4;
+	while (index < size)
+	{
+		Tag chunkid;
+		uint32_t chunksize = 0;
+		status result = AF_SUCCEED;
+
+		readTag(&chunkid);
+		readU32(&chunksize);
+
+		if (chunkid == "VHDR")
+		{
+			result = parseVHDR(chunkid, chunksize);
+		}
+		else if (chunkid == "BODY")
+		{
+			result = parseBODY(chunkid, chunksize);
+		}
+		else if (chunkid == "NAME" ||
+			chunkid == "AUTH" ||
+			chunkid == "(c) " ||
+			chunkid == "ANNO")
+		{
+			parseMiscellaneous(chunkid, chunksize);
+		}
+
+		if (result == AF_FAIL)
+			return AF_FAIL;
+
+		/*
+			Increment the index by the size of the chunk
+			plus the size of the chunk header.
+		*/
+		index += chunksize + 8;
+
+		/* All chunks must be aligned on an even number of bytes. */
+		if ((index % 2) != 0)
+			index++;
+
+		/* Set the seek position to the beginning of the next chunk. */
+		m_fh->seek(index + 8, File::SeekFromBeginning);
+	}
+
+	/* The file has been successfully parsed. */
+	return AF_SUCCEED;
+}
+
+AFfilesetup IFFFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "IFF/8SVX file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet &&
+		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+	{
+		_af_error(AF_BAD_SAMPFMT,
+			"IFF/8SVX format supports only two's complement integer data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->sampleFormatSet && track->f.sampleWidth != 8)
+	{
+		_af_error(AF_BAD_WIDTH,
+			"IFF/8SVX file allows only 8 bits per sample "
+			"(%d bits requested)", track->f.sampleWidth);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->channelCountSet && track->f.channelCount != 1)
+	{
+		_af_error(AF_BAD_CHANNELS,
+			"invalid channel count (%d) for IFF/8SVX format "
+			"(only 1 channel supported)",
+			track->f.channelCount);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"IFF/8SVX does not support compression");
+		return AF_NULL_FILESETUP;
+	}
+
+	/* Ignore requested byte order since samples are only one byte. */
+	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+	/* Either one channel was requested or no request was made. */
+	track->f.channelCount = 1;
+	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 8);
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_NUMMARKS,
+			"IFF/8SVX format does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "IFF/8SVX format does not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_NUMINSTS,
+			"IFF/8SVX format does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &iffDefaultFileSetup, true);
+}
+
+status IFFFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	uint32_t fileSize = 0;
+
+	m_fh->write("FORM", 4);
+	writeU32(&fileSize);
+
+	m_fh->write("8SVX", 4);
+
+	writeVHDR();
+	writeMiscellaneous();
+	writeBODY();
+
+	return AF_SUCCEED;
+}
+
+status IFFFile::update()
+{
+	uint32_t length;
+
+	writeVHDR();
+	writeMiscellaneous();
+	writeBODY();
+
+	/* Get the length of the file. */
+	length = m_fh->length();
+	length -= 8;
+
+	/* Set the length of the FORM chunk. */
+	m_fh->seek(4, File::SeekFromBeginning);
+	writeU32(&length);
+
+	return AF_SUCCEED;
+}
+
+status IFFFile::writeVHDR()
+{
+	uint32_t chunkSize;
+	uint32_t oneShotSamples, repeatSamples, samplesPerRepeat;
+	uint16_t sampleRate;
+	uint8_t octaves, compression;
+	uint32_t volume;
+
+	/*
+		If VHDR_offset hasn't been set yet, set it to the
+		current offset.
+	*/
+	if (m_VHDR_offset == 0)
+		m_VHDR_offset = m_fh->tell();
+	else
+		m_fh->seek(m_VHDR_offset, File::SeekFromBeginning);
+
+	Track *track = getTrack();
+
+	m_fh->write("VHDR", 4);
+
+	chunkSize = 20;
+	writeU32(&chunkSize);
+
+	/*
+		IFF/8SVX files have only one audio channel, so the
+		number of samples is equal to the number of frames.
+	*/
+	oneShotSamples = track->totalfframes;
+	writeU32(&oneShotSamples);
+	repeatSamples = 0;
+	writeU32(&repeatSamples);
+	samplesPerRepeat = 0;
+	writeU32(&samplesPerRepeat);
+
+	sampleRate = track->f.sampleRate;
+	writeU16(&sampleRate);
+
+	octaves = 0;
+	compression = 0;
+	writeU8(&octaves);
+	writeU8(&compression);
+
+	/* Volume is in fixed-point notation; 65536 means gain of 1.0. */
+	volume = 65536;
+	writeU32(&volume);
+
+	return AF_SUCCEED;
+}
+
+status IFFFile::writeBODY()
+{
+	uint32_t chunkSize;
+
+	Track *track = getTrack();
+
+	if (m_BODY_offset == 0)
+		m_BODY_offset = m_fh->tell();
+	else
+		m_fh->seek(m_BODY_offset, File::SeekFromBeginning);
+
+	m_fh->write("BODY", 4);
+
+	/*
+		IFF/8SVX supports only one channel, so the number of
+		frames is equal to the number of samples, and each
+		sample is one byte.
+	*/
+	chunkSize = track->totalfframes;
+	writeU32(&chunkSize);
+
+	if (track->fpos_first_frame == 0)
+		track->fpos_first_frame = m_fh->tell();
+
+	/* Add a pad byte to the end of the chunk if the chunk size is odd. */
+	if ((chunkSize % 2) == 1)
+	{
+		uint8_t zero = 0;
+		m_fh->seek(m_BODY_offset + 8 + chunkSize, File::SeekFromBeginning);
+		writeU8(&zero);
+	}
+
+	return AF_SUCCEED;
+}
+
+/*
+	WriteMiscellaneous writes all the miscellaneous data chunks in a
+	file handle structure to an IFF/8SVX file.
+*/
+status IFFFile::writeMiscellaneous()
+{
+	if (m_miscellaneousPosition == 0)
+		m_miscellaneousPosition = m_fh->tell();
+	else
+		m_fh->seek(m_miscellaneousPosition, File::SeekFromBeginning);
+
+	for (int i=0; i<m_miscellaneousCount; i++)
+	{
+		Miscellaneous *misc = &m_miscellaneous[i];
+		Tag chunkType;
+		uint32_t chunkSize;
+		uint8_t padByte = 0;
+
+		switch (misc->type)
+		{
+			case AF_MISC_NAME:
+				chunkType = "NAME"; break;
+			case AF_MISC_AUTH:
+				chunkType = "AUTH"; break;
+			case AF_MISC_COPY:
+				chunkType = "(c) "; break;
+			case AF_MISC_ANNO:
+				chunkType = "ANNO"; break;
+		}
+
+		writeTag(&chunkType);
+
+		chunkSize = misc->size;
+		writeU32(&chunkSize);
+
+		/*
+			Write the miscellaneous buffer and then a pad byte
+			if necessary.  If the buffer is null, skip the space
+			for now.
+		*/
+		if (misc->buffer != NULL)
+			m_fh->write(misc->buffer, misc->size);
+		else
+			m_fh->seek(misc->size, File::SeekFromCurrent);
+
+		if (misc->size % 2 != 0)
+			writeU8(&padByte);
+	}
+
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/IFF.h b/libaudiofile/IFF.h
new file mode 100644
index 0000000..943d01c
--- /dev/null
+++ b/libaudiofile/IFF.h
@@ -0,0 +1,59 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	IFF.h
+
+	This file declares constants and functions related to the
+	IFF/8SVX file format.
+*/
+
+#ifndef IFF_H
+#define IFF_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+class IFFFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	IFFFile();
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+	AFfileoffset m_miscellaneousPosition;
+	AFfileoffset m_VHDR_offset;
+	AFfileoffset m_BODY_offset;
+
+	status parseMiscellaneous(const Tag &type, size_t size);
+	status parseVHDR(const Tag &type, size_t size);
+	status parseBODY(const Tag &type, size_t size);
+
+	status writeVHDR();
+	status writeMiscellaneous();
+	status writeBODY();
+};
+
+#endif
diff --git a/libaudiofile/IRCAM.cpp b/libaudiofile/IRCAM.cpp
new file mode 100644
index 0000000..2cf6524
--- /dev/null
+++ b/libaudiofile/IRCAM.cpp
@@ -0,0 +1,439 @@
+/*
+	Audio File Library
+	Copyright (C) 2001, Silicon Graphics, Inc.
+	Copyright (C) 2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	IRCAM.cpp
+
+	This file contains routines for reading and writing
+	Berkeley/IRCAM/CARL sound files.
+*/
+
+#include "config.h"
+#include "IRCAM.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Marker.h"
+#include "Setup.h"
+#include "Track.h"
+#include "byteorder.h"
+#include "util.h"
+
+enum
+{
+	SF_CHAR = 1,
+	SF_SHORT = 2,
+	SF_24INT = 3,
+	SF_LONG = 0x40004,
+	SF_FLOAT = 4,
+	SF_DOUBLE = 8,
+	SF_ALAW = 0x10001,
+	SF_ULAW = 0x20001
+};
+
+#define SF_MAXCHAN 4
+#define SF_MAXCOMMENT 512
+#define SF_MINCOMMENT 256
+
+enum
+{
+	SF_END,
+	SF_MAXAMP,
+	SF_COMMENT,
+	SF_LINKCODE
+};
+
+#define SIZEOF_BSD_HEADER 1024
+
+static const uint8_t ircam_vax_le_magic[4] = {0x64, 0xa3, 0x01, 0x00},
+	ircam_vax_be_magic[4] = {0x00, 0x01, 0xa3, 0x64},
+	ircam_sun_be_magic[4] = {0x64, 0xa3, 0x02, 0x00},
+	ircam_sun_le_magic[4] = {0x00, 0x02, 0xa3, 0x64},
+	ircam_mips_le_magic[4] = {0x64, 0xa3, 0x03, 0x00},
+	ircam_mips_be_magic[4] = {0x00, 0x03, 0xa3, 0x64},
+	ircam_next_be_magic[4] = {0x64, 0xa3, 0x04, 0x00},
+	ircam_next_le_magic[4] = {0x00, 0x04, 0xa3, 0x64};
+
+static const _AFfilesetup ircam_default_filesetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_IRCAM,		/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+const int _af_ircam_compression_types[_AF_IRCAM_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW
+};
+
+bool IRCAMFile::recognize(File *fh)
+{
+	uint8_t buffer[4];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 4) != 4)
+		return false;
+
+	/* Check to see if the file's magic number matches. */
+	if (!memcmp(buffer, ircam_vax_le_magic, 4) ||
+		!memcmp(buffer, ircam_vax_be_magic, 4) ||
+		!memcmp(buffer, ircam_sun_be_magic, 4) ||
+		!memcmp(buffer, ircam_sun_le_magic, 4) ||
+		!memcmp(buffer, ircam_mips_le_magic, 4) ||
+		!memcmp(buffer, ircam_mips_be_magic, 4) ||
+		!memcmp(buffer, ircam_next_be_magic, 4) ||
+		!memcmp(buffer, ircam_next_le_magic, 4))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+AFfilesetup IRCAMFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "BICSF file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		if (track->f.isUnsigned())
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"BICSF format does not support unsigned data");
+			return AF_NULL_FILESETUP;
+		}
+
+		if (track->f.isSigned() &&
+			track->f.sampleWidth != 8 &&
+			track->f.sampleWidth != 16 &&
+			track->f.sampleWidth != 24 &&
+			track->f.sampleWidth != 32)
+		{
+			_af_error(AF_BAD_WIDTH,
+				"BICSF format supports only 8-, 16-, 24-, or 32-bit "
+				"two's complement audio data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+
+	if (track->rateSet && track->f.sampleRate <= 0.0)
+	{
+		_af_error(AF_BAD_RATE,
+			"invalid sample rate %.30g for BICSF file",
+			track->f.sampleRate);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->channelCountSet && track->f.channelCount != 1 &&
+		track->f.channelCount != 2 && track->f.channelCount != 4)
+	{
+		_af_error(AF_BAD_CHANNELS,
+			"invalid channel count (%d) for BICSF format "
+			"(1, 2, or 4 channels only)",
+			track->f.channelCount);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->compressionSet &&
+		track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED,
+			"BICSF format does not support compression type %d",
+			track->f.compressionType);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "BICSF file cannot have AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_NUMMARKS, "BICSF format does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_NUMINSTS, "BICSF format does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	/* XXXmpruett: We don't support miscellaneous chunks for now. */
+	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "BICSF format does not currently support miscellaneous chunks");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &ircam_default_filesetup, true);
+}
+
+status IRCAMFile::readInit(AFfilesetup setup)
+{
+	float maxAmp = 1.0;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	uint8_t magic[4];
+	if (m_fh->read(magic, 4) != 4)
+	{
+		_af_error(AF_BAD_READ, "Could not read BICSF file header");
+		return AF_FAIL;
+	}
+
+	if (memcmp(magic, ircam_vax_le_magic, 4) != 0 &&
+		memcmp(magic, ircam_vax_be_magic, 4) != 0 &&
+		memcmp(magic, ircam_sun_be_magic, 4) != 0 &&
+		memcmp(magic, ircam_sun_le_magic, 4) != 0 &&
+		memcmp(magic, ircam_mips_le_magic, 4) != 0 &&
+		memcmp(magic, ircam_mips_be_magic, 4) != 0 &&
+		memcmp(magic, ircam_next_be_magic, 4) != 0 &&
+		memcmp(magic, ircam_next_le_magic, 4) != 0)
+	{
+		_af_error(AF_BAD_FILEFMT,
+			"file is not a BICSF file (bad magic number)");
+		return AF_FAIL;
+	}
+
+	// Check whether the file's magic number indicates little-endian data.
+	bool isLittleEndian = !memcmp(magic, ircam_vax_le_magic, 4) ||
+		!memcmp(magic, ircam_sun_le_magic, 4) ||
+		!memcmp(magic, ircam_mips_le_magic, 4) ||
+		!memcmp(magic, ircam_next_le_magic, 4);
+
+	setFormatByteOrder(isLittleEndian ? AF_BYTEORDER_LITTLEENDIAN :
+		AF_BYTEORDER_BIGENDIAN);
+
+	float rate;
+	readFloat(&rate);
+	uint32_t channels;
+	readU32(&channels);
+	uint32_t packMode;
+	readU32(&packMode);
+
+	Track *track = allocateTrack();
+	if (!track)
+		return AF_FAIL;
+
+	track->f.sampleRate = rate;
+	track->f.compressionType = AF_COMPRESSION_NONE;
+
+	if (isLittleEndian)
+		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+	else
+		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+	if (channels != 1 && channels != 2 && channels != 4)
+	{
+		_af_error(AF_BAD_FILEFMT,
+			"invalid channel count (%d) for BICSF format (1, 2, or 4 only)",
+			channels);
+		return AF_FAIL;
+	}
+
+	track->f.channelCount = channels;
+
+	track->f.framesPerPacket = 1;
+
+	switch (packMode)
+	{
+		case SF_CHAR:
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 8;
+			break;
+		case SF_SHORT:
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 16;
+			break;
+		case SF_24INT:
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 24;
+			break;
+		case SF_LONG:
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 32;
+			break;
+		case SF_FLOAT:
+			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+			track->f.sampleWidth = 32;
+			break;
+		case SF_DOUBLE:
+			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+			track->f.sampleWidth = 64;
+			break;
+		case SF_ALAW:
+			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 16;
+			track->f.bytesPerPacket = channels;
+			break;
+		case SF_ULAW:
+			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.sampleWidth = 16;
+			track->f.bytesPerPacket = channels;
+			break;
+		default:
+			_af_error(AF_BAD_NOT_IMPLEMENTED,
+				"BICSF data format %d not supported", packMode);
+			return AF_FAIL;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.computeBytesPerPacketPCM();
+
+	if (_af_set_sample_format(&track->f, track->f.sampleFormat,
+		track->f.sampleWidth) == AF_FAIL)
+	{
+		return AF_FAIL;
+	}
+
+	if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+		track->f.pcm.slope = maxAmp;
+
+	track->data_size = m_fh->length() - SIZEOF_BSD_HEADER;
+	track->computeTotalFileFrames();
+
+	track->fpos_first_frame = SIZEOF_BSD_HEADER;
+
+	return AF_SUCCEED;
+}
+
+/* We write IRCAM files using the native byte order. */
+status IRCAMFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	uint32_t dataOffset = SIZEOF_BSD_HEADER;
+
+	Track *track = getTrack();
+	track->fpos_first_frame = dataOffset;
+
+	/* Choose the magic number appropriate for the byte order. */
+	const uint8_t *magic;
+#ifdef WORDS_BIGENDIAN
+	magic = ircam_sun_be_magic;
+#else
+	magic = ircam_vax_le_magic;
+#endif
+
+	uint32_t channels = track->f.channelCount;
+	float rate = track->f.sampleRate;
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+	{
+		_af_error(AF_BAD_COMPTYPE,
+			"unsupported compression type %d in IRCAM sound file",
+			track->f.compressionType);
+		return AF_FAIL;
+	}
+
+	uint32_t packMode = 0;
+	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+		packMode = SF_ULAW;
+	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+		packMode = SF_ALAW;
+	else if (track->f.isSigned())
+	{
+		switch (track->f.bytesPerSample(false))
+		{
+			case 1: packMode = SF_CHAR; break;
+			case 2: packMode = SF_SHORT; break;
+			case 3: packMode = SF_24INT; break;
+			case 4: packMode = SF_LONG; break;
+			default:
+				_af_error(AF_BAD_SAMPFMT,
+					"unsupported sample width %d for two's complement BICSF file",
+					track->f.sampleWidth);
+				return AF_FAIL;
+		}
+	}
+	else if (track->f.isFloat())
+	{
+		if (track->f.sampleWidth == 32)
+			packMode = SF_FLOAT;
+		else if (track->f.sampleWidth == 64)
+			packMode = SF_DOUBLE;
+		else
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"unsupported sample width %d for BICSF file",
+				track->f.sampleWidth);
+			return AF_FAIL;
+		}
+	}
+	else if (track->f.isUnsigned())
+	{
+		_af_error(AF_BAD_SAMPFMT, "BICSF format does not support unsigned integer audio data");
+		return AF_FAIL;
+	}
+
+	m_fh->seek(0, File::SeekFromBeginning);
+	m_fh->write(magic, 4);
+	writeFloat(&rate);
+	writeU32(&channels);
+	writeU32(&packMode);
+
+	/* Zero the entire description block. */
+	uint8_t zeros[SIZEOF_BSD_HEADER];
+	memset(zeros, 0, SIZEOF_BSD_HEADER);
+	m_fh->write(zeros, SIZEOF_BSD_HEADER - 4*4);
+
+	return AF_SUCCEED;
+}
+
+status IRCAMFile::update()
+{
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/IRCAM.h b/libaudiofile/IRCAM.h
new file mode 100644
index 0000000..bec49d4
--- /dev/null
+++ b/libaudiofile/IRCAM.h
@@ -0,0 +1,49 @@
+/*
+	Audio File Library
+	Copyright (C) 2001, Silicon Graphics, Inc.
+	Copyright (C) 2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	IRCAM.h
+
+	This file contains constants and function prototypes related to
+	the Berkeley/IRCAM/CARL Sound File format.
+*/
+
+#ifndef IRCAM_H
+#define IRCAM_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+#define _AF_IRCAM_NUM_COMPTYPES 2
+extern const int _af_ircam_compression_types[_AF_IRCAM_NUM_COMPTYPES];
+
+class IRCAMFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+};
+
+#endif
diff --git a/libaudiofile/Instrument.cpp b/libaudiofile/Instrument.cpp
new file mode 100644
index 0000000..84e68b3
--- /dev/null
+++ b/libaudiofile/Instrument.cpp
@@ -0,0 +1,302 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Instrument.cpp
+
+	Info about instrument parameters:
+
+	Each unit has an array of _InstParamInfo structures, one for
+	each instrument parameter.  Each of these structures describes
+	the inst parameters.
+
+	id: a 4-byte id as in AIFF file
+	type: data type AU_PVLIST_*
+	name: text name
+	defaultValue: default value, to which it is set when a file with
+		instruments is first opened for writing.
+
+	Each inst has only an array of values (_AFPVu's).  Each value in the
+	instrument's array is the value of the corresponding index into the
+	unit's instparaminfo array.
+
+	So for a unit u and an instrument i, u.instparam[N] describes
+	the parameter whose value is given in i.value[N].
+*/
+
+#include "config.h"
+
+#include "FileHandle.h"
+#include "Instrument.h"
+#include "Setup.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "units.h"
+#include "util.h"
+
+#include <stdlib.h>
+
+bool InstrumentSetup::allocateLoops(int count)
+{
+	freeLoops();
+	loops = (LoopSetup *) _af_calloc(count, sizeof (LoopSetup));
+	if (loops)
+	{
+		loopCount = count;
+		return true;
+	}
+	return false;
+}
+
+void InstrumentSetup::freeLoops()
+{
+	if (loops)
+		free(loops);
+	loops = NULL;
+	loopCount = 0;
+}
+
+/*
+	Initialize instrument id list for audio file.
+*/
+void afInitInstIDs (AFfilesetup setup, const int *instids, int ninsts)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	if (!_af_unique_ids(instids, ninsts, "instrument", AF_BAD_INSTID))
+		return;
+
+	_af_setup_free_instruments(setup);
+
+	setup->instrumentCount = ninsts;
+	setup->instrumentSet = true;
+
+	setup->instruments = _af_instsetup_new(setup->instrumentCount);
+
+	for (int i=0; i < setup->instrumentCount; i++)
+		setup->instruments[i].id = instids[i];
+}
+
+int afGetInstIDs (AFfilehandle file, int *instids)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (instids)
+		for (int i=0; i < file->m_instrumentCount; i++)
+			instids[i] = file->m_instruments[i].id;
+
+	return file->m_instrumentCount;
+}
+
+/*
+	This routine checks and sets instrument parameters.
+	npv is number of valid AUpvlist pairs.
+*/
+void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	if (!file->checkCanWrite())
+		return;
+
+	Instrument *instrument = file->getInstrument(instid);
+	if (!instrument)
+		return;
+
+	if (AUpvgetmaxitems(pvlist) < npv)
+	npv = AUpvgetmaxitems(pvlist);
+
+	for (int i=0; i < npv; i++)
+	{
+		int	param;
+
+		AUpvgetparam(pvlist, i, &param);
+
+		int j;
+		if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
+			/* no parameter with that id; ignore */
+			continue;
+
+		if (!file->isInstrumentParameterValid(pvlist, i))
+			/* bad parameter value; ignore */
+			continue;
+
+		int	type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
+
+		switch (type)
+		{
+			case AU_PVTYPE_LONG:
+				AUpvgetval(pvlist, i, &instrument->values[j].l);
+				break;
+			case AU_PVTYPE_DOUBLE:
+				AUpvgetval(pvlist, i, &instrument->values[j].d);
+				break;
+			case AU_PVTYPE_PTR:
+				AUpvgetval(pvlist, i, &instrument->values[j].v);
+				break;
+			default:
+				return;
+		}
+	}
+}
+
+void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
+{
+	_af_instparam_set(file, instid, pvlist, npv);
+}
+
+void afSetInstParamLong (AFfilehandle file, int instid, int param, long value)
+{
+	AUpvlist pvlist = AUpvnew(1);
+
+	AUpvsetparam(pvlist, 0, param);
+	AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
+	AUpvsetval(pvlist, 0, &value);
+
+	_af_instparam_set(file, instid, pvlist, 1);
+
+	AUpvfree(pvlist);
+}
+
+/*
+	This routine gets instrument parameters.
+	npv is number of valid AUpvlist pairs
+*/
+void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist, int npv,
+	bool forceLong)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Instrument *instrument = file->getInstrument(instid);
+	if (!instrument)
+		return;
+
+	if (AUpvgetmaxitems(pvlist) < npv)
+		npv = AUpvgetmaxitems(pvlist);
+
+	for (int i=0; i < npv; i++)
+	{
+		int param;
+		AUpvgetparam(pvlist, i, &param);
+
+		int j;
+		if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
+			/* no parameter with that id; ignore */
+			continue;
+
+		int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
+
+		/*
+			forceLong is true when this routine called by
+			afGetInstParamLong().
+		*/
+		if (forceLong && type != AU_PVTYPE_LONG)
+		{
+			_af_error(AF_BAD_INSTPTYPE, "type of instrument parameter %d is not AU_PVTYPE_LONG", param);
+			continue;
+		}
+
+		AUpvsetvaltype(pvlist, i, type);
+
+		switch (type)
+		{
+			case AU_PVTYPE_LONG:
+				AUpvsetval(pvlist, i, &instrument->values[j].l);
+				break;
+			case AU_PVTYPE_DOUBLE:
+				AUpvsetval(pvlist, i, &instrument->values[j].d);
+				break;
+			case AU_PVTYPE_PTR:
+				AUpvsetval(pvlist, i, &instrument->values[j].v);
+				break;
+
+			default:
+				_af_error(AF_BAD_INSTPTYPE, "invalid instrument parameter type %d", type);
+				return;
+		}
+	}
+}
+
+/*
+	afGetInstParams -- get a parameter-value array containing
+	instrument parameters for the specified instrument chunk
+*/
+void afGetInstParams (AFfilehandle file, int inst, AUpvlist pvlist, int npv)
+{
+	_af_instparam_get(file, inst, pvlist, npv, false);
+}
+
+long afGetInstParamLong (AFfilehandle file, int inst, int param)
+{
+	long val;
+	AUpvlist pvlist = AUpvnew(1);
+
+	AUpvsetparam(pvlist, 0, param);
+	AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
+
+	_af_instparam_get(file, inst, pvlist, 1, true);
+
+	AUpvgetval(pvlist, 0, &val);
+	AUpvfree(pvlist);
+
+	return(val);
+}
+
+/*
+	Search _af_units[fileFormat].instrumentParameters for the instrument
+	parameter with the specified id.
+
+	Report an error and return -1 if no such instrument parameter
+	exists.
+*/
+
+int _af_instparam_index_from_id (int filefmt, int id)
+{
+	int i;
+
+	for (i = 0; i < _af_units[filefmt].instrumentParameterCount; i++)
+		if (_af_units[filefmt].instrumentParameters[i].id == id)
+			break;
+
+	if (i == _af_units[filefmt].instrumentParameterCount)
+	{
+		_af_error(AF_BAD_INSTPID, "invalid instrument parameter id %d",
+			id);
+		return -1;
+	}
+
+	return i;
+}
+
+Loop *Instrument::getLoop(int loopID)
+{
+	for (int i=0; i<loopCount; i++)
+		if (loops[i].id == loopID)
+			return &loops[i];
+	
+	_af_error(AF_BAD_LOOPID, "no loop with id %d for instrument %d\n",
+		loopID, id);
+	return NULL;
+}
diff --git a/libaudiofile/Instrument.h b/libaudiofile/Instrument.h
new file mode 100644
index 0000000..0aea449
--- /dev/null
+++ b/libaudiofile/Instrument.h
@@ -0,0 +1,70 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Instrument.h
+
+	This file declares routines for dealing with instruments.
+*/
+
+#ifndef INSTRUMENT_H
+#define INSTRUMENT_H
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "aupvlist.h"
+
+struct LoopSetup;
+struct Loop;
+
+struct InstrumentSetup
+{
+	int	id;
+
+	int loopCount;
+	LoopSetup *loops;
+
+	bool loopSet;
+
+	bool allocateLoops(int count);
+	void freeLoops();
+};
+
+struct Instrument
+{
+	int id;
+
+	int loopCount;
+	Loop *loops;
+
+	AFPVu *values;
+
+	Loop *getLoop(int loopID);
+};
+
+void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist,
+	int npv, bool forceLong);
+
+void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist,
+	int npv);
+
+int _af_instparam_index_from_id (int fileFormat, int id);
+
+#endif /* INSTRUMENT_H */
diff --git a/libaudiofile/Loop.cpp b/libaudiofile/Loop.cpp
new file mode 100644
index 0000000..87be439
--- /dev/null
+++ b/libaudiofile/Loop.cpp
@@ -0,0 +1,313 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Loop.cpp
+
+	All routines that operate on loops.
+*/
+
+#include "config.h"
+
+#include "FileHandle.h"
+#include "Instrument.h"
+#include "Setup.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+
+void afInitLoopIDs (AFfilesetup setup, int instid, const int *loopids, int nloops)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	if (!_af_unique_ids(loopids, nloops, "loop", AF_BAD_LOOPID))
+		return;
+
+	InstrumentSetup *instrument = setup->getInstrument(instid);
+	if (!instrument)
+		return;
+
+	instrument->freeLoops();
+	if (!instrument->allocateLoops(nloops))
+		return;
+
+	for (int i=0; i < nloops; i++)
+		instrument->loops[i].id = loopids[i];
+}
+
+int afGetLoopIDs (AFfilehandle file, int instid, int *loopids)
+{
+	if (!_af_filehandle_ok(file))
+		return AF_FAIL;
+
+	Instrument *instrument = file->getInstrument(instid);
+	if (!instrument)
+		return AF_FAIL;
+
+	if (loopids)
+		for (int i=0; i < instrument->loopCount; i++)
+			loopids[i] = instrument->loops[i].id;
+
+	return instrument->loopCount;
+}
+
+/*
+	getLoop returns pointer to requested loop if it exists, and if
+	mustWrite is true, only if handle is writable.
+*/
+
+static Loop *getLoop (AFfilehandle handle, int instid, int loopid,
+	bool mustWrite)
+{
+	if (!_af_filehandle_ok(handle))
+		return NULL;
+
+	if (mustWrite && !handle->checkCanWrite())
+		return NULL;
+
+	Instrument *instrument = handle->getInstrument(instid);
+	if (!instrument)
+		return NULL;
+
+	return instrument->getLoop(loopid);
+}
+
+/*
+	Set loop mode (as in AF_LOOP_MODE_...).
+*/
+void afSetLoopMode (AFfilehandle file, int instid, int loopid, int mode)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop)
+		return;
+
+	if (mode != AF_LOOP_MODE_NOLOOP &&
+		mode != AF_LOOP_MODE_FORW &&
+		mode != AF_LOOP_MODE_FORWBAKW)
+	{
+		_af_error(AF_BAD_LOOPMODE, "unrecognized loop mode %d", mode);
+		return;
+	}
+
+	loop->mode = mode;
+}
+
+/*
+	Get loop mode (as in AF_LOOP_MODE_...).
+*/
+int afGetLoopMode (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	return loop->mode;
+}
+
+/*
+	Set loop count.
+*/
+int afSetLoopCount (AFfilehandle file, int instid, int loopid, int count)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop)
+		return AF_FAIL;
+
+	if (count < 1)
+	{
+		_af_error(AF_BAD_LOOPCOUNT, "invalid loop count: %d", count);
+		return AF_FAIL;
+	}
+
+	loop->count = count;
+	return AF_SUCCEED;
+}
+
+/*
+	Get loop count.
+*/
+int afGetLoopCount(AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	return loop->count;
+}
+
+/*
+	Set loop start marker id in the file structure
+*/
+void afSetLoopStart(AFfilehandle file, int instid, int loopid, int markid)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop)
+		return;
+
+	loop->beginMarker = markid;
+}
+
+/*
+	Get loop start marker id.
+*/
+int afGetLoopStart (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	return loop->beginMarker;
+}
+
+/*
+	Set loop start frame in the file structure.
+*/
+int afSetLoopStartFrame (AFfilehandle file, int instid, int loopid, AFframecount startFrame)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop)
+		return -1;
+
+	if (startFrame < 0)
+	{
+		_af_error(AF_BAD_FRAME, "loop start frame must not be negative");
+		return AF_FAIL;
+	}
+
+	int	trackid = loop->trackid;
+	int beginMarker = loop->beginMarker;
+
+	afSetMarkPosition(file, trackid, beginMarker, startFrame);
+	return AF_SUCCEED;
+}
+
+/*
+	Get loop start frame.
+*/
+AFframecount afGetLoopStartFrame (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+	if (!loop)
+		return -1;
+
+	int trackid = loop->trackid;
+	int beginMarker = loop->beginMarker;
+
+	return afGetMarkPosition(file, trackid, beginMarker);
+}
+
+/*
+	Set loop track id.
+*/
+void afSetLoopTrack (AFfilehandle file, int instid, int loopid, int track)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop) return;
+
+	loop->trackid = track;
+}
+
+/*
+	Get loop track.
+*/
+int afGetLoopTrack (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	return loop->trackid;
+}
+
+/*
+	Set loop end frame marker id.
+*/
+void afSetLoopEnd (AFfilehandle file, int instid, int loopid, int markid)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+
+	if (!loop)
+		return;
+
+	loop->endMarker = markid;
+}
+
+/*
+	Get loop end frame marker id.
+*/
+int afGetLoopEnd (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	return loop->endMarker;
+}
+
+/*
+	Set loop end frame.
+*/
+int afSetLoopEndFrame (AFfilehandle file, int instid, int loopid, AFframecount endFrame)
+{
+	Loop *loop = getLoop(file, instid, loopid, true);
+	if (!loop)
+		return -1;
+
+	if (endFrame < 0)
+	{
+		_af_error(AF_BAD_FRAME, "loop end frame must not be negative");
+		return AF_FAIL;
+	}
+
+	int trackid = loop->trackid;
+	int endMarker = loop->endMarker;
+
+	afSetMarkPosition(file, trackid, endMarker, endFrame);
+	return AF_SUCCEED;
+}
+
+/*
+	Get loop end frame.
+*/
+
+AFframecount afGetLoopEndFrame (AFfilehandle file, int instid, int loopid)
+{
+	Loop *loop = getLoop(file, instid, loopid, false);
+
+	if (!loop)
+		return -1;
+
+	int trackid = loop->trackid;
+	int endMarker = loop->endMarker;
+
+	return afGetMarkPosition(file, trackid, endMarker);
+}
diff --git a/libaudiofile/Makefile.am b/libaudiofile/Makefile.am
new file mode 100644
index 0000000..d502cf2
--- /dev/null
+++ b/libaudiofile/Makefile.am
@@ -0,0 +1,127 @@
+SUBDIRS = alac modules
+
+lib_LTLIBRARIES = libaudiofile.la
+
+EXTRA_DIST = audiofile.exports
+
+libaudiofile_la_SOURCES = \
+	AIFF.cpp \
+	AIFF.h \
+	AVR.cpp \
+	AVR.h \
+	AudioFormat.cpp \
+	AudioFormat.h \
+	Buffer.cpp \
+	Buffer.h \
+	CAF.cpp \
+	CAF.h \
+	Compiler.h \
+	FLACFile.cpp \
+	FLACFile.h \
+	Features.h \
+	File.cpp \
+	File.h \
+	FileHandle.cpp \
+	FileHandle.h \
+	IFF.cpp \
+	IFF.h \
+	IRCAM.cpp \
+	IRCAM.h \
+	Instrument.cpp \
+	Instrument.h \
+	Loop.cpp \
+	Marker.cpp \
+	Marker.h \
+	Miscellaneous.cpp \
+	NIST.cpp \
+	NIST.h \
+	NeXT.cpp \
+	NeXT.h \
+	PacketTable.cpp \
+	PacketTable.h \
+	Raw.cpp \
+	Raw.h \
+	SampleVision.cpp \
+	SampleVision.h \
+	Setup.cpp \
+	Setup.h \
+	Shared.h \
+	Tag.h \
+	Track.cpp \
+	Track.h \
+	UUID.cpp \
+	UUID.h \
+	VOC.cpp \
+	VOC.h \
+	WAVE.cpp \
+	WAVE.h \
+	aes.cpp \
+	af_vfs.cpp \
+	af_vfs.h \
+	afinternal.h \
+	aupv.c \
+	aupvinternal.h \
+	aupvlist.h \
+	byteorder.h \
+	byteorder.h \
+	compression.cpp \
+	compression.h \
+	data.cpp \
+	debug.cpp \
+	debug.h \
+	error.c \
+	error.h \
+	extended.c \
+	extended.h \
+	format.cpp \
+	g711.c \
+	g711.h \
+	openclose.cpp \
+	pcm.cpp \
+	pcm.h \
+	query.cpp \
+	units.cpp \
+	units.h \
+	util.cpp \
+	util.h \
+	util.h
+
+libaudiofile_la_LIBADD = \
+	modules/libmodules.la \
+	alac/libalac.la \
+	$(COVERAGE_LIBS) \
+	$(FLAC_LIBS) \
+	-lm
+
+libaudiofile_la_LDFLAGS = -version-info $(AUDIOFILE_VERSION_INFO) \
+	-no-undefined \
+	-export-symbols $(srcdir)/audiofile.exports
+
+include_HEADERS = audiofile.h aupvlist.h af_vfs.h
+
+TESTS = UnitTests
+
+check_PROGRAMS = $(TESTS)
+
+if ENABLE_VALGRIND
+VALGRIND_FLAGS = --quiet --leak-check=full --show-reachable=yes --error-exitcode=1
+TESTS_ENVIRONMENT = $(top_builddir)/libtool --mode=execute $(VALGRIND) $(VALGRIND_FLAGS)
+endif
+
+LIBGTEST = ../gtest/libgtest.la
+
+UnitTests_SOURCES = modules/UT_RebufferModule.cpp
+UnitTests_LDADD = libaudiofile.la $(LIBGTEST)
+UnitTests_CPPFLAGS = -I$(top_srcdir)
+UnitTests_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
+UnitTests_LDFLAGS = -static
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = -DNDEBUG -Wall $(WERROR_CFLAGS) $(COVERAGE_CFLAGS) $(FLAC_CFLAGS) -fvisibility=hidden
+AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden
+
+CLEANFILES = *.gcda *.gcno
diff --git a/libaudiofile/Marker.cpp b/libaudiofile/Marker.cpp
new file mode 100644
index 0000000..e36fa94
--- /dev/null
+++ b/libaudiofile/Marker.cpp
@@ -0,0 +1,257 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Marker.cpp
+
+	This file contains routines for dealing with loop markers.
+*/
+
+#include "config.h"
+#include "Marker.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+
+void afInitMarkIDs(AFfilesetup setup, int trackid, const int *markids, int nmarks)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (track->markers != NULL)
+	{
+		for (int i=0; i<track->markerCount; i++)
+		{
+			if (track->markers[i].name != NULL)
+				free(track->markers[i].name);
+			if (track->markers[i].comment != NULL)
+				free(track->markers[i].comment);
+		}
+		free(track->markers);
+	}
+
+	track->markers = (MarkerSetup *) _af_calloc(nmarks, sizeof (struct MarkerSetup));
+	track->markerCount = nmarks;
+
+	for (int i=0; i<nmarks; i++)
+	{
+		track->markers[i].id = markids[i];
+		track->markers[i].name = _af_strdup("");
+		track->markers[i].comment = _af_strdup("");
+	}
+
+	track->markersSet = true;
+}
+
+void afInitMarkName(AFfilesetup setup, int trackid, int markid,
+	const char *namestr)
+{
+	int	markno;
+	int	length;
+
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	for (markno=0; markno<track->markerCount; markno++)
+	{
+		if (track->markers[markno].id == markid)
+			break;
+	}
+
+	if (markno == track->markerCount)
+	{
+		_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
+		return;
+	}
+
+	length = strlen(namestr);
+	if (length > 255)
+	{
+		_af_error(AF_BAD_STRLEN,
+			"warning: marker name truncated to 255 characters");
+		length = 255;
+	}
+
+	if (track->markers[markno].name)
+		free(track->markers[markno].name);
+	if ((track->markers[markno].name = (char *) _af_malloc(length+1)) == NULL)
+		return;
+	strncpy(track->markers[markno].name, namestr, length);
+	/*
+		The null terminator is not set by strncpy if
+		strlen(namestr) > length.  Set it here.
+	*/
+	track->markers[markno].name[length] = '\0';
+}
+
+void afInitMarkComment(AFfilesetup setup, int trackid, int markid,
+	const char *commstr)
+{
+	int	markno;
+	int	length;
+
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	for (markno=0; markno<track->markerCount; markno++)
+	{
+		if (track->markers[markno].id == markid)
+			break;
+	}
+
+	if (markno == track->markerCount)
+	{
+		_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
+		return;
+	}
+
+	length = strlen(commstr);
+
+	if (track->markers[markno].comment)
+		free(track->markers[markno].comment);
+	if ((track->markers[markno].comment = (char *) _af_malloc(length+1)) == NULL)
+		return;
+	strcpy(track->markers[markno].comment, commstr);
+}
+
+char *afGetMarkName (AFfilehandle file, int trackid, int markid)
+{
+	if (!_af_filehandle_ok(file))
+		return NULL;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return NULL;
+
+	Marker *marker = track->getMarker(markid);
+	if (!marker)
+		return NULL;
+
+	return marker->name;
+}
+
+char *afGetMarkComment (AFfilehandle file, int trackid, int markid)
+{
+	if (!_af_filehandle_ok(file))
+		return NULL;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return NULL;
+
+	Marker *marker = track->getMarker(markid);
+	if (!marker)
+		return NULL;
+
+	return marker->comment;
+}
+
+void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
+	AFframecount position)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	if (!file->checkCanWrite())
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	Marker *marker = track->getMarker(markid);
+	if (!marker)
+		return;
+
+	if (position < 0)
+	{
+		_af_error(AF_BAD_MARKPOS, "invalid marker position %jd",
+			static_cast<intmax_t>(position));
+		position = 0;
+	}
+
+	marker->position = position;
+}
+
+int afGetMarkIDs (AFfilehandle file, int trackid, int markids[])
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (markids != NULL)
+	{
+		for (int i=0; i<track->markerCount; i++)
+		{
+			markids[i] = track->markers[i].id;
+		}
+	}
+
+	return track->markerCount;
+}
+
+AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid)
+{
+	if (!_af_filehandle_ok(file))
+		return 0L;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return 0L;
+
+	Marker *marker = track->getMarker(markid);
+	if (!marker)
+		return 0L;
+
+	return marker->position;
+}
+
+Marker *_af_marker_new (int count)
+{
+	Marker	*markers = (Marker *) _af_calloc(count, sizeof (Marker));
+	if (markers == NULL)
+		return NULL;
+
+	return markers;
+}
diff --git a/libaudiofile/Marker.h b/libaudiofile/Marker.h
new file mode 100644
index 0000000..9dec093
--- /dev/null
+++ b/libaudiofile/Marker.h
@@ -0,0 +1,43 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef MARKER_H
+#define MARKER_H
+
+struct MarkerSetup
+{
+	int id;
+	char *name, *comment;
+};
+
+struct Marker
+{
+	short id;
+	unsigned long position;
+	char *name;
+	char *comment;
+};
+
+struct Track;
+
+Marker *_af_marker_new (int count);
+Marker *_af_marker_find_by_id (Track *track, int id);
+
+#endif /* MARKER_H */
diff --git a/libaudiofile/Miscellaneous.cpp b/libaudiofile/Miscellaneous.cpp
new file mode 100644
index 0000000..3e25eb6
--- /dev/null
+++ b/libaudiofile/Miscellaneous.cpp
@@ -0,0 +1,213 @@
+/*
+	Audio File Library
+	Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Miscellaneous.cpp
+
+	This file contains routines for dealing with the Audio File
+	Library's internal miscellaneous data types.
+*/
+
+#include "config.h"
+
+#include <algorithm>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+
+void afInitMiscIDs (AFfilesetup setup, const int *ids, int nids)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	if (setup->miscellaneous != NULL)
+	{
+		free(setup->miscellaneous);
+	}
+
+	setup->miscellaneousCount = nids;
+
+	if (nids == 0)
+		setup->miscellaneous = NULL;
+	else
+	{
+		setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(nids,
+			sizeof (MiscellaneousSetup));
+
+		if (setup->miscellaneous == NULL)
+			return;
+
+		for (int i=0; i<nids; i++)
+		{
+			setup->miscellaneous[i].id = ids[i];
+			setup->miscellaneous[i].type = 0;
+			setup->miscellaneous[i].size = 0;
+		}
+	}
+
+	setup->miscellaneousSet = true;
+}
+
+int afGetMiscIDs (AFfilehandle file, int *ids)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (ids != NULL)
+	{
+		for (int i=0; i<file->m_miscellaneousCount; i++)
+		{
+			ids[i] = file->m_miscellaneous[i].id;
+		}
+	}
+
+	return file->m_miscellaneousCount;
+}
+
+void afInitMiscType (AFfilesetup setup, int miscellaneousid, int type)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
+	if (miscellaneous)
+		miscellaneous->type = type;
+}
+
+int afGetMiscType (AFfilehandle file, int miscellaneousid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
+	if (miscellaneous)
+		return miscellaneous->type;
+	return -1;
+}
+
+void afInitMiscSize (AFfilesetup setup, int miscellaneousid, int size)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
+	if (miscellaneous)
+		miscellaneous->size = size;
+}
+
+int afGetMiscSize (AFfilehandle file, int miscellaneousid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
+	if (miscellaneous)
+		return miscellaneous->size;
+	return -1;
+}
+
+int afWriteMisc (AFfilehandle file, int miscellaneousid, const void *buf, int bytes)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (!file->checkCanWrite())
+		return -1;
+
+	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
+	if (!miscellaneous)
+		return -1;
+
+	if (bytes <= 0)
+	{
+		_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
+		return -1;
+	}
+
+	if (miscellaneous->buffer == NULL && miscellaneous->size != 0)
+	{
+		miscellaneous->buffer = _af_malloc(miscellaneous->size);
+		if (miscellaneous->buffer == NULL)
+			return -1;
+		memset(miscellaneous->buffer, 0, miscellaneous->size);
+	}
+
+	int localsize = std::min(bytes,
+		miscellaneous->size - miscellaneous->position);
+	memcpy((char *) miscellaneous->buffer + miscellaneous->position,
+		buf, localsize);
+	miscellaneous->position += localsize;
+	return localsize;
+}
+
+int afReadMisc (AFfilehandle file, int miscellaneousid, void *buf, int bytes)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (!file->checkCanRead())
+		return -1;
+
+	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
+	if (!miscellaneous)
+		return -1;
+
+	if (bytes <= 0)
+	{
+		_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
+		return -1;
+	}
+
+	int localsize = std::min(bytes,
+		miscellaneous->size - miscellaneous->position);
+	memcpy(buf, (char *) miscellaneous->buffer + miscellaneous->position,
+		localsize);
+	miscellaneous->position += localsize;
+	return localsize;
+}
+
+int afSeekMisc (AFfilehandle file, int miscellaneousid, int offset)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
+	if (!miscellaneous)
+		return -1;
+
+	if (offset >= miscellaneous->size)
+	{
+		_af_error(AF_BAD_MISCSEEK,
+			"offset %d too big for miscellaneous chunk %d "
+			"(%d data bytes)",
+			offset, miscellaneousid, miscellaneous->size);
+		return -1;
+	}
+
+	miscellaneous->position = offset;
+
+	return offset;
+}
diff --git a/libaudiofile/NIST.cpp b/libaudiofile/NIST.cpp
new file mode 100644
index 0000000..fa9f067
--- /dev/null
+++ b/libaudiofile/NIST.cpp
@@ -0,0 +1,462 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	NIST.cpp
+
+	This file contains code for reading NIST SPHERE files.
+*/
+
+#include "config.h"
+#include "NIST.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Setup.h"
+#include "Track.h"
+#include "File.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+
+#define NIST_SPHERE_HEADER_LENGTH 1024
+#define NIST_SPHERE_MAX_FIELD_LENGTH 80
+
+static const _AFfilesetup nistDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_NIST_SPHERE,	/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+bool NISTFile::recognize(File *fh)
+{
+	uint8_t buffer[16];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 16) != 16)
+		return false;
+
+	/* Check to see if the file's magic number matches. */
+	if (memcmp(buffer, "NIST_1A\n   1024\n", 16) == 0)
+		return true;
+
+	return false;
+}
+
+AFfilesetup NISTFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "NIST SPHERE file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		/* XXXmpruett: Currently we allow only 1-16 bit sample width. */
+		if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
+			(track->f.sampleWidth < 1 || track->f.sampleWidth > 16))
+		{
+			_af_error(AF_BAD_WIDTH,
+				"invalid sample width %d bits for NIST SPHERE format",
+				track->f.sampleWidth);
+			return AF_NULL_FILESETUP;
+		}
+		else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"NIST SPHERE format does not support unsigned data");
+			return AF_NULL_FILESETUP;
+		}
+		else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
+			track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"NIST SPHERE format does not support floating-point data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+
+	if (track->rateSet && track->f.sampleRate <= 0.0)
+	{
+		_af_error(AF_BAD_RATE,
+			"invalid sample rate %.30g for NIST SPHERE file",
+			track->f.sampleRate);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->compressionSet && track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED,
+			"NIST SPHERE format supports only G.711 u-law or A-law compression");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "NIST SPHERE file cannot have AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_NUMMARKS, "NIST SPHERE format does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_NUMINSTS, "NIST SPHERE format does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	/* XXXmpruett: We don't support miscellaneous chunks for now. */
+	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "NIST SPHERE format does not currently support miscellaneous chunks");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &nistDefaultFileSetup, true);
+}
+
+static bool nist_header_read_int (const char *header, const char *key, int *val)
+{
+	const char *cp;
+	char keystring[256], scanstring[256];
+
+	snprintf(keystring, 256, "\n%s -i", key);
+
+	if ((cp = strstr(header, keystring)) != NULL)
+	{
+		snprintf(scanstring, 256, "\n%s -i %%d", key);
+		sscanf(cp, scanstring, val);
+		return true;
+	}
+
+	return false;
+}
+
+static bool nist_header_read_string (const char *header, const char *key, int *length, char *val)
+{
+	const char *cp;
+	char keystring[256], scanstring[256];
+
+	snprintf(keystring, 256, "\n%s -s", key);
+
+	if ((cp = strstr(header, keystring)) != NULL)
+	{
+		snprintf(scanstring, 256, "\n%s -s%%d %%79s", key);
+		sscanf(cp, scanstring, length, val);
+		return true;
+	}
+
+	return false;
+}
+
+status NISTFile::readInit(AFfilesetup setup)
+{
+	char header[NIST_SPHERE_HEADER_LENGTH + 1];
+	int intval;
+	char strval[NIST_SPHERE_MAX_FIELD_LENGTH];
+	int sample_n_bytes;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	if (m_fh->read(header, NIST_SPHERE_HEADER_LENGTH) != NIST_SPHERE_HEADER_LENGTH)
+	{
+		_af_error(AF_BAD_READ, "Could not read NIST SPHERE file header");
+		return AF_FAIL;
+	}
+
+	header[NIST_SPHERE_HEADER_LENGTH] = '\0';
+
+	if (memcmp(header, "NIST_1A\n   1024\n", 16) != 0)
+	{
+		_af_error(AF_BAD_FILEFMT, "Bad NIST SPHERE file header");
+		return AF_FAIL;
+	}
+
+	Track *track = allocateTrack();
+	if (!track)
+		return AF_FAIL;
+
+	// Read channel count.
+	if (nist_header_read_int(header, "channel_count", &intval))
+	{
+		if (intval < 1)
+		{
+			_af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
+				intval);
+			return AF_FAIL;
+		}
+		track->f.channelCount = intval;
+	}
+	else
+	{
+		_af_error(AF_BAD_HEADER, "number of channels not specified");
+		return AF_FAIL;
+	}
+
+	// Read number of bytes per sample.
+	if (!nist_header_read_int(header, "sample_n_bytes", &sample_n_bytes))
+	{
+		_af_error(AF_BAD_HEADER, "bytes per sample not specified");
+		return AF_FAIL;
+	}
+
+	track->f.framesPerPacket = 1;
+
+	/*
+		Since some older NIST SPHERE files lack a sample_coding
+		field, if sample_n_bytes is 1, assume mu-law;
+		otherwise assume linear PCM.
+	*/
+	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+	if (sample_n_bytes == 1)
+	{
+		track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+		track->f.sampleWidth = 16;
+		track->f.bytesPerPacket = track->f.channelCount;
+	}
+	else
+	{
+		track->f.compressionType = AF_COMPRESSION_NONE;
+		track->f.sampleWidth = sample_n_bytes * 8;
+		track->f.computeBytesPerPacketPCM();
+	}
+
+	if (nist_header_read_string(header, "sample_coding", &intval, strval))
+	{
+		if (strcmp(strval, "pcm") == 0)
+			;
+		else if (strcmp(strval, "ulaw") == 0 || strcmp(strval, "mu-law") == 0)
+		{
+			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+			track->f.sampleWidth = 16;
+		}
+		else if (strcmp(strval, "alaw") == 0)
+		{
+			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+			track->f.sampleWidth = 16;
+		}
+		else
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"unrecognized NIST SPHERE sample format %s", strval);
+			return AF_FAIL;
+		}
+	}
+
+	// Read string representing byte order.
+	if (nist_header_read_string(header, "sample_byte_format", &intval, strval))
+	{
+		if (intval > 1)
+		{
+			if (strncmp(strval, "01", 2) == 0)
+				track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+			else
+				track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+		}
+		else
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	}
+	else
+	{
+		/*
+			Fail if this field is not present and sample
+			width is more than one byte.
+		*/
+		if (track->f.compressionType == AF_COMPRESSION_NONE &&
+			track->f.sampleWidth > 8)
+		{
+			_af_error(AF_BAD_HEADER, "sample byte order not specified");
+			return AF_FAIL;
+		}
+	}
+
+	// Read significant bits per sample.
+	if (nist_header_read_int(header, "sample_sig_bits", &intval))
+	{
+		if (intval < 1 || intval > 32)
+		{
+			_af_error(AF_BAD_WIDTH, "invalid sample width %d bits\n",
+				intval);
+			return AF_FAIL;
+		}
+
+		/*
+			Use specified significant bits value as the
+			sample width for uncompressed data as long
+			as the number of bytes per sample remains
+			unchanged.
+		*/
+		if (track->f.compressionType == AF_COMPRESSION_NONE &&
+			(intval + 7) / 8 == sample_n_bytes)
+		{
+			track->f.sampleWidth = intval;
+		}
+	}
+
+	// Read sample rate.
+	if (nist_header_read_int(header, "sample_rate", &intval))
+	{
+		if (intval <= 0)
+		{
+			_af_error(AF_BAD_RATE, "invalid sample rate %d Hz\n", intval);
+			return AF_FAIL;
+		}
+		track->f.sampleRate = intval;
+	}
+	else
+	{
+		_af_error(AF_BAD_HEADER, "sample rate not specified");
+		return AF_FAIL;
+	}
+
+	// Read sample count.
+	if (nist_header_read_int(header, "sample_count", &intval))
+	{
+		track->totalfframes = intval;
+	}
+	else
+	{
+		_af_error(AF_BAD_HEADER, "number of samples not specified");
+		return AF_FAIL;
+	}
+
+	if (_af_set_sample_format(&track->f, track->f.sampleFormat,
+		track->f.sampleWidth) == AF_FAIL)
+	{
+		return AF_FAIL;
+	}
+
+	track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;
+	track->data_size = m_fh->length() - NIST_SPHERE_HEADER_LENGTH;
+
+	return AF_SUCCEED;
+}
+
+static const char *sample_byte_format (AudioFormat *fmt)
+{
+	int nbytes = _af_format_sample_size(fmt, false);
+
+	assert(nbytes == 1 || nbytes == 2);
+
+	if (nbytes == 1)
+		return "0";
+	else if (nbytes == 2)
+	{
+		if (fmt->byteOrder == AF_BYTEORDER_BIGENDIAN)
+			return "10";
+		else
+			return "01";
+	}
+
+	/* NOTREACHED */
+	return NULL;
+}
+
+static const char *sample_coding (AudioFormat *fmt)
+{
+	if (fmt->compressionType == AF_COMPRESSION_NONE)
+		return "pcm";
+	else if (fmt->compressionType == AF_COMPRESSION_G711_ULAW)
+		return "ulaw";
+	else if (fmt->compressionType == AF_COMPRESSION_G711_ALAW)
+		return "alaw";
+
+	/* NOTREACHED */
+	return NULL;
+}
+
+status NISTFile::writeHeader()
+{
+	Track *track = getTrack();
+
+	char header[NIST_SPHERE_HEADER_LENGTH];
+	int printed = snprintf(header, NIST_SPHERE_HEADER_LENGTH,
+		"NIST_1A\n   1024\n"
+		"channel_count -i %d\n"
+		"sample_count -i %d\n"
+		"sample_rate -i %d\n"
+		"sample_n_bytes -i %d\n"
+		"sample_byte_format -s%d %s\n"
+		"sample_sig_bits -i %d\n"
+		"sample_coding -s%d %s\n"
+		"end_head\n",
+		track->f.channelCount,
+		(int) track->totalfframes,
+		(int) track->f.sampleRate,
+		(int) _af_format_sample_size(&track->f, false),
+		(int) _af_format_sample_size(&track->f, false), sample_byte_format(&track->f),
+		track->f.sampleWidth,
+		(int) strlen(sample_coding(&track->f)), sample_coding(&track->f));
+
+	/* Fill the remaining space in the buffer with space characters. */
+	if (printed < NIST_SPHERE_HEADER_LENGTH)
+		memset(header + printed, ' ', NIST_SPHERE_HEADER_LENGTH - printed);
+
+	return m_fh->write(header, NIST_SPHERE_HEADER_LENGTH) == NIST_SPHERE_HEADER_LENGTH ? AF_SUCCEED : AF_FAIL;
+}
+
+status NISTFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	Track *track = getTrack();
+
+	track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+	writeHeader();
+
+	return AF_SUCCEED;
+}
+
+status NISTFile::update()
+{
+	m_fh->seek(0, File::SeekFromBeginning);
+	writeHeader();
+
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/NIST.h b/libaudiofile/NIST.h
new file mode 100644
index 0000000..949a6d0
--- /dev/null
+++ b/libaudiofile/NIST.h
@@ -0,0 +1,47 @@
+/*
+	Audio File Library
+	Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	NIST.h
+
+	This file declares code for reading and writing NIST SPHERE files.
+*/
+
+#ifndef NIST_H
+#define NIST_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+class NISTFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup setup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+	status writeHeader();
+};
+
+#endif
diff --git a/libaudiofile/NeXT.cpp b/libaudiofile/NeXT.cpp
new file mode 100644
index 0000000..c462dbe
--- /dev/null
+++ b/libaudiofile/NeXT.cpp
@@ -0,0 +1,366 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2011-2013, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	NeXT.cpp
+
+	This file contains routines for reading and writing NeXT/Sun
+	.snd/.au sound files.
+*/
+
+#include "config.h"
+#include "NeXT.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+
+const int _af_next_compression_types[_AF_NEXT_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW
+};
+
+static const _AFfilesetup nextDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_NEXTSND,	/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+enum
+{
+	_AU_FORMAT_UNSPECIFIED = 0,
+	_AU_FORMAT_MULAW_8 = 1,		/* CCITT G.711 mu-law 8-bit */
+	_AU_FORMAT_LINEAR_8 = 2,
+	_AU_FORMAT_LINEAR_16 = 3,
+	_AU_FORMAT_LINEAR_24 = 4,
+	_AU_FORMAT_LINEAR_32 = 5,
+	_AU_FORMAT_FLOAT = 6,
+	_AU_FORMAT_DOUBLE = 7,
+	_AU_FORMAT_INDIRECT = 8,
+	_AU_FORMAT_NESTED = 9,
+	_AU_FORMAT_DSP_CORE = 10,
+	_AU_FORMAT_DSP_DATA_8 = 11,	/* 8-bit fixed point */
+	_AU_FORMAT_DSP_DATA_16 = 12,	/* 16-bit fixed point */
+	_AU_FORMAT_DSP_DATA_24 = 13,	/* 24-bit fixed point */
+	_AU_FORMAT_DSP_DATA_32 = 14,	/* 32-bit fixed point */
+	_AU_FORMAT_DISPLAY = 16,
+	_AU_FORMAT_MULAW_SQUELCH = 17,	/* 8-bit mu-law, squelched */
+	_AU_FORMAT_EMPHASIZED = 18,
+	_AU_FORMAT_COMPRESSED = 19,
+	_AU_FORMAT_COMPRESSED_EMPHASIZED = 20,
+	_AU_FORMAT_DSP_COMMANDS = 21,
+	_AU_FORMAT_DSP_COMMANDS_SAMPLES = 22,
+	_AU_FORMAT_ADPCM_G721 = 23,	/* CCITT G.721 ADPCM 32 kbits/s */
+	_AU_FORMAT_ADPCM_G722 = 24,	/* CCITT G.722 ADPCM */
+	_AU_FORMAT_ADPCM_G723_3 = 25,	/* CCITT G.723 ADPCM 24 kbits/s */
+	_AU_FORMAT_ADPCM_G723_5 = 26,	/* CCITT G.723 ADPCM 40 kbits/s */
+	_AU_FORMAT_ALAW_8 = 27,		/* CCITT G.711 a-law */
+	_AU_FORMAT_AES = 28,
+	_AU_FORMAT_DELTA_MULAW_8 = 29
+};
+
+static const uint32_t _AU_LENGTH_UNSPECIFIED = 0xffffffff;
+
+NeXTFile::NeXTFile()
+{
+	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
+}
+
+status NeXTFile::readInit(AFfilesetup setup)
+{
+	uint32_t id, offset, length, encoding, sampleRate, channelCount;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	m_fh->read(&id, 4);
+	assert(!memcmp(&id, ".snd", 4));
+
+	readU32(&offset);
+	readU32(&length);
+	readU32(&encoding);
+	readU32(&sampleRate);
+	readU32(&channelCount);
+
+	if (!channelCount)
+	{
+		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
+		return AF_FAIL;
+	}
+
+	Track *track = allocateTrack();
+	if (!track)
+		return AF_FAIL;
+
+	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+	track->f.sampleRate = sampleRate;
+	track->f.channelCount = channelCount;
+	track->f.framesPerPacket = 1;
+
+	/* Override the compression type later if necessary. */
+	track->f.compressionType = AF_COMPRESSION_NONE;
+
+	track->fpos_first_frame = offset;
+
+	off_t lengthAvailable = m_fh->length() - offset;
+	if (length == _AU_LENGTH_UNSPECIFIED || static_cast<off_t>(length) > lengthAvailable)
+		length = lengthAvailable;
+
+	track->data_size = length;
+
+	switch (encoding)
+	{
+		case _AU_FORMAT_MULAW_8:
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.bytesPerPacket = track->f.channelCount;
+			break;
+		case _AU_FORMAT_ALAW_8:
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.bytesPerPacket = track->f.channelCount;
+			break;
+		case _AU_FORMAT_LINEAR_8:
+			track->f.sampleWidth = 8;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			break;
+		case _AU_FORMAT_LINEAR_16:
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			break;
+		case _AU_FORMAT_LINEAR_24:
+			track->f.sampleWidth = 24;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			break;
+		case _AU_FORMAT_LINEAR_32:
+			track->f.sampleWidth = 32;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			break;
+		case _AU_FORMAT_FLOAT:
+			track->f.sampleWidth = 32;
+			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+			break;
+		case _AU_FORMAT_DOUBLE:
+			track->f.sampleWidth = 64;
+			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+			break;
+
+		default:
+			/*
+				This encoding method is not recognized.
+			*/
+			_af_error(AF_BAD_SAMPFMT, "bad sample format");
+			return AF_FAIL;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.computeBytesPerPacketPCM();
+
+	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+	track->computeTotalFileFrames();
+
+	return AF_SUCCEED;
+}
+
+bool NeXTFile::recognize(File *fh)
+{
+	uint8_t buffer[4];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 4) != 4 || memcmp(buffer, ".snd", 4) != 0)
+		return false;
+
+	return true;
+}
+
+AFfilesetup NeXTFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "NeXT files must have exactly 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+	{
+		_af_error(AF_BAD_FILEFMT, "NeXT format does not support unsigned data");
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
+	}
+
+	if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
+	{
+		if (track->f.sampleWidth != 8 &&
+			track->f.sampleWidth != 16 &&
+			track->f.sampleWidth != 24 &&
+			track->f.sampleWidth != 32)
+		{
+			_af_error(AF_BAD_WIDTH, "invalid sample width %d for NeXT file (only 8-, 16-, 24-, and 32-bit data are allowed)", track->f.sampleWidth);
+			return AF_NULL_FILESETUP;
+		}
+	}
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not implemented for NeXT files");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed() &&
+		track->byteOrderSet &&
+		track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
+		track->f.isByteOrderSignificant())
+	{
+		_af_error(AF_BAD_BYTEORDER, "NeXT format supports only big-endian data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "NeXT files cannot have AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "NeXT format does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "NeXT format does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+	{
+		_af_error(AF_BAD_FILESETUP, "NeXT format does not support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &nextDefaultFileSetup, false);
+}
+
+static uint32_t nextencodingtype (AudioFormat *format);
+
+status NeXTFile::update()
+{
+	writeHeader();
+	return AF_SUCCEED;
+}
+
+status NeXTFile::writeHeader()
+{
+	Track *track = getTrack();
+
+	if (m_fh->seek(0, File::SeekFromBeginning) != 0)
+		_af_error(AF_BAD_LSEEK, "bad seek");
+
+	uint32_t offset = track->fpos_first_frame;
+	uint32_t length = track->data_size;
+	uint32_t encoding = nextencodingtype(&track->f);
+	uint32_t sampleRate = track->f.sampleRate;
+	uint32_t channelCount = track->f.channelCount;
+
+	m_fh->write(".snd", 4);
+	writeU32(&offset);
+	writeU32(&length);
+	writeU32(&encoding);
+	writeU32(&sampleRate);
+	writeU32(&channelCount);
+
+	return AF_SUCCEED;
+}
+
+static uint32_t nextencodingtype (AudioFormat *format)
+{
+	uint32_t encoding = 0;
+
+	if (format->compressionType != AF_COMPRESSION_NONE)
+	{
+		if (format->compressionType == AF_COMPRESSION_G711_ULAW)
+			encoding = _AU_FORMAT_MULAW_8;
+		else if (format->compressionType == AF_COMPRESSION_G711_ALAW)
+			encoding = _AU_FORMAT_ALAW_8;
+	}
+	else if (format->sampleFormat == AF_SAMPFMT_TWOSCOMP)
+	{
+		if (format->sampleWidth == 8)
+			encoding = _AU_FORMAT_LINEAR_8;
+		else if (format->sampleWidth == 16)
+			encoding = _AU_FORMAT_LINEAR_16;
+		else if (format->sampleWidth == 24)
+			encoding = _AU_FORMAT_LINEAR_24;
+		else if (format->sampleWidth == 32)
+			encoding = _AU_FORMAT_LINEAR_32;
+	}
+	else if (format->sampleFormat == AF_SAMPFMT_FLOAT)
+		encoding = _AU_FORMAT_FLOAT;
+	else if (format->sampleFormat == AF_SAMPFMT_DOUBLE)
+		encoding = _AU_FORMAT_DOUBLE;
+
+	return encoding;
+}
+
+status NeXTFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	writeHeader();
+
+	Track *track = getTrack();
+	track->fpos_first_frame = 28;
+
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/NeXT.h b/libaudiofile/NeXT.h
new file mode 100644
index 0000000..a732679
--- /dev/null
+++ b/libaudiofile/NeXT.h
@@ -0,0 +1,53 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	NeXT.h
+
+	This file contains headers and constants related to the NeXT/Sun
+	.snd audio file format.
+*/
+
+#ifndef NEXT_H
+#define NEXT_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+#define _AF_NEXT_NUM_COMPTYPES 2
+extern const int _af_next_compression_types[_AF_NEXT_NUM_COMPTYPES];
+
+class NeXTFile : public _AFfilehandle
+{
+public:
+	NeXTFile();
+
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+	status writeHeader();
+};
+
+#endif
diff --git a/libaudiofile/PacketTable.cpp b/libaudiofile/PacketTable.cpp
new file mode 100644
index 0000000..9acf7d4
--- /dev/null
+++ b/libaudiofile/PacketTable.cpp
@@ -0,0 +1,69 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "PacketTable.h"
+
+PacketTable::PacketTable(int64_t numValidFrames, int32_t primingFrames,
+	int32_t remainderFrames) :
+	m_numValidFrames(numValidFrames),
+	m_primingFrames(primingFrames),
+	m_remainderFrames(remainderFrames)
+{
+}
+
+PacketTable::PacketTable()
+{
+	m_numValidFrames = 0;
+	m_primingFrames = 0;
+	m_remainderFrames = 0;
+}
+
+PacketTable::~PacketTable()
+{
+}
+
+void PacketTable::setNumValidFrames(int64_t numValidFrames)
+{
+	m_numValidFrames = numValidFrames;
+}
+
+void PacketTable::setPrimingFrames(int32_t primingFrames)
+{
+	m_primingFrames = primingFrames;
+}
+
+void PacketTable::setRemainderFrames(int32_t remainderFrames)
+{
+	m_remainderFrames = remainderFrames;
+}
+
+void PacketTable::append(size_t bytesPerPacket)
+{
+	m_bytesPerPacket.push_back(bytesPerPacket);
+}
+
+AFfileoffset PacketTable::startOfPacket(size_t packet) const
+{
+	AFfileoffset offset = 0;
+	for (size_t i=0; i<packet; i++)
+		offset += m_bytesPerPacket[i];
+	return offset;
+}
diff --git a/libaudiofile/PacketTable.h b/libaudiofile/PacketTable.h
new file mode 100644
index 0000000..397e97d
--- /dev/null
+++ b/libaudiofile/PacketTable.h
@@ -0,0 +1,61 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef PacketTable_h
+#define PacketTable_h
+
+#include "Shared.h"
+
+#include <audiofile.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+class PacketTable : public Shared<PacketTable>
+{
+public:
+	PacketTable();
+	PacketTable(int64_t numValidFrames,
+		int32_t primingFrames,
+		int32_t remainderFrames);
+	~PacketTable();
+
+	size_t numPackets() const { return m_bytesPerPacket.size(); }
+	int64_t numValidFrames() const { return m_numValidFrames; }
+	void setNumValidFrames(int64_t numValidFrames);
+	int32_t primingFrames() const { return m_primingFrames; }
+	void setPrimingFrames(int32_t primingFrames);
+	int32_t remainderFrames() const { return m_remainderFrames; }
+	void setRemainderFrames(int32_t remainderFrames);
+
+	void append(size_t bytesPerPacket);
+	size_t bytesPerPacket(size_t packet) const { return m_bytesPerPacket[packet]; }
+	AFfileoffset startOfPacket(size_t packet) const;
+
+private:
+	int64_t m_numValidFrames;
+	int32_t m_primingFrames;
+	int32_t m_remainderFrames;
+
+	std::vector<size_t> m_bytesPerPacket;
+};
+
+#endif
diff --git a/libaudiofile/Raw.cpp b/libaudiofile/Raw.cpp
new file mode 100644
index 0000000..f276196
--- /dev/null
+++ b/libaudiofile/Raw.cpp
@@ -0,0 +1,189 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Raw.cpp
+
+	This file contains code for reading and writing raw audio
+	data files.
+*/
+
+#include "config.h"
+#include "Raw.h"
+
+#include "File.h"
+#include "Setup.h"
+#include "Track.h"
+#include "util.h"
+
+static const _AFfilesetup rawDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	// valid
+	AF_FILE_RAWDATA,		// fileFormat
+	true,	// trackSet
+	true,	// instrumentSet
+	true,	// miscellaneousSet
+	1,		// trackCount
+	NULL,	// tracks
+	0,		// instrumentCount
+	NULL,	// instruments
+	0,		// miscellaneousCount
+	NULL	// miscellaneous
+};
+
+const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW
+};
+
+bool RawFile::recognize(File *fh)
+{
+	return false;
+}
+
+status RawFile::readInit(AFfilesetup fileSetup)
+{
+	if (!fileSetup)
+	{
+		_af_error(AF_BAD_FILESETUP, "a valid AFfilesetup is required for reading raw data");
+		return AF_FAIL;
+	}
+
+	if (initFromSetup(fileSetup) == AF_FAIL)
+		return AF_FAIL;
+
+	TrackSetup *trackSetup = fileSetup->getTrack();
+	if (!trackSetup)
+		return AF_FAIL;
+
+	Track *track = getTrack();
+
+	/* Set the track's data offset. */
+	if (trackSetup->dataOffsetSet)
+		track->fpos_first_frame = trackSetup->dataOffset;
+	else
+		track->fpos_first_frame = 0;
+
+	/* Set the track's frame count. */
+	if (trackSetup->frameCountSet)
+	{
+		track->totalfframes = trackSetup->frameCount;
+	}
+	else
+	{
+		AFfileoffset filesize = m_fh->length();
+		if (filesize == -1)
+			track->totalfframes = -1;
+		else
+		{
+			/* Ensure that the data offset is valid. */
+			if (track->fpos_first_frame > filesize)
+			{
+				_af_error(AF_BAD_FILESETUP, "data offset is larger than file size");
+				return AF_FAIL;
+			}
+
+			filesize -= track->fpos_first_frame;
+			track->totalfframes = filesize / (int) _af_format_frame_size(&track->f, false);
+		}
+		track->data_size = filesize;
+	}
+
+	return AF_SUCCEED;
+}
+
+status RawFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	TrackSetup *trackSetup = setup->getTrack();
+	if (!trackSetup)
+		return AF_FAIL;
+
+	Track *track = getTrack();
+
+	if (trackSetup->dataOffsetSet)
+		track->fpos_first_frame = trackSetup->dataOffset;
+	else
+		track->fpos_first_frame = 0;
+
+	return AF_SUCCEED;
+}
+
+status RawFile::update()
+{
+	return AF_SUCCEED;
+}
+
+AFfilesetup RawFile::completeSetup(AFfilesetup setup)
+{
+	AFfilesetup	newSetup;
+
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_FILESETUP, "raw file must have exactly one track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+	{
+		_af_error(AF_BAD_FILESETUP, "could not access track in file setup");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "raw file cannot have AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount != 0)
+	{
+		_af_error(AF_BAD_NUMMARKS, "raw file cannot have markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount != 0)
+	{
+		_af_error(AF_BAD_NUMINSTS, "raw file cannot have instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+	{
+		_af_error(AF_BAD_NUMMISC, "raw file cannot have miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	newSetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
+	*newSetup = rawDefaultFileSetup;
+
+	newSetup->tracks = (TrackSetup *) _af_malloc(sizeof (TrackSetup));
+	newSetup->tracks[0] = setup->tracks[0];
+	newSetup->tracks[0].f.compressionParams = NULL;
+
+	newSetup->tracks[0].markerCount = 0;
+	newSetup->tracks[0].markers = NULL;
+
+	return newSetup;
+}
diff --git a/libaudiofile/Raw.h b/libaudiofile/Raw.h
new file mode 100644
index 0000000..04eef5d
--- /dev/null
+++ b/libaudiofile/Raw.h
@@ -0,0 +1,45 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Raw.h
+*/
+
+#ifndef RAW_H
+#define RAW_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+#define _AF_RAW_NUM_COMPTYPES 2
+extern const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES];
+
+class RawFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup setup) OVERRIDE;
+	status writeInit(AFfilesetup setup) OVERRIDE;
+	status update() OVERRIDE;
+};
+
+#endif
diff --git a/libaudiofile/SampleVision.cpp b/libaudiofile/SampleVision.cpp
new file mode 100644
index 0000000..5b3ce9c
--- /dev/null
+++ b/libaudiofile/SampleVision.cpp
@@ -0,0 +1,348 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "SampleVision.h"
+
+#include "File.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "util.h"
+#include <string.h>
+
+static const char *kSMPMagic = "SOUND SAMPLE DATA ";
+static const unsigned kSMPMagicLength = 18;
+static const char *kSMPVersion = "2.1 ";
+static const unsigned kSMPVersionLength = 4;
+static const unsigned kSMPNameLength = 30;
+static const unsigned kSMPCommentLength = 60;
+static const unsigned kSMPMarkerNameLength = 10;
+static const uint32_t kSMPInvalidSamplePosition = 0xffffffffu;
+
+static const uint8_t kSMPMIDIUnityPlaybackNote = 60;
+
+static const _AFfilesetup sSampleVisionDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,
+	AF_FILE_SAMPLEVISION,
+	true,	// trackSet
+	true,	// instrumentSet
+	true,	// miscellaneousSet
+	1,		// trackCount
+	NULL,	// tracks
+	1,		// instrumentCount
+	NULL,	// instruments
+	0,		// miscellaneousCount
+	NULL	// miscellaneous
+};
+
+static void trimTrailingSpaces(char *s)
+{
+	int n = strlen(s);
+	if (!n)
+		return;
+	while (--n > 0 && s[n] == ' ')
+		;
+	s[n+1] = '\0';
+}
+
+SampleVisionFile::SampleVisionFile() :
+	m_frameCountOffset(-1)
+{
+	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
+}
+
+SampleVisionFile::~SampleVisionFile()
+{
+}
+
+bool SampleVisionFile::recognize(File *fh)
+{
+	fh->seek(0, File::SeekFromBeginning);
+	char magic[kSMPMagicLength];
+	if (fh->read(magic, kSMPMagicLength) != (ssize_t) kSMPMagicLength)
+		return false;
+	return !strncmp(magic, kSMPMagic, kSMPMagicLength);
+}
+
+AFfilesetup SampleVisionFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "SampleVision file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		if (!track->f.isSigned() || track->f.sampleWidth != 16)
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"SampleVision format supports only 16-bit signed integer audio data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+	else
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+			track->f.sampleWidth);
+
+	if (track->byteOrderSet && track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN)
+	{
+		// Treat error as correctable.
+		_af_error(AF_BAD_BYTEORDER, "SampleVision supports only little-endian data");
+	}
+
+	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+
+	if (track->compressionSet && !track->f.isUncompressed())
+	{
+		_af_error(AF_BAD_COMPTYPE, "SampleVision does not support compressed audio data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount)
+	{
+		_af_error(AF_BAD_NUMMARKS, "SampleVision does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "SampleVision does not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount)
+	{
+		_af_error(AF_BAD_FILESETUP, "SampleVision does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount)
+	{
+		_af_error(AF_BAD_FILESETUP, "SampleVision does not support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &sSampleVisionDefaultFileSetup, true);
+}
+
+status SampleVisionFile::readInit(AFfilesetup)
+{
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	char magic[kSMPMagicLength];
+	if (m_fh->read(magic, kSMPMagicLength) != (ssize_t) kSMPMagicLength)
+		return AF_FAIL;
+	if (strncmp(magic, kSMPMagic, kSMPMagicLength) != 0)
+		return AF_FAIL;
+
+	char version[kSMPVersionLength];
+	if (m_fh->read(version, kSMPVersionLength) != (ssize_t) kSMPVersionLength)
+		return AF_FAIL;
+	if (strncmp(version, kSMPVersion, kSMPVersionLength) != 0)
+		return AF_FAIL;
+
+	Track *track = allocateTrack();
+
+	char name[kSMPNameLength + 1];
+	m_fh->read(name, kSMPNameLength);
+	name[kSMPNameLength] = '\0';
+	trimTrailingSpaces(name);
+	if (strlen(name) > 0)
+		addMiscellaneous(AF_MISC_NAME, name);
+
+	char comment[kSMPCommentLength + 1];
+	m_fh->read(comment, kSMPCommentLength);
+	comment[kSMPCommentLength] = '\0';
+	trimTrailingSpaces(comment);
+	if (strlen(comment) > 0)
+		addMiscellaneous(AF_MISC_COMMENT, comment);
+
+	uint32_t frameCount;
+	readU32(&frameCount);
+	track->totalfframes = frameCount;
+	track->fpos_first_frame = m_fh->tell();
+	track->data_size = 2 * frameCount;
+
+	m_fh->seek(track->data_size, File::SeekFromCurrent);
+
+	uint16_t reserved;
+	readU16(&reserved);
+
+	parseLoops();
+	parseMarkers();
+
+	uint8_t midiNote;
+	uint32_t sampleRate;
+	uint32_t smpteOffset;
+	uint32_t cycleLength;
+
+	readU8(&midiNote);
+	readU32(&sampleRate);
+	readU32(&smpteOffset);
+	readU32(&cycleLength);
+
+	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+	track->f.sampleRate = sampleRate;
+	track->f.channelCount = 1;
+	track->f.compressionType = AF_COMPRESSION_NONE;
+	track->f.framesPerPacket = 1;
+	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+	track->f.computeBytesPerPacketPCM();
+
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::parseLoops()
+{
+	for (int i=0; i<8; i++)
+	{
+		uint32_t startFrame, endFrame;
+		uint8_t type;
+		uint16_t count;
+		readU32(&startFrame);
+		readU32(&endFrame);
+		readU8(&type);
+		readU16(&count);
+	}
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::parseMarkers()
+{
+	for (int i=0; i<8; i++)
+	{
+		char name[kSMPMarkerNameLength + 1];
+		m_fh->read(name, kSMPMarkerNameLength);
+		name[kSMPMarkerNameLength] = '\0';
+		uint32_t position;
+		readU32(&position);
+	}
+	return AF_SUCCEED;
+}
+
+void SampleVisionFile::addMiscellaneous(int type, const char *data)
+{
+	m_miscellaneousCount++;
+	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
+		m_miscellaneousCount * sizeof (Miscellaneous));
+
+	Miscellaneous &m = m_miscellaneous[m_miscellaneousCount - 1];
+	m.id = m_miscellaneousCount;
+	m.type = type;
+	m.size = strlen(data);
+	m.position = 0;
+	m.buffer = _af_malloc(m.size);
+	memcpy(m.buffer, data, m.size);
+}
+
+status SampleVisionFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	m_fh->write(kSMPMagic, kSMPMagicLength);
+	m_fh->write(kSMPVersion, kSMPVersionLength);
+
+	char name[kSMPNameLength + 1];
+	char comment[kSMPCommentLength + 1];
+	memset(name, ' ', kSMPNameLength);
+	memset(comment, ' ', kSMPCommentLength);
+	m_fh->write(name, kSMPNameLength);
+	m_fh->write(comment, kSMPCommentLength);
+
+	uint32_t frameCount = 0;
+	m_frameCountOffset = m_fh->tell();
+	writeU32(&frameCount);
+
+	Track *track = getTrack();
+	track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::update()
+{
+	m_fh->seek(m_frameCountOffset, File::SeekFromBeginning);
+	Track *track = getTrack();
+	uint32_t frameCount = track->totalfframes;
+	writeU32(&frameCount);
+	writeTrailer();
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::writeTrailer()
+{
+	Track *track = getTrack();
+
+	m_fh->seek(track->fpos_after_data, File::SeekFromBeginning);
+
+	uint16_t reserved = 0;
+	writeU16(&reserved);
+
+	writeLoops();
+	writeMarkers();
+
+	uint8_t midiNote = kSMPMIDIUnityPlaybackNote;
+	uint32_t sampleRate = track->f.sampleRate;
+	uint32_t smpteOffset = 0;
+	uint32_t cycleLength = 0;
+
+	writeU8(&midiNote);
+	writeU32(&sampleRate);
+	writeU32(&smpteOffset);
+	writeU32(&cycleLength);
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::writeLoops()
+{
+	for (int i=0; i<8; i++)
+	{
+		uint32_t startFrame = kSMPInvalidSamplePosition, endFrame = 0;
+		uint8_t type = 0;
+		uint16_t count = 0;
+		writeU32(&startFrame);
+		writeU32(&endFrame);
+		writeU8(&type);
+		writeU16(&count);
+	}
+	return AF_SUCCEED;
+}
+
+status SampleVisionFile::writeMarkers()
+{
+	for (int i=0; i<8; i++)
+	{
+		char name[kSMPMarkerNameLength + 1];
+		memset(name, ' ', kSMPMarkerNameLength);
+		name[kSMPMarkerNameLength] = '\0';
+		m_fh->write(name, kSMPMarkerNameLength);
+		uint32_t position = kSMPInvalidSamplePosition;
+		writeU32(&position);
+	}
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/SampleVision.h b/libaudiofile/SampleVision.h
new file mode 100644
index 0000000..7404f27
--- /dev/null
+++ b/libaudiofile/SampleVision.h
@@ -0,0 +1,54 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef SAMPLE_VISION_H
+#define SAMPLE_VISION_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+class SampleVisionFile : public _AFfilehandle
+{
+public:
+	SampleVisionFile();
+	virtual ~SampleVisionFile();
+
+	static bool recognize(File *fh);
+
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+
+	status update() OVERRIDE;
+
+private:
+	AFfileoffset m_frameCountOffset;
+
+	status parseLoops();
+	status parseMarkers();
+	status writeTrailer();
+	status writeLoops();
+	status writeMarkers();
+
+	void addMiscellaneous(int type, const char *data);
+};
+
+#endif
diff --git a/libaudiofile/Setup.cpp b/libaudiofile/Setup.cpp
new file mode 100644
index 0000000..cd32002
--- /dev/null
+++ b/libaudiofile/Setup.cpp
@@ -0,0 +1,560 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	Setup.cpp
+*/
+
+#include "config.h"
+#include "Setup.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "FileHandle.h"
+#include "Instrument.h"
+#include "Marker.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "audiofile.h"
+#include "pcm.h"
+#include "units.h"
+#include "util.h"
+
+static const _AFfilesetup _af_default_file_setup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+#if WORDS_BIGENDIAN
+	AF_FILE_AIFFC,	/* file format */
+#else
+	AF_FILE_WAVE,	/* file format */
+#endif
+	false,		/* trackSet */
+	false,		/* instrumentSet */
+	false,		/* miscellaneousSet */
+	1,		/* trackCount */
+	NULL,		/* tracks */
+	1,		/* instrumentCount */
+	NULL,		/* instruments */
+	0,		/* miscellaneousCount */
+	NULL		/* miscellaneous */
+};
+
+static const InstrumentSetup _af_default_instrumentsetup =
+{
+	0,		/* id */
+	2,		/* loopCount */
+	NULL,		/* loops */
+	false		/* loopSet */
+};
+
+static const TrackSetup _af_default_tracksetup =
+{
+	0,
+	{
+		44100.0,
+		AF_SAMPFMT_TWOSCOMP,
+		16,
+		_AF_BYTEORDER_NATIVE,
+		{ SLOPE_INT16, 0, MIN_INT16, MAX_INT16 },
+		2,
+		AF_COMPRESSION_NONE,
+		NULL
+	},
+	false,		/* rateSet */
+	false,		/* sampleFormatSet */
+	false,		/* sampleWidthSet */
+	false,		/* byteOrderSet */
+	false,		/* channelCountSet */
+	false,		/* compressionSet */
+	false,		/* aesDataSet */
+	false,		/* markersSet */
+	false,		/* dataOffsetSet */
+	false,		/* frameCountSet */
+
+	4,		/* markerCount */
+	NULL,		/* markers */
+	0,		/* dataOffset */
+	0		/* frameCount */
+};
+
+TrackSetup *_af_tracksetup_new (int trackCount)
+{
+	TrackSetup	*tracks;
+
+	if (trackCount == 0)
+		return NULL;
+
+	tracks = (TrackSetup *) _af_calloc(trackCount, sizeof (TrackSetup));
+	if (tracks == NULL)
+		return NULL;
+
+	for (int i=0; i<trackCount; i++)
+	{
+		tracks[i] = _af_default_tracksetup;
+
+		tracks[i].id = AF_DEFAULT_TRACK + i;
+
+		/* XXXmpruett deal with compression */
+
+		_af_set_sample_format(&tracks[i].f, tracks[i].f.sampleFormat,
+			tracks[i].f.sampleWidth);
+
+		if (tracks[i].markerCount == 0)
+			tracks[i].markers = NULL;
+		else
+		{
+			tracks[i].markers = (MarkerSetup *) _af_calloc(tracks[i].markerCount,
+				sizeof (MarkerSetup));
+
+			if (tracks[i].markers == NULL)
+				return NULL;
+
+			for (int j=0; j<tracks[i].markerCount; j++)
+			{
+				tracks[i].markers[j].id = j+1;
+
+				tracks[i].markers[j].name = _af_strdup("");
+				if (tracks[i].markers[j].name == NULL)
+					return NULL;
+
+				tracks[i].markers[j].comment = _af_strdup("");
+				if (tracks[i].markers[j].comment == NULL)
+					return NULL;
+			}
+		}
+	}
+
+	return tracks;
+}
+
+InstrumentSetup *_af_instsetup_new (int instrumentCount)
+{
+	InstrumentSetup	*instruments;
+
+	if (instrumentCount == 0)
+		return NULL;
+	instruments = (InstrumentSetup *) _af_calloc(instrumentCount, sizeof (InstrumentSetup));
+	if (instruments == NULL)
+		return NULL;
+
+	for (int i=0; i<instrumentCount; i++)
+	{
+		instruments[i] = _af_default_instrumentsetup;
+		instruments[i].id = AF_DEFAULT_INST + i;
+		if (instruments[i].loopCount == 0)
+			instruments[i].loops = NULL;
+		else
+		{
+			instruments[i].loops = (LoopSetup *) _af_calloc(instruments[i].loopCount, sizeof (LoopSetup));
+			if (instruments[i].loops == NULL)
+				return NULL;
+
+			for (int j=0; j<instruments[i].loopCount; j++)
+				instruments[i].loops[j].id = j+1;
+		}
+	}
+
+	return instruments;
+}
+
+AFfilesetup afNewFileSetup (void)
+{
+	AFfilesetup	setup;
+
+	setup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
+	if (setup == NULL) return AF_NULL_FILESETUP;
+
+	*setup = _af_default_file_setup;
+
+	setup->tracks = _af_tracksetup_new(setup->trackCount);
+
+	setup->instruments = _af_instsetup_new(setup->instrumentCount);
+
+	if (setup->miscellaneousCount == 0)
+		setup->miscellaneous = NULL;
+	else
+	{
+		setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(setup->miscellaneousCount,
+			sizeof (MiscellaneousSetup));
+		for (int i=0; i<setup->miscellaneousCount; i++)
+		{
+			setup->miscellaneous[i].id = i+1;
+			setup->miscellaneous[i].type = 0;
+			setup->miscellaneous[i].size = 0;
+		}
+	}
+
+	return setup;
+}
+
+/*
+	Free the specified track's markers and their subfields.
+*/
+void _af_setup_free_markers (AFfilesetup setup, int trackno)
+{
+	if (setup->tracks[trackno].markerCount != 0)
+	{
+		for (int i=0; i<setup->tracks[trackno].markerCount; i++)
+		{
+			free(setup->tracks[trackno].markers[i].name);
+			free(setup->tracks[trackno].markers[i].comment);
+		}
+
+		free(setup->tracks[trackno].markers);
+	}
+
+	setup->tracks[trackno].markers = NULL;
+	setup->tracks[trackno].markerCount = 0;
+}
+
+/*
+	Free the specified setup's tracks and their subfields.
+*/
+void _af_setup_free_tracks (AFfilesetup setup)
+{
+	if (setup->tracks)
+	{
+		for (int i=0; i<setup->trackCount; i++)
+		{
+			_af_setup_free_markers(setup, i);
+		}
+
+		free(setup->tracks);
+	}
+
+	setup->tracks = NULL;
+	setup->trackCount = 0;
+}
+
+/*
+	Free the specified setup's instruments and their subfields.
+*/
+void _af_setup_free_instruments (AFfilesetup setup)
+{
+	if (setup->instruments)
+	{
+		for (int i=0; i < setup->instrumentCount; i++)
+			setup->instruments[i].freeLoops();
+
+		free(setup->instruments);
+	}
+
+	setup->instruments = NULL;
+	setup->instrumentCount = 0;
+}
+
+void afFreeFileSetup (AFfilesetup setup)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	_af_setup_free_tracks(setup);
+
+	_af_setup_free_instruments(setup);
+
+	if (setup->miscellaneousCount)
+	{
+		free(setup->miscellaneous);
+		setup->miscellaneous = NULL;
+		setup->miscellaneousCount = 0;
+	}
+
+	memset(setup, 0, sizeof (_AFfilesetup));
+	free(setup);
+}
+
+void afInitFileFormat (AFfilesetup setup, int filefmt)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	if (filefmt < 0 || filefmt >= _AF_NUM_UNITS)
+	{
+		_af_error(AF_BAD_FILEFMT, "unrecognized file format %d",
+			filefmt);
+		return;
+	}
+
+	if (!_af_units[filefmt].implemented)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED,
+			"%s format not currently supported",
+			_af_units[filefmt].name);
+		return;
+	}
+
+	setup->fileFormat = filefmt;
+}
+
+void afInitChannels (AFfilesetup setup, int trackid, int channels)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (channels < 1)
+	{
+		_af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
+			channels);
+		return;
+	}
+
+	track->f.channelCount = channels;
+	track->channelCountSet = true;
+}
+
+void afInitSampleFormat (AFfilesetup setup, int trackid, int sampfmt, int sampwidth)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	_af_set_sample_format(&track->f, sampfmt, sampwidth);
+
+	track->sampleFormatSet = true;
+	track->sampleWidthSet = true;
+}
+
+void afInitByteOrder (AFfilesetup setup, int trackid, int byteorder)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (byteorder != AF_BYTEORDER_BIGENDIAN &&
+		byteorder != AF_BYTEORDER_LITTLEENDIAN)
+	{
+		_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
+		return;
+	}
+
+	track->f.byteOrder = byteorder;
+	track->byteOrderSet = true;
+}
+
+void afInitRate (AFfilesetup setup, int trackid, double rate)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (rate <= 0.0)
+	{
+		_af_error(AF_BAD_RATE, "invalid sample rate %.30g", rate);
+		return;
+	}
+
+	track->f.sampleRate = rate;
+	track->rateSet = true;
+}
+
+/*
+	track data: data offset within the file (initialized for raw reading only)
+*/
+void afInitDataOffset (AFfilesetup setup, int trackid, AFfileoffset offset)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (offset < 0)
+	{
+		_af_error(AF_BAD_DATAOFFSET, "invalid data offset %jd",
+			static_cast<intmax_t>(offset));
+		return;
+	}
+
+	track->dataOffset = offset;
+	track->dataOffsetSet = true;
+}
+
+/*
+	track data: data offset within the file (initialized for raw reading only)
+*/
+void afInitFrameCount (AFfilesetup setup, int trackid, AFfileoffset count)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (count < 0)
+	{
+		_af_error(AF_BAD_FRAMECNT, "invalid frame count %jd",
+			static_cast<intmax_t>(count));
+		return;
+	}
+
+	track->frameCount = count;
+	track->frameCountSet = true;
+}
+
+#define alloccopy(type, n, var, copyfrom) \
+{ \
+	if (n == 0) \
+		var = NULL; \
+	else \
+	{ \
+		if ((var = (type *) _af_calloc(n, sizeof (type))) == NULL) \
+			goto fail; \
+		memcpy((var), (copyfrom), (n) * sizeof (type)); \
+	} \
+}
+
+AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
+	const _AFfilesetup *defaultSetup, bool copyMarks)
+{
+	AFfilesetup newsetup;
+	int instrumentCount, miscellaneousCount, trackCount;
+
+	newsetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
+	if (newsetup == AF_NULL_FILESETUP)
+		return AF_NULL_FILESETUP;
+
+	*newsetup = *defaultSetup;
+
+	newsetup->tracks = NULL;
+	newsetup->instruments = NULL;
+	newsetup->miscellaneous = NULL;
+
+	/* Copy tracks. */
+	trackCount = setup->trackSet ? setup->trackCount :
+		newsetup->trackSet ? newsetup->trackCount : 0;
+	alloccopy(TrackSetup, trackCount, newsetup->tracks, setup->tracks);
+	newsetup->trackCount = trackCount;
+
+	/* Copy instruments. */
+	instrumentCount = setup->instrumentSet ? setup->instrumentCount :
+		newsetup->instrumentSet ? newsetup->instrumentCount : 0;
+	alloccopy(InstrumentSetup, instrumentCount, newsetup->instruments, setup->instruments);
+	newsetup->instrumentCount = instrumentCount;
+
+	/* Copy miscellaneous information. */
+	miscellaneousCount = setup->miscellaneousSet ? setup->miscellaneousCount :
+		newsetup->miscellaneousSet ? newsetup->miscellaneousCount : 0;
+	alloccopy(MiscellaneousSetup, miscellaneousCount, newsetup->miscellaneous, setup->miscellaneous);
+	newsetup->miscellaneousCount = miscellaneousCount;
+
+	for (int i=0; i<setup->trackCount; i++)
+	{
+		TrackSetup	*track = &newsetup->tracks[i];
+
+		/* XXXmpruett set compression information */
+
+		if (!setup->tracks[i].markersSet && !copyMarks)
+		{
+			track->markers = NULL;
+			track->markerCount = 0;
+			continue;
+		}
+
+		alloccopy(MarkerSetup, setup->tracks[i].markerCount,
+			track->markers, setup->tracks[i].markers);
+		track->markerCount = setup->tracks[i].markerCount;
+
+		for (int j=0; j<setup->tracks[i].markerCount; j++)
+		{
+			track->markers[j].name =
+				_af_strdup(setup->tracks[i].markers[j].name);
+			if (track->markers[j].name == NULL)
+				goto fail;
+
+			track->markers[j].comment =
+				_af_strdup(setup->tracks[i].markers[j].comment);
+			if (track->markers[j].comment == NULL)
+				goto fail;
+		}
+	}
+
+	for (int i=0; i<newsetup->instrumentCount; i++)
+	{
+		InstrumentSetup	*instrument = &newsetup->instruments[i];
+		alloccopy(LoopSetup, setup->instruments[i].loopCount,
+			instrument->loops, setup->instruments[i].loops);
+	}
+
+	return newsetup;
+
+	fail:
+		if (newsetup->miscellaneous)
+			free(newsetup->miscellaneous);
+		if (newsetup->instruments)
+			free(newsetup->instruments);
+		if (newsetup->tracks)
+			free(newsetup->tracks);
+		if (newsetup)
+			free(newsetup);
+
+	return AF_NULL_FILESETUP;
+}
+
+TrackSetup *_AFfilesetup::getTrack(int trackID)
+{
+	for (int i=0; i<trackCount; i++)
+	{
+		if (tracks[i].id == trackID)
+			return &tracks[i];
+	}
+
+	_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);
+	return NULL;
+}
+
+InstrumentSetup *_AFfilesetup::getInstrument(int instrumentID)
+{
+	for (int i=0; i < instrumentCount; i++)
+		if (instruments[i].id == instrumentID)
+			return &instruments[i];
+
+	_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
+	return NULL;
+}
+
+MiscellaneousSetup *_AFfilesetup::getMiscellaneous(int miscellaneousID)
+{
+	for (int i=0; i<miscellaneousCount; i++)
+	{
+		if (miscellaneous[i].id == miscellaneousID)
+			return &miscellaneous[i];
+	}
+
+	_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);
+
+	return NULL;
+}
diff --git a/libaudiofile/Setup.h b/libaudiofile/Setup.h
new file mode 100644
index 0000000..272f47b
--- /dev/null
+++ b/libaudiofile/Setup.h
@@ -0,0 +1,61 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef SETUP_H
+#define SETUP_H
+
+#include "afinternal.h"
+
+struct InstrumentSetup;
+struct MiscellaneousSetup;
+struct TrackSetup;
+
+struct _AFfilesetup
+{
+	int	valid;
+
+	int fileFormat;
+
+	bool trackSet, instrumentSet, miscellaneousSet;
+
+	int trackCount;
+	TrackSetup *tracks;
+
+	int instrumentCount;
+	InstrumentSetup *instruments;
+
+	int miscellaneousCount;
+	MiscellaneousSetup *miscellaneous;
+
+	TrackSetup *getTrack(int trackID = AF_DEFAULT_TRACK);
+	InstrumentSetup *getInstrument(int instrumentID);
+	MiscellaneousSetup *getMiscellaneous(int miscellaneousID);
+};
+
+void _af_setup_free_markers (AFfilesetup setup, int trackno);
+void _af_setup_free_tracks (AFfilesetup setup);
+void _af_setup_free_instruments (AFfilesetup setup);
+
+AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
+	const _AFfilesetup *defaultSetup, bool copyMarks);
+
+InstrumentSetup *_af_instsetup_new (int count);
+
+#endif
diff --git a/libaudiofile/Shared.h b/libaudiofile/Shared.h
new file mode 100644
index 0000000..d3469e9
--- /dev/null
+++ b/libaudiofile/Shared.h
@@ -0,0 +1,109 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SHARED_H
+#define SHARED_H
+
+template <typename T>
+class Shared
+{
+public:
+	Shared() : m_refCount(0)
+	{
+	}
+	void retain() { m_refCount++; }
+	void release() { if (--m_refCount == 0) delete static_cast<T *>(this); }
+
+protected:
+	~Shared()
+	{
+	}
+
+private:
+	int m_refCount;
+
+	Shared(const Shared &);
+	Shared &operator =(const Shared &);
+};
+
+template <typename T>
+class SharedPtr
+{
+public:
+	SharedPtr() : m_ptr(0)
+	{
+	}
+	SharedPtr(T *ptr) : m_ptr(ptr)
+	{
+		if (m_ptr) m_ptr->retain();
+	}
+	SharedPtr(const SharedPtr &p) : m_ptr(p.m_ptr)
+	{
+		if (m_ptr) m_ptr->retain();
+	}
+	~SharedPtr()
+	{
+		if (T *p = m_ptr) p->release();
+	}
+
+	SharedPtr &operator =(T *ptr)
+	{
+		if (m_ptr != ptr)
+		{
+			if (ptr) ptr->retain();
+			if (m_ptr) m_ptr->release();
+			m_ptr = ptr;
+		}
+		return *this;
+	}
+	SharedPtr &operator =(const SharedPtr &p)
+	{
+		if (m_ptr != p.m_ptr)
+		{
+			if (p.m_ptr) p.m_ptr->retain();
+			if (m_ptr) m_ptr->release();
+			m_ptr = p.m_ptr;
+		}
+		return *this;
+	}
+
+	T *get() const { return m_ptr; }
+	T &operator *() const { return *m_ptr; }
+	T *operator ->() const { return m_ptr; }
+
+	typedef T *SharedPtr::*UnspecifiedBoolType;
+	operator UnspecifiedBoolType() const { return m_ptr ? &SharedPtr::m_ptr : 0; }
+
+	bool operator !() const { return !m_ptr; }
+
+private:
+	T *m_ptr;
+};
+
+#endif
diff --git a/libaudiofile/Tag.h b/libaudiofile/Tag.h
new file mode 100644
index 0000000..9ae8cf0
--- /dev/null
+++ b/libaudiofile/Tag.h
@@ -0,0 +1,57 @@
+/*
+	Audio File Library
+	Copyright (C) 2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef TAG_H
+#define TAG_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <string>
+
+class Tag
+{
+public:
+	Tag() : m_value(0) { }
+	Tag(uint32_t value) : m_value(value) { }
+	Tag(const char *s)
+	{
+		assert(strlen(s) == 4);
+		memcpy(&m_value, s, 4);
+	}
+
+	uint32_t value() const { return m_value; }
+
+	bool operator==(const Tag &t) const { return m_value == t.m_value; }
+	bool operator!=(const Tag &t) const { return m_value != t.m_value; }
+
+	std::string name() const
+	{
+		char s[5];
+		memcpy(s, &m_value, 4);
+		s[4] = '\0';
+		return std::string(s);
+	}
+
+private:
+	uint32_t m_value;
+};
+
+#endif
diff --git a/libaudiofile/Track.cpp b/libaudiofile/Track.cpp
new file mode 100644
index 0000000..440207e
--- /dev/null
+++ b/libaudiofile/Track.cpp
@@ -0,0 +1,177 @@
+/*
+	Audio File Library
+	Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	track.c
+
+	This file contains functions for dealing with tracks within an
+	audio file.
+*/
+
+#include "config.h"
+#include "Track.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+#include "Marker.h"
+#include "PacketTable.h"
+#include "modules/Module.h"
+#include "modules/ModuleState.h"
+
+void afInitTrackIDs (AFfilesetup file, const int *trackids, int trackCount)
+{
+	assert(file);
+	assert(trackids);
+	assert(trackCount == 1);
+	assert(trackids[0] == AF_DEFAULT_TRACK);
+}
+
+int afGetTrackIDs (AFfilehandle file, int *trackids)
+{
+	assert(file);
+
+	if (trackids != NULL)
+		trackids[0] = AF_DEFAULT_TRACK;
+
+	return 1;
+}
+
+Track::Track()
+{
+	id = AF_DEFAULT_TRACK;
+
+	f.compressionParams = NULL;
+	v.compressionParams = NULL;
+
+	channelMatrix = NULL;
+
+	markerCount = 0;
+	markers = NULL;
+
+	hasAESData = false;
+	memset(aesData, 0, 24);
+
+	totalfframes = 0;
+	nextfframe = 0;
+	frames2ignore = 0;
+	fpos_first_frame = 0;
+	fpos_next_frame = 0;
+	fpos_after_data = 0;
+	totalvframes = 0;
+	nextvframe = 0;
+	data_size = 0;
+}
+
+Track::~Track()
+{
+	if (f.compressionParams)
+	{
+		AUpvfree(f.compressionParams);
+		f.compressionParams = NULL;
+	}
+
+	if (v.compressionParams)
+	{
+		AUpvfree(v.compressionParams);
+		v.compressionParams = NULL;
+	}
+
+	free(channelMatrix);
+	channelMatrix = NULL;
+
+	if (markers)
+	{
+		for (int j=0; j<markerCount; j++)
+		{
+			free(markers[j].name);
+			markers[j].name = NULL;
+			free(markers[j].comment);
+			markers[j].comment = NULL;
+		}
+
+		free(markers);
+		markers = NULL;
+	}
+}
+
+void Track::print()
+{
+	fprintf(stderr, "totalfframes %jd\n", (intmax_t) totalfframes);
+	fprintf(stderr, "nextfframe %jd\n", (intmax_t) nextfframe);
+	fprintf(stderr, "frames2ignore %jd\n", (intmax_t) frames2ignore);
+	fprintf(stderr, "fpos_first_frame %jd\n", (intmax_t) fpos_first_frame);
+	fprintf(stderr, "fpos_next_frame %jd\n", (intmax_t) fpos_next_frame);
+	fprintf(stderr, "fpos_after_data %jd\n", (intmax_t) fpos_after_data);
+	fprintf(stderr, "totalvframes %jd\n", (intmax_t) totalvframes);
+	fprintf(stderr, "nextvframe %jd\n", (intmax_t) nextvframe);
+	fprintf(stderr, "data_size %jd\n", (intmax_t) data_size);
+}
+
+Marker *Track::getMarker(int markerID)
+{
+	for (int i=0; i<markerCount; i++)
+		if (markers[i].id == markerID)
+			return &markers[i];
+
+	_af_error(AF_BAD_MARKID, "no marker with id %d found in track %d",
+		markerID, id);
+
+	return NULL;
+}
+
+status Track::copyMarkers(TrackSetup *setup)
+{
+	if ((markerCount = setup->markerCount) == 0)
+	{
+		markers = NULL;
+		return AF_SUCCEED;
+	}
+
+	markers = _af_marker_new(markerCount);
+	if (!markers)
+		return AF_FAIL;
+
+	for (int i=0; i<markerCount; i++)
+	{
+		markers[i].id = setup->markers[i].id;
+		markers[i].name = _af_strdup(setup->markers[i].name);
+		if (!markers[i].name)
+			return AF_FAIL;
+
+		markers[i].comment = _af_strdup(setup->markers[i].comment);
+		if (!markers[i].comment)
+			return AF_FAIL;
+		markers[i].position = 0;
+	}
+
+	return AF_SUCCEED;
+}
+
+void Track::computeTotalFileFrames()
+{
+	if (f.bytesPerPacket && f.framesPerPacket)
+		totalfframes = (data_size / f.bytesPerPacket) * f.framesPerPacket;
+}
diff --git a/libaudiofile/Track.h b/libaudiofile/Track.h
new file mode 100644
index 0000000..5c83a48
--- /dev/null
+++ b/libaudiofile/Track.h
@@ -0,0 +1,98 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	track.h
+*/
+
+#ifndef TRACK_H
+#define TRACK_H
+
+#include "AudioFormat.h"
+#include "Shared.h"
+#include "afinternal.h"
+
+class ModuleState;
+class PacketTable;
+struct Marker;
+struct MarkerSetup;
+
+struct TrackSetup
+{
+	int id;
+
+	AudioFormat f;
+
+	bool rateSet, sampleFormatSet, sampleWidthSet, byteOrderSet,
+		channelCountSet, compressionSet, aesDataSet, markersSet,
+		dataOffsetSet, frameCountSet;
+
+	int markerCount;
+	MarkerSetup *markers;
+
+	AFfileoffset dataOffset;
+	AFframecount frameCount;
+};
+
+struct Track
+{
+	Track();
+	~Track();
+
+	int	id;	/* usually AF_DEFAULT_TRACKID */
+
+	AudioFormat f, v;	/* file and virtual audio formats */
+
+	SharedPtr<PacketTable> m_packetTable;
+
+	double *channelMatrix;
+
+	int markerCount;
+	Marker *markers;
+
+	bool hasAESData;	/* Is AES nonaudio data present? */
+	unsigned char aesData[24];	/* AES nonaudio data */
+
+	AFframecount totalfframes;		/* frameCount */
+	AFframecount nextfframe;		/* currentFrame */
+	AFframecount frames2ignore;
+	AFfileoffset fpos_first_frame;	/* dataStart */
+	AFfileoffset fpos_next_frame;
+	AFfileoffset fpos_after_data;
+	AFframecount totalvframes;
+	AFframecount nextvframe;
+	AFfileoffset data_size;		/* trackBytes */
+
+	SharedPtr<ModuleState> ms;
+
+	double taper, dynamic_range;
+	bool ratecvt_filter_params_set;
+
+	bool filemodhappy;
+
+	void print();
+
+	Marker *getMarker(int markerID);
+	status copyMarkers(TrackSetup *setup);
+
+	void computeTotalFileFrames();
+};
+
+#endif
diff --git a/libaudiofile/UUID.cpp b/libaudiofile/UUID.cpp
new file mode 100644
index 0000000..5e4d8ba
--- /dev/null
+++ b/libaudiofile/UUID.cpp
@@ -0,0 +1,67 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "UUID.h"
+
+#include <stdio.h>
+#include <string.h>
+
+bool UUID::operator==(const UUID &u) const
+{
+	return !memcmp(data, u.data, 16);
+}
+
+bool UUID::operator!=(const UUID &u) const
+{
+	return memcmp(data, u.data, 16) != 0;
+}
+
+std::string UUID::name() const
+{
+	char s[37];
+	uint32_t u1 =
+		(data[0] << 24) |
+		(data[1] << 16) |
+		(data[2] << 8) |
+		data[3];
+	uint16_t u2 =
+		(data[4] << 8) |
+		data[5];
+	uint16_t u3 =
+		(data[6] << 8) |
+		data[7];
+	uint16_t u4 =
+		(data[8] << 8) |
+		data[9];
+	snprintf(s, 37, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+		u1, u2, u3, u4,
+		data[10], data[11], data[12], data[13], data[14], data[15]);
+	return std::string(s);
+}
diff --git a/libaudiofile/UUID.h b/libaudiofile/UUID.h
new file mode 100644
index 0000000..76f724f
--- /dev/null
+++ b/libaudiofile/UUID.h
@@ -0,0 +1,45 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UUID_H
+#define UUID_H
+
+#include <stdint.h>
+#include <string>
+
+struct UUID
+{
+	uint8_t data[16];
+
+	bool operator==(const UUID &) const;
+	bool operator!=(const UUID &) const;
+	std::string name() const;
+};
+
+#endif
diff --git a/libaudiofile/VOC.cpp b/libaudiofile/VOC.cpp
new file mode 100644
index 0000000..70e7696
--- /dev/null
+++ b/libaudiofile/VOC.cpp
@@ -0,0 +1,446 @@
+/*
+	Audio File Library
+	Copyright (C) 2011-2013, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "VOC.h"
+
+#include "File.h"
+#include "Track.h"
+#include "Setup.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include <string.h>
+#include <assert.h>
+
+const int _af_voc_compression_types[_AF_VOC_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW
+};
+
+static const int kVOCMagicLength = 20;
+static const char kVOCMagic[kVOCMagicLength + 1] = "Creative Voice File\x1a";
+
+enum
+{
+	kVOCTerminator = 0,
+	kVOCSoundData = 1,
+	kVOCSoundDataContinuation = 2,
+	kVOCSilence = 3,
+	kVOCMarker = 4,
+	kVOCText = 5,
+	kVOCRepeatStart = 6,
+	kVOCRepeatEnd = 7,
+	kVOCExtendedInfo = 8,
+	kVOCSoundDataNew = 9
+};
+
+enum
+{
+	kVOCFormatU8 = 0,
+	kVOCFormatCreativeADPCM4_8 = 1,
+	kVOCFormatCreativeADPCM3_8 = 2,
+	kVOCFormatCreativeADPCM2_8 = 3,
+	kVOCFormatS16 = 4,
+	kVOCFormatAlaw = 6,
+	kVOCFormatUlaw = 7,
+	kVOCFormatCreativeADPCM4_16 = 0x200,
+};
+
+static const _AFfilesetup vocDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	// valid
+	AF_FILE_VOC,			// fileFormat
+	true,	// trackSet
+	true,	// instrumentSet
+	true,	// miscellaneousSet
+	1,		// trackCount
+	NULL,	// tracks
+	1,		// instrumentCount
+	NULL,	// instruments
+	0,		// miscellaneousCount
+	NULL	// miscellaneous
+};
+
+VOCFile::VOCFile() :
+	m_soundDataOffset(-1)
+{
+	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
+}
+
+bool VOCFile::recognize(File *f)
+{
+	f->seek(0, File::SeekFromBeginning);
+	char buffer[kVOCMagicLength];
+	if (f->read(buffer, kVOCMagicLength) != kVOCMagicLength)
+		return false;
+	if (memcmp(buffer, kVOCMagic, kVOCMagicLength) != 0)
+		return false;
+	return true;
+}
+
+AFfilesetup VOCFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "VOC file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->sampleFormatSet)
+	{
+		if (!track->f.isInteger())
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"VOC format supports only integer audio data");
+			return AF_NULL_FILESETUP;
+		}
+
+		if ((track->f.isSigned() && track->f.sampleWidth != 16) ||
+			(track->f.isUnsigned() && track->f.sampleWidth != 8))
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"VOC format supports only 16-bit signed or 8-bit unsigned data");
+			return AF_NULL_FILESETUP;
+		}
+	}
+	else
+		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+			track->f.sampleWidth);
+
+	if (track->f.isUncompressed() &&
+		track->byteOrderSet &&
+		track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
+		track->f.isByteOrderSignificant())
+	{
+		_af_error(AF_BAD_BYTEORDER, "VOC supports only little-endian data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+	{
+		_af_error(AF_BAD_COMPTYPE,
+			"compression format %d not supported in VOC file",
+			track->f.compressionType);
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->markersSet && track->markerCount)
+	{
+		_af_error(AF_BAD_NUMMARKS, "VOC does not support markers");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "VOC does not support AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet && setup->instrumentCount)
+	{
+		_af_error(AF_BAD_FILESETUP, "VOC does not support instruments");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->miscellaneousSet && setup->miscellaneousCount)
+	{
+		_af_error(AF_BAD_FILESETUP, "VOC does not support miscellaneous data");
+		return AF_NULL_FILESETUP;
+	}
+
+	return _af_filesetup_copy(setup, &vocDefaultFileSetup, true);
+}
+
+status VOCFile::readInit(AFfilesetup)
+{
+	m_fh->seek(20, File::SeekFromBeginning);
+
+	uint16_t dataOffset, version, checksum;
+	readU16(&dataOffset);
+	readU16(&version);
+	readU16(&checksum);
+
+	Track *track = allocateTrack();
+
+	bool hasExtendedInfo = false;
+	bool foundSoundData = false;
+
+	off_t position = m_fh->tell();
+	off_t fileLength = m_fh->length();
+	while (position < fileLength)
+	{
+		uint32_t blockHeader;
+		if (!readU32(&blockHeader))
+			break;
+		uint8_t blockType = blockHeader & 0xff;
+		uint32_t blockSize = blockHeader >> 8;
+
+		if (blockType == kVOCSoundData)
+		{
+			if (foundSoundData)
+			{
+				_af_error(AF_BAD_HEADER, "VOC file contains multiple sound data blocks");
+				return AF_FAIL;
+			}
+
+			foundSoundData = true;
+
+			uint8_t frequencyDivisor, codec;
+			readU8(&frequencyDivisor);
+			readU8(&codec);
+
+			if (!hasExtendedInfo)
+			{
+				track->f.channelCount = 1;
+				track->f.sampleRate = 1000000 / (256 - frequencyDivisor);
+			}
+
+			track->f.compressionType = AF_COMPRESSION_NONE;
+			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+			track->f.framesPerPacket = 1;
+
+			if (codec == kVOCFormatU8)
+			{
+				_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, 8);
+				track->f.computeBytesPerPacketPCM();
+			}
+			else if (codec == kVOCFormatCreativeADPCM4_8 ||
+				codec == kVOCFormatCreativeADPCM3_8 ||
+				codec == kVOCFormatCreativeADPCM2_8)
+			{
+				_af_error(AF_BAD_NOT_IMPLEMENTED,
+					"Creative ADPCM compression is not currently suppported");
+				return AF_FAIL;
+			}
+			else
+			{
+				_af_error(AF_BAD_CODEC_TYPE,
+					"VOC file contains unrecognized codec type %d", codec);
+				return AF_FAIL;
+			}
+
+			track->fpos_first_frame = m_fh->tell();
+			track->data_size = m_fh->length() - 1 - track->fpos_first_frame;
+			track->computeTotalFileFrames();
+		}
+		else if (blockType == kVOCExtendedInfo)
+		{
+			if (foundSoundData)
+			{
+				_af_error(AF_BAD_HEADER, "VOC extended information found after sound data");
+				return AF_FAIL;
+			}
+
+			hasExtendedInfo = true;
+
+			uint16_t frequencyDivisor;
+			uint8_t bitsPerSample;
+			uint8_t isStereo;
+			readU16(&frequencyDivisor);
+			readU8(&bitsPerSample);
+			readU8(&isStereo);
+
+			track->f.sampleWidth = bitsPerSample;
+			track->f.channelCount = isStereo ? 2 : 1;
+			uint32_t frequencyDividend = 256000000 / (isStereo ? 2 : 1);
+			track->f.sampleRate = frequencyDividend / (65536 - frequencyDivisor);
+		}
+		else if (blockType == kVOCSoundDataNew)
+		{
+			if (foundSoundData)
+			{
+				_af_error(AF_BAD_HEADER, "VOC file contains multiple sound data blocks");
+				return AF_FAIL;
+			}
+
+			foundSoundData = true;
+
+			uint32_t sampleRate;
+			uint8_t bitsPerSample, channels;
+			uint16_t format;
+			uint32_t pad;
+			readU32(&sampleRate);
+			readU8(&bitsPerSample);
+			readU8(&channels);
+			readU16(&format);
+			readU32(&pad);
+
+			if (!channels)
+			{
+				_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
+				return AF_FAIL;
+			}
+
+			track->fpos_first_frame = m_fh->tell();
+			track->data_size = blockSize - 12;
+
+			track->f.compressionType = AF_COMPRESSION_NONE;
+			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+			track->f.sampleRate = sampleRate;
+			track->f.channelCount = channels;
+			track->f.framesPerPacket = 1;
+
+			if (format == kVOCFormatU8)
+			{
+				_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, 8);
+				track->f.computeBytesPerPacketPCM();
+			}
+			else if (format == kVOCFormatS16)
+			{
+				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+				track->f.computeBytesPerPacketPCM();
+			}
+			else if (format == kVOCFormatAlaw)
+			{
+				track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+				track->f.bytesPerPacket = track->f.channelCount;
+				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+			}
+			else if (format == kVOCFormatUlaw)
+			{
+				track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+				track->f.bytesPerPacket = track->f.channelCount;
+				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+			}
+			else if (format == kVOCFormatCreativeADPCM4_8 ||
+				format == kVOCFormatCreativeADPCM3_8 ||
+				format == kVOCFormatCreativeADPCM2_8 ||
+				format == kVOCFormatCreativeADPCM4_16)
+			{
+				_af_error(AF_BAD_NOT_IMPLEMENTED,
+					"Creative ADPCM compression is not currently supported");
+				return AF_FAIL;
+			}
+			else
+			{
+				_af_error(AF_BAD_CODEC_TYPE,
+					"VOC file contains unrecognized codec type %d", format);
+				return AF_FAIL;
+			}
+
+			track->computeTotalFileFrames();
+		}
+
+		position += 4 + blockSize;
+
+		m_fh->seek(position, File::SeekFromBeginning);
+	}
+
+	return AF_SUCCEED;
+}
+
+status VOCFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	m_fh->write(kVOCMagic, kVOCMagicLength);
+	uint16_t dataOffset = 0x001a;
+	uint16_t version = 0x0114;
+	uint16_t checksum = 0x1234 + ~version;
+	writeU16(&dataOffset);
+	writeU16(&version);
+	writeU16(&checksum);
+
+	return writeSoundData();
+}
+
+status VOCFile::update()
+{
+	if (writeSoundData() == AF_FAIL || writeTerminator() == AF_FAIL)
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status VOCFile::writeSoundData()
+{
+	if (m_soundDataOffset == -1)
+		m_soundDataOffset = m_fh->tell();
+	else
+		m_fh->seek(m_soundDataOffset, File::SeekFromBeginning);
+
+	Track *track = getTrack();
+
+	assert((track->f.isSigned() && track->f.sampleWidth == 16) ||
+		(track->f.isUnsigned() && track->f.sampleWidth == 8));
+
+	uint8_t blockType = kVOCSoundDataNew;
+	uint32_t blockSize = 12 + track->data_size;
+	uint32_t blockHeader = blockSize << 8 | blockType;
+	if (!writeU32(&blockHeader))
+		return AF_FAIL;
+
+	uint32_t sampleRate = track->f.sampleRate;
+	uint8_t bitsPerSample = track->f.sampleWidth;
+	uint8_t channels = track->f.channelCount;
+	uint16_t format;
+	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+	{
+		format = kVOCFormatUlaw;
+		bitsPerSample = 8;
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+	{
+		format = kVOCFormatAlaw;
+		bitsPerSample = 8;
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_NONE)
+	{
+		if (track->f.isUnsigned())
+			format = kVOCFormatU8;
+		else
+			format = kVOCFormatS16;
+	}
+	uint32_t pad = 0;
+	if (!writeU32(&sampleRate) ||
+		!writeU8(&bitsPerSample) ||
+		!writeU8(&channels) ||
+		!writeU16(&format) ||
+		!writeU32(&pad))
+		return AF_FAIL;
+
+	if (track->fpos_first_frame == 0)
+		track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
+
+status VOCFile::writeTerminator()
+{
+	Track *track = getTrack();
+	m_fh->seek(track->fpos_first_frame + track->data_size, File::SeekFromBeginning);
+	uint8_t terminator = kVOCTerminator;
+	if (!writeU8(&terminator))
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
diff --git a/libaudiofile/VOC.h b/libaudiofile/VOC.h
new file mode 100644
index 0000000..18554f1
--- /dev/null
+++ b/libaudiofile/VOC.h
@@ -0,0 +1,49 @@
+/*
+	Audio File Library
+	Copyright (C) 2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef VOC_H
+#define VOC_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+
+#define _AF_VOC_NUM_COMPTYPES 2
+extern const int _af_voc_compression_types[_AF_VOC_NUM_COMPTYPES];
+
+class VOCFile : public _AFfilehandle
+{
+public:
+	VOCFile();
+
+	static bool recognize(File *);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+	status update() OVERRIDE;
+
+private:
+	status writeSoundData();
+	status writeTerminator();
+
+	AFfileoffset m_soundDataOffset;
+};
+
+#endif
diff --git a/libaudiofile/WAVE.cpp b/libaudiofile/WAVE.cpp
new file mode 100644
index 0000000..61f9541
--- /dev/null
+++ b/libaudiofile/WAVE.cpp
@@ -0,0 +1,1610 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2003-2004, 2010-2013, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000-2002, Silicon Graphics, Inc.
+	Copyright (C) 2002-2003, Davy Durham
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	WAVE.cpp
+
+	This file contains code for reading and writing RIFF WAVE format
+	sound files.
+*/
+
+#include "config.h"
+#include "WAVE.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "Instrument.h"
+#include "Marker.h"
+#include "Setup.h"
+#include "Tag.h"
+#include "Track.h"
+#include "UUID.h"
+#include "byteorder.h"
+#include "util.h"
+
+/* These constants are from RFC 2361. */
+enum
+{
+	WAVE_FORMAT_UNKNOWN = 0x0000,	/* Microsoft Unknown Wave Format */
+	WAVE_FORMAT_PCM = 0x0001,	/* Microsoft PCM Format */
+	WAVE_FORMAT_ADPCM = 0x0002,	/* Microsoft ADPCM Format */
+	WAVE_FORMAT_IEEE_FLOAT = 0x0003,	/* IEEE Float */
+	WAVE_FORMAT_VSELP = 0x0004,	/* Compaq Computer's VSELP */
+	WAVE_FORMAT_IBM_CVSD = 0x0005,	/* IBM CVSD */
+	WAVE_FORMAT_ALAW = 0x0006,	/* Microsoft ALAW */
+	WAVE_FORMAT_MULAW = 0x0007,	/* Microsoft MULAW */
+	WAVE_FORMAT_OKI_ADPCM = 0x0010,	/* OKI ADPCM */
+	WAVE_FORMAT_DVI_ADPCM = 0x0011,	/* Intel's DVI ADPCM */
+	WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012,	/* Videologic's MediaSpace ADPCM */
+	WAVE_FORMAT_SIERRA_ADPCM = 0x0013,	/* Sierra ADPCM */
+	WAVE_FORMAT_G723_ADPCM = 0x0014,	/* G.723 ADPCM */
+	WAVE_FORMAT_DIGISTD = 0x0015,	/* DSP Solutions' DIGISTD */
+	WAVE_FORMAT_DIGIFIX = 0x0016,	/* DSP Solutions' DIGIFIX */
+	WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017,	/* Dialogic OKI ADPCM */
+	WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018,	/* MediaVision ADPCM */
+	WAVE_FORMAT_CU_CODEC = 0x0019,	/* HP CU */
+	WAVE_FORMAT_YAMAHA_ADPCM = 0x0020,	/* Yamaha ADPCM */
+	WAVE_FORMAT_SONARC = 0x0021,	/* Speech Compression's Sonarc */
+	WAVE_FORMAT_DSP_TRUESPEECH = 0x0022,	/* DSP Group's True Speech */
+	WAVE_FORMAT_ECHOSC1 = 0x0023,	/* Echo Speech's EchoSC1 */
+	WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024,	/* Audiofile AF36 */
+	WAVE_FORMAT_APTX = 0x0025,	/* APTX */
+	WAVE_FORMAT_DOLBY_AC2 = 0x0030,	/* Dolby AC2 */
+	WAVE_FORMAT_GSM610 = 0x0031,	/* GSM610 */
+	WAVE_FORMAT_MSNAUDIO = 0x0032,	/* MSNAudio */
+	WAVE_FORMAT_ANTEX_ADPCME = 0x0033,	/* Antex ADPCME */
+
+	WAVE_FORMAT_MPEG = 0x0050,		/* MPEG */
+	WAVE_FORMAT_MPEGLAYER3 = 0x0055,	/* MPEG layer 3 */
+	WAVE_FORMAT_LUCENT_G723 = 0x0059,	/* Lucent G.723 */
+	WAVE_FORMAT_G726_ADPCM = 0x0064,	/* G.726 ADPCM */
+	WAVE_FORMAT_G722_ADPCM = 0x0065,	/* G.722 ADPCM */
+
+	IBM_FORMAT_MULAW = 0x0101,
+	IBM_FORMAT_ALAW = 0x0102,
+	IBM_FORMAT_ADPCM = 0x0103,
+
+	WAVE_FORMAT_CREATIVE_ADPCM = 0x0200,
+
+	WAVE_FORMAT_EXTENSIBLE = 0xfffe
+};
+
+const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES] =
+{
+	AF_COMPRESSION_G711_ULAW,
+	AF_COMPRESSION_G711_ALAW,
+	AF_COMPRESSION_IMA,
+	AF_COMPRESSION_MS_ADPCM
+};
+
+const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS] =
+{
+	{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
+	{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
+	{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
+	{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
+	{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
+	{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
+	{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} }
+};
+
+static const _AFfilesetup waveDefaultFileSetup =
+{
+	_AF_VALID_FILESETUP,	/* valid */
+	AF_FILE_WAVE,		/* fileFormat */
+	true,			/* trackSet */
+	true,			/* instrumentSet */
+	true,			/* miscellaneousSet  */
+	1,			/* trackCount */
+	NULL,			/* tracks */
+	0,			/* instrumentCount */
+	NULL,			/* instruments */
+	0,			/* miscellaneousCount */
+	NULL			/* miscellaneous */
+};
+
+static const UUID _af_wave_guid_pcm =
+{{
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+}};
+static const UUID _af_wave_guid_ieee_float =
+{{
+	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+}};
+static const UUID _af_wave_guid_ulaw =
+{{
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+}};
+static const UUID _af_wave_guid_alaw =
+{{
+	0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+}};
+
+WAVEFile::WAVEFile()
+{
+	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
+
+	m_factOffset = 0;
+	m_miscellaneousOffset = 0;
+	m_markOffset = 0;
+	m_dataSizeOffset = 0;
+
+	m_msadpcmNumCoefficients = 0;
+}
+
+status WAVEFile::parseFrameCount(const Tag &id, uint32_t size)
+{
+	Track *track = getTrack();
+
+	uint32_t totalFrames;
+	readU32(&totalFrames);
+
+	track->totalfframes = totalFrames;
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parseFormat(const Tag &id, uint32_t size)
+{
+	Track *track = getTrack();
+
+	uint16_t formatTag;
+	readU16(&formatTag);
+	uint16_t channelCount;
+	readU16(&channelCount);
+	uint32_t sampleRate;
+	readU32(&sampleRate);
+	uint32_t averageBytesPerSecond;
+	readU32(&averageBytesPerSecond);
+	uint16_t blockAlign;
+	readU16(&blockAlign);
+
+	if (!channelCount)
+	{
+		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
+		return AF_FAIL;
+	}
+
+	track->f.channelCount = channelCount;
+	track->f.sampleRate = sampleRate;
+	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+
+	/* Default to uncompressed audio data. */
+	track->f.compressionType = AF_COMPRESSION_NONE;
+	track->f.framesPerPacket = 1;
+
+	switch (formatTag)
+	{
+		case WAVE_FORMAT_PCM:
+		{
+			uint16_t bitsPerSample;
+			readU16(&bitsPerSample);
+
+			track->f.sampleWidth = bitsPerSample;
+
+			if (bitsPerSample == 0 || bitsPerSample > 32)
+			{
+				_af_error(AF_BAD_WIDTH,
+					"bad sample width of %d bits",
+					bitsPerSample);
+				return AF_FAIL;
+			}
+
+			if (bitsPerSample <= 8)
+				track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+			else
+				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+		}
+		break;
+
+		case WAVE_FORMAT_MULAW:
+		case IBM_FORMAT_MULAW:
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+			track->f.bytesPerPacket = track->f.channelCount;
+			break;
+
+		case WAVE_FORMAT_ALAW:
+		case IBM_FORMAT_ALAW:
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+			track->f.bytesPerPacket = track->f.channelCount;
+			break;
+
+		case WAVE_FORMAT_IEEE_FLOAT:
+		{
+			uint16_t bitsPerSample;
+			readU16(&bitsPerSample);
+
+			if (bitsPerSample == 64)
+			{
+				track->f.sampleWidth = 64;
+				track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+			}
+			else
+			{
+				track->f.sampleWidth = 32;
+				track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+			}
+		}
+		break;
+
+		case WAVE_FORMAT_ADPCM:
+		{
+			uint16_t bitsPerSample, extraByteCount,
+					samplesPerBlock, numCoefficients;
+
+			if (track->f.channelCount != 1 &&
+				track->f.channelCount != 2)
+			{
+				_af_error(AF_BAD_CHANNELS,
+					"WAVE file with MS ADPCM compression "
+					"must have 1 or 2 channels");
+			}
+
+			readU16(&bitsPerSample);
+			readU16(&extraByteCount);
+			readU16(&samplesPerBlock);
+			readU16(&numCoefficients);
+
+			/* numCoefficients should be at least 7. */
+			assert(numCoefficients >= 7 && numCoefficients <= 255);
+			if (numCoefficients < 7 || numCoefficients > 255)
+			{
+				_af_error(AF_BAD_HEADER,
+						"Bad number of coefficients");
+				return AF_FAIL;
+			}
+
+			m_msadpcmNumCoefficients = numCoefficients;
+
+			for (int i=0; i<m_msadpcmNumCoefficients; i++)
+			{
+				readS16(&m_msadpcmCoefficients[i][0]);
+				readS16(&m_msadpcmCoefficients[i][1]);
+			}
+
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.compressionType = AF_COMPRESSION_MS_ADPCM;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+			track->f.framesPerPacket = samplesPerBlock;
+			track->f.bytesPerPacket = blockAlign;
+
+			// Create the parameter list.
+			AUpvlist pv = AUpvnew(2);
+			AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
+			AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+			long l = m_msadpcmNumCoefficients;
+			AUpvsetval(pv, 0, &l);
+
+			AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
+			AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
+			void *v = m_msadpcmCoefficients;
+			AUpvsetval(pv, 1, &v);
+
+			track->f.compressionParams = pv;
+		}
+		break;
+
+		case WAVE_FORMAT_DVI_ADPCM:
+		{
+			uint16_t bitsPerSample, extraByteCount, samplesPerBlock;
+
+			readU16(&bitsPerSample);
+			readU16(&extraByteCount);
+			readU16(&samplesPerBlock);
+
+			if (bitsPerSample != 4)
+			{
+				_af_error(AF_BAD_NOT_IMPLEMENTED,
+					"IMA ADPCM compression supports only 4 bits per sample");
+			}
+
+			int bytesPerBlock = (samplesPerBlock + 14) / 8 * 4 * channelCount;
+			if (bytesPerBlock > blockAlign || (samplesPerBlock % 8) != 1)
+			{
+				_af_error(AF_BAD_CODEC_CONFIG,
+					"Invalid samples per block for IMA ADPCM compression");
+			}
+
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			track->f.compressionType = AF_COMPRESSION_IMA;
+			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+			initIMACompressionParams();
+
+			track->f.framesPerPacket = samplesPerBlock;
+			track->f.bytesPerPacket = blockAlign;
+		}
+		break;
+
+		case WAVE_FORMAT_EXTENSIBLE:
+		{
+			uint16_t bitsPerSample;
+			readU16(&bitsPerSample);
+			uint16_t extraByteCount;
+			readU16(&extraByteCount);
+			uint16_t reserved;
+			readU16(&reserved);
+			uint32_t channelMask;
+			readU32(&channelMask);
+			UUID subformat;
+			readUUID(&subformat);
+			if (subformat == _af_wave_guid_pcm)
+			{
+				track->f.sampleWidth = bitsPerSample;
+
+				if (bitsPerSample == 0 || bitsPerSample > 32)
+				{
+					_af_error(AF_BAD_WIDTH,
+						"bad sample width of %d bits",
+						bitsPerSample);
+					return AF_FAIL;
+				}
+
+				// Use valid bits per sample if bytes per sample is the same.
+				if (reserved <= bitsPerSample &&
+					(reserved + 7) / 8 == (bitsPerSample + 7) / 8)
+					track->f.sampleWidth = reserved;
+
+				if (bitsPerSample <= 8)
+					track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+				else
+					track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			}
+			else if (subformat == _af_wave_guid_ieee_float)
+			{
+				if (bitsPerSample == 64)
+				{
+					track->f.sampleWidth = 64;
+					track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+				}
+				else
+				{
+					track->f.sampleWidth = 32;
+					track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+				}
+			}
+			else if (subformat == _af_wave_guid_alaw ||
+				subformat == _af_wave_guid_ulaw)
+			{
+				track->f.compressionType = subformat == _af_wave_guid_alaw ?
+					AF_COMPRESSION_G711_ALAW : AF_COMPRESSION_G711_ULAW;
+				track->f.sampleWidth = 16;
+				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+				track->f.bytesPerPacket = channelCount;
+			}
+			else
+			{
+				_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE extensible data format %s is not currently supported", subformat.name().c_str());
+				return AF_FAIL;
+			}
+		}
+		break;
+
+		case WAVE_FORMAT_YAMAHA_ADPCM:
+		case WAVE_FORMAT_OKI_ADPCM:
+		case WAVE_FORMAT_CREATIVE_ADPCM:
+		case IBM_FORMAT_ADPCM:
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE ADPCM data format 0x%x is not currently supported", formatTag);
+			return AF_FAIL;
+			break;
+
+		case WAVE_FORMAT_MPEG:
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG data format is not supported");
+			return AF_FAIL;
+			break;
+
+		case WAVE_FORMAT_MPEGLAYER3:
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG layer 3 data format is not supported");
+			return AF_FAIL;
+			break;
+
+		default:
+			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE file data format 0x%x not currently supported != 0xfffe ? %d, != EXTENSIBLE? %d", formatTag, formatTag != 0xfffe, formatTag != WAVE_FORMAT_EXTENSIBLE);
+			return AF_FAIL;
+			break;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.computeBytesPerPacketPCM();
+
+	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parseData(const Tag &id, uint32_t size)
+{
+	Track *track = getTrack();
+
+	track->fpos_first_frame = m_fh->tell();
+	track->data_size = size;
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parsePlayList(const Tag &id, uint32_t size)
+{
+	uint32_t segmentCount;
+	readU32(&segmentCount);
+
+	if (segmentCount == 0)
+	{
+		m_instrumentCount = 0;
+		m_instruments = NULL;
+		return AF_SUCCEED;
+	}
+
+	for (unsigned segment=0; segment<segmentCount; segment++)
+	{
+		uint32_t startMarkID, loopLength, loopCount;
+
+		readU32(&startMarkID);
+		readU32(&loopLength);
+		readU32(&loopCount);
+	}
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parseCues(const Tag &id, uint32_t size)
+{
+	Track *track = getTrack();
+
+	uint32_t markerCount;
+	readU32(&markerCount);
+	track->markerCount = markerCount;
+
+	if (markerCount == 0)
+	{
+		track->markers = NULL;
+		return AF_SUCCEED;
+	}
+
+	if ((track->markers = _af_marker_new(markerCount)) == NULL)
+		return AF_FAIL;
+
+	for (unsigned i=0; i<markerCount; i++)
+	{
+		uint32_t id, position, chunkid;
+		uint32_t chunkByteOffset, blockByteOffset;
+		uint32_t sampleFrameOffset;
+		Marker *marker = &track->markers[i];
+
+		readU32(&id);
+		readU32(&position);
+		readU32(&chunkid);
+		readU32(&chunkByteOffset);
+		readU32(&blockByteOffset);
+
+		/*
+			sampleFrameOffset represents the position of
+			the mark in units of frames.
+		*/
+		readU32(&sampleFrameOffset);
+
+		marker->id = id;
+		marker->position = sampleFrameOffset;
+		marker->name = _af_strdup("");
+		marker->comment = _af_strdup("");
+	}
+
+	return AF_SUCCEED;
+}
+
+/* Parse an adtl sub-chunk within a LIST chunk. */
+status WAVEFile::parseADTLSubChunk(const Tag &id, uint32_t size)
+{
+	Track *track = getTrack();
+
+	AFfileoffset endPos = m_fh->tell() + size;
+
+	while (m_fh->tell() < endPos)
+	{
+		Tag chunkID;
+		uint32_t chunkSize;
+
+		readTag(&chunkID);
+		readU32(&chunkSize);
+
+		if (chunkID == "labl" || chunkID == "note")
+		{
+			uint32_t id;
+			long length=chunkSize-4;
+			char *p = (char *) _af_malloc(length);
+
+			readU32(&id);
+			m_fh->read(p, length);
+
+			Marker *marker = track->getMarker(id);
+
+			if (marker)
+			{
+				if (chunkID == "labl")
+				{
+					free(marker->name);
+					marker->name = p;
+				}
+				else if (chunkID == "note")
+				{
+					free(marker->comment);
+					marker->comment = p;
+				}
+				else
+					free(p);
+			}
+			else
+				free(p);
+
+			/*
+				If chunkSize is odd, skip an extra byte
+				at the end of the chunk.
+			*/
+			if ((chunkSize % 2) != 0)
+				m_fh->seek(1, File::SeekFromCurrent);
+		}
+		else
+		{
+			/* If chunkSize is odd, skip an extra byte. */
+			m_fh->seek(chunkSize + (chunkSize % 2), File::SeekFromCurrent);
+		}
+	}
+	return AF_SUCCEED;
+}
+
+/* Parse an INFO sub-chunk within a LIST chunk. */
+status WAVEFile::parseINFOSubChunk(const Tag &id, uint32_t size)
+{
+	AFfileoffset endPos = m_fh->tell() + size;
+
+	while (m_fh->tell() < endPos)
+	{
+		int misctype = AF_MISC_UNRECOGNIZED;
+		Tag miscid;
+		uint32_t miscsize;
+
+		readTag(&miscid);
+		readU32(&miscsize);
+
+		if (miscid == "IART")
+			misctype = AF_MISC_AUTH;
+		else if (miscid == "INAM")
+			misctype = AF_MISC_NAME;
+		else if (miscid == "ICOP")
+			misctype = AF_MISC_COPY;
+		else if (miscid == "ICMT")
+			misctype = AF_MISC_ICMT;
+		else if (miscid == "ICRD")
+			misctype = AF_MISC_ICRD;
+		else if (miscid == "ISFT")
+			misctype = AF_MISC_ISFT;
+
+		if (misctype != AF_MISC_UNRECOGNIZED)
+		{
+			char *string = (char *) _af_malloc(miscsize);
+
+			m_fh->read(string, miscsize);
+
+			m_miscellaneousCount++;
+			m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous, sizeof (Miscellaneous) * m_miscellaneousCount);
+
+			m_miscellaneous[m_miscellaneousCount-1].id = m_miscellaneousCount;
+			m_miscellaneous[m_miscellaneousCount-1].type = misctype;
+			m_miscellaneous[m_miscellaneousCount-1].size = miscsize;
+			m_miscellaneous[m_miscellaneousCount-1].position = 0;
+			m_miscellaneous[m_miscellaneousCount-1].buffer = string;
+		}
+		else
+		{
+			m_fh->seek(miscsize, File::SeekFromCurrent);
+		}
+
+		/* Make the current position an even number of bytes.  */
+		if (miscsize % 2 != 0)
+			m_fh->seek(1, File::SeekFromCurrent);
+	}
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parseList(const Tag &id, uint32_t size)
+{
+	Tag typeID;
+	readTag(&typeID);
+	size-=4;
+
+	if (typeID == "adtl")
+	{
+		/* Handle adtl sub-chunks. */
+		return parseADTLSubChunk(typeID, size);
+	}
+	else if (typeID == "INFO")
+	{
+		/* Handle INFO sub-chunks. */
+		return parseINFOSubChunk(typeID, size);
+	}
+	else
+	{
+		/* Skip unhandled sub-chunks. */
+		m_fh->seek(size, File::SeekFromCurrent);
+		return AF_SUCCEED;
+	}
+	return AF_SUCCEED;
+}
+
+status WAVEFile::parseInstrument(const Tag &id, uint32_t size)
+{
+	uint8_t baseNote;
+	int8_t detune, gain;
+	uint8_t lowNote, highNote, lowVelocity, highVelocity;
+	uint8_t padByte;
+
+	readU8(&baseNote);
+	readS8(&detune);
+	readS8(&gain);
+	readU8(&lowNote);
+	readU8(&highNote);
+	readU8(&lowVelocity);
+	readU8(&highVelocity);
+	readU8(&padByte);
+
+	return AF_SUCCEED;
+}
+
+bool WAVEFile::recognize(File *fh)
+{
+	uint8_t buffer[8];
+
+	fh->seek(0, File::SeekFromBeginning);
+
+	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "RIFF", 4) != 0)
+		return false;
+	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "WAVE", 4) != 0)
+		return false;
+
+	return true;
+}
+
+status WAVEFile::readInit(AFfilesetup setup)
+{
+	Tag type, formtype;
+	uint32_t size;
+	uint32_t index = 0;
+
+	bool hasFormat = false;
+	bool hasData = false;
+	bool hasFrameCount = false;
+
+	Track *track = allocateTrack();
+
+	m_fh->seek(0, File::SeekFromBeginning);
+
+	readTag(&type);
+	readU32(&size);
+	readTag(&formtype);
+
+	assert(type == "RIFF");
+	assert(formtype == "WAVE");
+
+	/* Include the offset of the form type. */
+	index += 4;
+
+	while (index < size)
+	{
+		Tag chunkid;
+		uint32_t chunksize = 0;
+		status result;
+
+		readTag(&chunkid);
+		readU32(&chunksize);
+
+		if (chunkid == "fmt ")
+		{
+			result = parseFormat(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+
+			hasFormat = true;
+		}
+		else if (chunkid == "data")
+		{
+			/* The format chunk must precede the data chunk. */
+			if (!hasFormat)
+			{
+				_af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
+				return AF_FAIL;
+			}
+
+			result = parseData(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+
+			hasData = true;
+		}
+		else if (chunkid == "inst")
+		{
+			result = parseInstrument(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkid == "fact")
+		{
+			hasFrameCount = true;
+			result = parseFrameCount(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkid == "cue ")
+		{
+			result = parseCues(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkid == "LIST" || chunkid == "list")
+		{
+			result = parseList(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkid == "INST")
+		{
+			result = parseInstrument(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+		else if (chunkid == "plst")
+		{
+			result = parsePlayList(chunkid, chunksize);
+			if (result == AF_FAIL)
+				return AF_FAIL;
+		}
+
+		index += chunksize + 8;
+
+		/* All chunks must be aligned on an even number of bytes */
+		if ((index % 2) != 0)
+			index++;
+
+		m_fh->seek(index + 8, File::SeekFromBeginning);
+	}
+
+	/* The format chunk and the data chunk are required. */
+	if (!hasFormat || !hasData)
+	{
+		return AF_FAIL;
+	}
+
+	/*
+		At this point we know that the file has a format chunk and a
+		data chunk, so we can assume that track->f and track->data_size
+		have been initialized.
+	*/
+	if (!hasFrameCount)
+	{
+		if (track->f.bytesPerPacket && track->f.framesPerPacket)
+		{
+			track->computeTotalFileFrames();
+		}
+		else
+		{
+			_af_error(AF_BAD_HEADER, "Frame count required but not found");
+			return AF_FAIL;
+		}
+	}
+
+	return AF_SUCCEED;
+}
+
+AFfilesetup WAVEFile::completeSetup(AFfilesetup setup)
+{
+	if (setup->trackSet && setup->trackCount != 1)
+	{
+		_af_error(AF_BAD_NUMTRACKS, "WAVE file must have 1 track");
+		return AF_NULL_FILESETUP;
+	}
+
+	TrackSetup *track = setup->getTrack();
+	if (!track)
+		return AF_NULL_FILESETUP;
+
+	if (track->f.isCompressed())
+	{
+		if (!track->sampleFormatSet)
+			_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
+		else
+			_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+	}
+	else if (track->sampleFormatSet)
+	{
+		switch (track->f.sampleFormat)
+		{
+			case AF_SAMPFMT_FLOAT:
+				if (track->sampleWidthSet &&
+					track->f.sampleWidth != 32)
+				{
+					_af_error(AF_BAD_WIDTH,
+						"Warning: invalid sample width for floating-point WAVE file: %d (must be 32 bits)\n",
+						track->f.sampleWidth);
+					_af_set_sample_format(&track->f, AF_SAMPFMT_FLOAT, 32);
+				}
+				break;
+
+			case AF_SAMPFMT_DOUBLE:
+				if (track->sampleWidthSet &&
+					track->f.sampleWidth != 64)
+				{
+					_af_error(AF_BAD_WIDTH,
+						"Warning: invalid sample width for double-precision floating-point WAVE file: %d (must be 64 bits)\n",
+						track->f.sampleWidth);
+					_af_set_sample_format(&track->f, AF_SAMPFMT_DOUBLE, 64);
+				}
+				break;
+
+			case AF_SAMPFMT_UNSIGNED:
+				if (track->sampleWidthSet)
+				{
+					if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+					{
+						_af_error(AF_BAD_WIDTH, "invalid sample width for WAVE file: %d (must be 1-32 bits)\n", track->f.sampleWidth);
+						return AF_NULL_FILESETUP;
+					}
+					if (track->f.sampleWidth > 8)
+					{
+						_af_error(AF_BAD_SAMPFMT, "WAVE integer data of more than 8 bits must be two's complement signed");
+						_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
+					}
+				}
+				else
+				/*
+					If the sample width is not set but the user requests
+					unsigned data, set the width to 8 bits.
+				*/
+					_af_set_sample_format(&track->f, track->f.sampleFormat, 8);
+				break;
+
+			case AF_SAMPFMT_TWOSCOMP:
+				if (track->sampleWidthSet)
+				{
+					if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+					{
+						_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
+						return AF_NULL_FILESETUP;
+					}
+					else if (track->f.sampleWidth <= 8)
+					{
+						_af_error(AF_BAD_SAMPFMT, "Warning: WAVE format integer data of 1-8 bits must be unsigned; setting sample format to unsigned");
+						_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, track->f.sampleWidth);
+					}
+				}
+				else
+				/*
+					If no sample width was specified, we default to 16 bits
+					for signed integer data.
+				*/
+					_af_set_sample_format(&track->f, track->f.sampleFormat, 16);
+				break;
+		}
+	}
+	/*
+		Otherwise set the sample format depending on the sample
+		width or set completely to default.
+	*/
+	else
+	{
+		if (!track->sampleWidthSet)
+		{
+			track->f.sampleWidth = 16;
+			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+		}
+		else
+		{
+			if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+			{
+				_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
+				return AF_NULL_FILESETUP;
+			}
+			else if (track->f.sampleWidth > 8)
+				/* Here track->f.sampleWidth is in {1..32}. */
+				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+			else
+				/* Here track->f.sampleWidth is in {1..8}. */
+				track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+		}
+	}
+
+	if (track->f.compressionType != AF_COMPRESSION_NONE &&
+		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
+		track->f.compressionType != AF_COMPRESSION_IMA &&
+		track->f.compressionType != AF_COMPRESSION_MS_ADPCM)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in WAVE format");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed() &&
+		track->byteOrderSet &&
+		track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
+		track->f.isByteOrderSignificant())
+	{
+		_af_error(AF_BAD_BYTEORDER, "WAVE format only supports little-endian data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (track->f.isUncompressed())
+		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+
+	if (track->aesDataSet)
+	{
+		_af_error(AF_BAD_FILESETUP, "WAVE files cannot have AES data");
+		return AF_NULL_FILESETUP;
+	}
+
+	if (setup->instrumentSet)
+	{
+		if (setup->instrumentCount > 1)
+		{
+			_af_error(AF_BAD_NUMINSTS, "WAVE files can have 0 or 1 instrument");
+			return AF_NULL_FILESETUP;
+		}
+		else if (setup->instrumentCount == 1)
+		{
+			if (setup->instruments[0].loopSet &&
+				setup->instruments[0].loopCount > 0 &&
+				(!track->markersSet || track->markerCount == 0))
+			{
+				_af_error(AF_BAD_NUMMARKS, "WAVE files with loops must contain at least 1 marker");
+				return AF_NULL_FILESETUP;
+			}
+		}
+	}
+
+	/* Make sure the miscellaneous data is of an acceptable type. */
+	if (setup->miscellaneousSet)
+	{
+		for (int i=0; i<setup->miscellaneousCount; i++)
+		{
+			switch (setup->miscellaneous[i].type)
+			{
+				case AF_MISC_COPY:
+				case AF_MISC_AUTH:
+				case AF_MISC_NAME:
+				case AF_MISC_ICRD:
+				case AF_MISC_ISFT:
+				case AF_MISC_ICMT:
+					break;
+				default:
+					_af_error(AF_BAD_MISCTYPE, "illegal miscellaneous type [%d] for WAVE file", setup->miscellaneous[i].type);
+					return AF_NULL_FILESETUP;
+			}
+		}
+	}
+
+	/*
+		Allocate an AFfilesetup and make all the unset fields correct.
+	*/
+	AFfilesetup	newsetup = _af_filesetup_copy(setup, &waveDefaultFileSetup, false);
+
+	/* Make sure we do not copy loops if they are not specified in setup. */
+	if (setup->instrumentSet && setup->instrumentCount > 0 &&
+		setup->instruments[0].loopSet)
+	{
+		free(newsetup->instruments[0].loops);
+		newsetup->instruments[0].loopCount = 0;
+	}
+
+	return newsetup;
+}
+
+bool WAVEFile::isInstrumentParameterValid(AUpvlist list, int i)
+{
+	int param, type;
+
+	AUpvgetparam(list, i, &param);
+	AUpvgetvaltype(list, i, &type);
+	if (type != AU_PVTYPE_LONG)
+		return false;
+
+	long lval;
+	AUpvgetval(list, i, &lval);
+
+	switch (param)
+	{
+		case AF_INST_MIDI_BASENOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_NUMCENTS_DETUNE:
+			return ((lval >= -50) && (lval <= 50));
+
+		case AF_INST_MIDI_LOVELOCITY:
+			return ((lval >= 1) && (lval <= 127));
+
+		case AF_INST_MIDI_HIVELOCITY:
+			return ((lval >= 1) && (lval <= 127));
+
+		case AF_INST_MIDI_LONOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_MIDI_HINOTE:
+			return ((lval >= 0) && (lval <= 127));
+
+		case AF_INST_NUMDBS_GAIN:
+			return true;
+
+		default:
+			return false;
+	}
+
+	return true;
+}
+
+status WAVEFile::writeFormat()
+{
+	uint16_t	formatTag, channelCount;
+	uint32_t	sampleRate, averageBytesPerSecond;
+	uint16_t	blockAlign;
+	uint32_t	chunkSize;
+	uint16_t	bitsPerSample;
+
+	Track *track = getTrack();
+
+	m_fh->write("fmt ", 4);
+
+	switch (track->f.compressionType)
+	{
+		case AF_COMPRESSION_NONE:
+			chunkSize = 16;
+			if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
+				track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+			{
+				formatTag = WAVE_FORMAT_IEEE_FLOAT;
+			}
+			else if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
+				track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+			{
+				formatTag = WAVE_FORMAT_PCM;
+			}
+			else
+			{
+				_af_error(AF_BAD_COMPTYPE, "bad sample format");
+				return AF_FAIL;
+			}
+
+			blockAlign = _af_format_frame_size(&track->f, false);
+			bitsPerSample = 8 * _af_format_sample_size(&track->f, false);
+			break;
+
+		/*
+			G.711 compression uses eight bits per sample.
+		*/
+		case AF_COMPRESSION_G711_ULAW:
+			chunkSize = 18;
+			formatTag = IBM_FORMAT_MULAW;
+			blockAlign = track->f.channelCount;
+			bitsPerSample = 8;
+			break;
+
+		case AF_COMPRESSION_G711_ALAW:
+			chunkSize = 18;
+			formatTag = IBM_FORMAT_ALAW;
+			blockAlign = track->f.channelCount;
+			bitsPerSample = 8;
+			break;
+
+		case AF_COMPRESSION_IMA:
+			chunkSize = 20;
+			formatTag = WAVE_FORMAT_DVI_ADPCM;
+			blockAlign = track->f.bytesPerPacket;
+			bitsPerSample = 4;
+			break;
+
+		case AF_COMPRESSION_MS_ADPCM:
+			chunkSize = 50;
+			formatTag = WAVE_FORMAT_ADPCM;
+			blockAlign = track->f.bytesPerPacket;
+			bitsPerSample = 4;
+			break;
+
+		default:
+			_af_error(AF_BAD_COMPTYPE, "bad compression type");
+			return AF_FAIL;
+	}
+
+	writeU32(&chunkSize);
+	writeU16(&formatTag);
+
+	channelCount = track->f.channelCount;
+	writeU16(&channelCount);
+
+	sampleRate = track->f.sampleRate;
+	writeU32(&sampleRate);
+
+	averageBytesPerSecond =
+		track->f.sampleRate * _af_format_frame_size(&track->f, false);
+	if (track->f.compressionType == AF_COMPRESSION_IMA ||
+		track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
+		averageBytesPerSecond = track->f.sampleRate * track->f.bytesPerPacket /
+			track->f.framesPerPacket;
+	writeU32(&averageBytesPerSecond);
+
+	writeU16(&blockAlign);
+
+	writeU16(&bitsPerSample);
+
+	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
+		track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+	{
+		uint16_t zero = 0;
+		writeU16(&zero);
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_IMA)
+	{
+		uint16_t extraByteCount = 2;
+		writeU16(&extraByteCount);
+		uint16_t samplesPerBlock = track->f.framesPerPacket;
+		writeU16(&samplesPerBlock);
+	}
+	else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
+	{
+		uint16_t extraByteCount = 2 + 2 + m_msadpcmNumCoefficients * 4;
+		writeU16(&extraByteCount);
+		uint16_t samplesPerBlock = track->f.framesPerPacket;
+		writeU16(&samplesPerBlock);
+
+		uint16_t numCoefficients = m_msadpcmNumCoefficients;
+		writeU16(&numCoefficients);
+
+		for (int i=0; i<m_msadpcmNumCoefficients; i++)
+		{
+			writeS16(&m_msadpcmCoefficients[i][0]);
+			writeS16(&m_msadpcmCoefficients[i][1]);
+		}
+	}
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::writeFrameCount()
+{
+	uint32_t factSize = 4;
+	uint32_t totalFrameCount;
+
+	Track *track = getTrack();
+
+	/* Omit the fact chunk only for uncompressed integer audio formats. */
+	if (track->f.compressionType == AF_COMPRESSION_NONE &&
+		(track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
+		track->f.sampleFormat == AF_SAMPFMT_UNSIGNED))
+		return AF_SUCCEED;
+
+	/*
+		If the offset for the fact chunk hasn't been set yet,
+		set it to the file's current position.
+	*/
+	if (m_factOffset == 0)
+		m_factOffset = m_fh->tell();
+	else
+		m_fh->seek(m_factOffset, File::SeekFromBeginning);
+
+	m_fh->write("fact", 4);
+	writeU32(&factSize);
+
+	totalFrameCount = track->totalfframes;
+	writeU32(&totalFrameCount);
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::writeData()
+{
+	Track *track = getTrack();
+
+	m_fh->write("data", 4);
+	m_dataSizeOffset = m_fh->tell();
+
+	uint32_t chunkSize = track->data_size;
+
+	writeU32(&chunkSize);
+	track->fpos_first_frame = m_fh->tell();
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::update()
+{
+	Track *track = getTrack();
+
+	if (track->fpos_first_frame != 0)
+	{
+		uint32_t dataLength, fileLength;
+
+		// Update the frame count chunk if present.
+		writeFrameCount();
+
+		// Update the length of the data chunk.
+		m_fh->seek(m_dataSizeOffset, File::SeekFromBeginning);
+		dataLength = (uint32_t) track->data_size;
+		writeU32(&dataLength);
+
+		// Update the length of the RIFF chunk.
+		fileLength = (uint32_t) m_fh->length();
+		fileLength -= 8;
+
+		m_fh->seek(4, File::SeekFromBeginning);
+		writeU32(&fileLength);
+	}
+
+	/*
+		Write the actual data that was set after initializing
+		the miscellaneous IDs.	The size of the data will be
+		unchanged.
+	*/
+	writeMiscellaneous();
+
+	// Write the new positions; the size of the data will be unchanged.
+	writeCues();
+
+	return AF_SUCCEED;
+}
+
+/* Convert an Audio File Library miscellaneous type to a WAVE type. */
+static bool misc_type_to_wave (int misctype, Tag *miscid)
+{
+	if (misctype == AF_MISC_AUTH)
+		*miscid = "IART";
+	else if (misctype == AF_MISC_NAME)
+		*miscid = "INAM";
+	else if (misctype == AF_MISC_COPY)
+		*miscid = "ICOP";
+	else if (misctype == AF_MISC_ICMT)
+		*miscid = "ICMT";
+	else if (misctype == AF_MISC_ICRD)
+		*miscid = "ICRD";
+	else if (misctype == AF_MISC_ISFT)
+		*miscid = "ISFT";
+	else
+		return false;
+
+	return true;
+}
+
+status WAVEFile::writeMiscellaneous()
+{
+	if (m_miscellaneousCount != 0)
+	{
+		uint32_t	miscellaneousBytes;
+		uint32_t 	chunkSize;
+
+		/* Start at 12 to account for 'LIST', size, and 'INFO'. */
+		miscellaneousBytes = 12;
+
+		/* Then calculate the size of the whole INFO chunk. */
+		for (int i=0; i<m_miscellaneousCount; i++)
+		{
+			Tag miscid;
+
+			// Skip miscellaneous data of an unsupported type.
+			if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
+				continue;
+
+			// Account for miscellaneous type and size.
+			miscellaneousBytes += 8;
+			miscellaneousBytes += m_miscellaneous[i].size;
+
+			// Add a pad byte if necessary.
+			if (m_miscellaneous[i].size % 2 != 0)
+				miscellaneousBytes++;
+
+			assert(miscellaneousBytes % 2 == 0);
+		}
+
+		if (m_miscellaneousOffset == 0)
+			m_miscellaneousOffset = m_fh->tell();
+		else
+			m_fh->seek(m_miscellaneousOffset, File::SeekFromBeginning);
+
+		/*
+			Write the data.  On the first call to this
+			function (from _af_wave_write_init), the
+			data won't be available, fh->seek is used to
+			reserve space until the data has been provided.
+			On subseuent calls to this function (from
+			_af_wave_update), the data will really be written.
+		*/
+
+		/* Write 'LIST'. */
+		m_fh->write("LIST", 4);
+
+		/* Write the size of the following chunk. */
+		chunkSize = miscellaneousBytes-8;
+		writeU32(&chunkSize);
+
+		/* Write 'INFO'. */
+		m_fh->write("INFO", 4);
+
+		/* Write each miscellaneous chunk. */
+		for (int i=0; i<m_miscellaneousCount; i++)
+		{
+			uint32_t miscsize = m_miscellaneous[i].size;
+			Tag miscid;
+
+			// Skip miscellaneous data of an unsupported type.
+			if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
+				continue;
+
+			writeTag(&miscid);
+			writeU32(&miscsize);
+			if (m_miscellaneous[i].buffer != NULL)
+			{
+				uint8_t	zero = 0;
+
+				m_fh->write(m_miscellaneous[i].buffer, m_miscellaneous[i].size);
+
+				// Pad if necessary.
+				if ((m_miscellaneous[i].size%2) != 0)
+					writeU8(&zero);
+			}
+			else
+			{
+				int	size;
+				size = m_miscellaneous[i].size;
+
+				// Pad if necessary.
+				if ((size % 2) != 0)
+					size++;
+				m_fh->seek(size, File::SeekFromCurrent);
+			}
+		}
+	}
+
+	return AF_SUCCEED;
+}
+
+status WAVEFile::writeCues()
+{
+	Track *track = getTrack();
+
+	if (!track->markerCount)
+		return AF_SUCCEED;
+
+	if (m_markOffset == 0)
+		m_markOffset = m_fh->tell();
+	else
+		m_fh->seek(m_markOffset, File::SeekFromBeginning);
+
+	Tag cue("cue ");
+	writeTag(&cue);
+
+	/*
+		The cue chunk consists of 4 bytes for the number of cue points
+		followed by 24 bytes for each cue point record.
+	*/
+	uint32_t cueChunkSize = 4 + track->markerCount * 24;
+	writeU32(&cueChunkSize);
+	uint32_t numCues = track->markerCount;
+	writeU32(&numCues);
+
+	// Write each marker to the file.
+	for (int i=0; i<track->markerCount; i++)
+	{
+		uint32_t identifier = track->markers[i].id;
+		writeU32(&identifier);
+
+		uint32_t position = i;
+		writeU32(&position);
+
+		Tag data("data");
+		writeTag(&data);
+
+		/*
+			For an uncompressed WAVE file which contains only one data chunk,
+			chunkStart and blockStart are zero.
+		*/
+		uint32_t chunkStart = 0;
+		writeU32(&chunkStart);
+
+		uint32_t blockStart = 0;
+		writeU32(&blockStart);
+
+		AFframecount markPosition = track->markers[i].position;
+		uint32_t sampleOffset = markPosition;
+		writeU32(&sampleOffset);
+	}
+
+	// Now write the cue names and comments within a master list chunk.
+	uint32_t listChunkSize = 4;
+	for (int i=0; i<track->markerCount; i++)
+	{
+		const char *name = track->markers[i].name;
+		const char *comment = track->markers[i].comment;
+
+		/*
+			Each 'labl' or 'note' chunk consists of 4 bytes for the chunk ID,
+			4 bytes for the chunk data size, 4 bytes for the cue point ID,
+			and then the length of the label as a null-terminated string.
+
+			In all, this is 12 bytes plus the length of the string, its null
+			termination byte, and a trailing pad byte if the length of the
+			chunk is otherwise odd.
+		*/
+		listChunkSize += 12 + zStringLength(name);
+		listChunkSize += 12 + zStringLength(comment);
+	}
+
+	Tag list("LIST");
+	writeTag(&list);
+	writeU32(&listChunkSize);
+	Tag adtl("adtl");
+	writeTag(&adtl);
+
+	for (int i=0; i<track->markerCount; i++)
+	{
+		uint32_t cuePointID = track->markers[i].id;
+
+		const char *name = track->markers[i].name;
+		uint32_t labelSize = 4 + zStringLength(name);
+		Tag lablTag("labl");
+		writeTag(&lablTag);
+		writeU32(&labelSize);
+		writeU32(&cuePointID);
+		writeZString(name);
+
+		const char *comment = track->markers[i].comment;
+		uint32_t noteSize = 4 + zStringLength(comment);
+		Tag noteTag("note");
+		writeTag(&noteTag);
+		writeU32(&noteSize);
+		writeU32(&cuePointID);
+		writeZString(comment);
+	}
+
+	return AF_SUCCEED;
+}
+
+bool WAVEFile::writeZString(const char *s)
+{
+	ssize_t lengthPlusNull = strlen(s) + 1;
+	if (m_fh->write(s, lengthPlusNull) != lengthPlusNull)
+		return false;
+	if (lengthPlusNull & 1)
+	{
+		uint8_t zero = 0;
+		if (!writeU8(&zero))
+			return false;
+	}
+	return true;
+}
+
+size_t WAVEFile::zStringLength(const char *s)
+{
+	size_t lengthPlusNull = strlen(s) + 1;
+	return lengthPlusNull + (lengthPlusNull & 1);
+}
+
+status WAVEFile::writeInit(AFfilesetup setup)
+{
+	if (initFromSetup(setup) == AF_FAIL)
+		return AF_FAIL;
+
+	initCompressionParams();
+
+	uint32_t zero = 0;
+
+	m_fh->seek(0, File::SeekFromBeginning);
+	m_fh->write("RIFF", 4);
+	m_fh->write(&zero, 4);
+	m_fh->write("WAVE", 4);
+
+	writeMiscellaneous();
+	writeCues();
+	writeFormat();
+	writeFrameCount();
+	writeData();
+
+	return AF_SUCCEED;
+}
+
+bool WAVEFile::readUUID(UUID *u)
+{
+	return m_fh->read(u->data, 16) == 16;
+}
+
+bool WAVEFile::writeUUID(const UUID *u)
+{
+	return m_fh->write(u->data, 16) == 16;
+}
+
+void WAVEFile::initCompressionParams()
+{
+	Track *track = getTrack();
+	if (track->f.compressionType == AF_COMPRESSION_IMA)
+		initIMACompressionParams();
+	else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
+		initMSADPCMCompressionParams();
+}
+
+void WAVEFile::initIMACompressionParams()
+{
+	Track *track = getTrack();
+
+	track->f.framesPerPacket = 505;
+	track->f.bytesPerPacket = 256 * track->f.channelCount;
+
+	AUpvlist pv = AUpvnew(1);
+	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = _AF_IMA_ADPCM_TYPE_WAVE;
+	AUpvsetval(pv, 0, &l);
+
+	track->f.compressionParams = pv;
+}
+
+void WAVEFile::initMSADPCMCompressionParams()
+{
+	const int16_t coefficients[7][2] =
+	{
+		{ 256, 0 },
+		{ 512, -256 },
+		{ 0, 0 },
+		{ 192, 64 },
+		{ 240, 0 },
+		{ 460, -208 },
+		{ 392, -232 }
+	};
+	memcpy(m_msadpcmCoefficients, coefficients, sizeof (int16_t) * 7 * 2);
+	m_msadpcmNumCoefficients = 7;
+
+	Track *track = getTrack();
+
+	track->f.framesPerPacket = 500;
+	track->f.bytesPerPacket = 256 * track->f.channelCount;
+
+	AUpvlist pv = AUpvnew(2);
+	AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
+	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+	long l = m_msadpcmNumCoefficients;
+	AUpvsetval(pv, 0, &l);
+
+	AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
+	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
+	void *v = m_msadpcmCoefficients;
+	AUpvsetval(pv, 1, &v);
+
+	track->f.compressionParams = pv;
+}
diff --git a/libaudiofile/WAVE.h b/libaudiofile/WAVE.h
new file mode 100644
index 0000000..e78d4a2
--- /dev/null
+++ b/libaudiofile/WAVE.h
@@ -0,0 +1,100 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2003, 2010-2012, Michael Pruett <michael@68k.org>
+	Copyright (C) 2002-2003, Davy Durham
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	WAVE.h
+
+	This file contains structures and constants related to the RIFF
+	WAVE sound file format.
+*/
+
+#ifndef WAVE_H
+#define WAVE_H
+
+#include "Compiler.h"
+#include "FileHandle.h"
+#include <stdint.h>
+
+#define _AF_WAVE_NUM_INSTPARAMS 7
+extern const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS];
+#define _AF_WAVE_NUM_COMPTYPES 4
+extern const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES];
+
+struct UUID;
+
+class WAVEFile : public _AFfilehandle
+{
+public:
+	static bool recognize(File *fh);
+	static AFfilesetup completeSetup(AFfilesetup);
+
+	WAVEFile();
+
+	status readInit(AFfilesetup) OVERRIDE;
+	status writeInit(AFfilesetup) OVERRIDE;
+
+	status update() OVERRIDE;
+
+	bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;
+
+private:
+	AFfileoffset m_factOffset;	// start of fact (frame count) chunk
+	AFfileoffset m_miscellaneousOffset;
+	AFfileoffset m_markOffset;
+	AFfileoffset m_dataSizeOffset;
+
+	/*
+		The index into the coefficient array is of type
+		uint8_t, so we can safely limit msadpcmCoefficients to
+		be 256 coefficient pairs.
+	*/
+	int m_msadpcmNumCoefficients;
+	int16_t m_msadpcmCoefficients[256][2];
+
+	status parseFrameCount(const Tag &type, uint32_t size);
+	status parseFormat(const Tag &type, uint32_t size);
+	status parseData(const Tag &type, uint32_t size);
+	status parsePlayList(const Tag &type, uint32_t size);
+	status parseCues(const Tag &type, uint32_t size);
+	status parseADTLSubChunk(const Tag &type, uint32_t size);
+	status parseINFOSubChunk(const Tag &type, uint32_t size);
+	status parseList(const Tag &type, uint32_t size);
+	status parseInstrument(const Tag &type, uint32_t size);
+
+	status writeFormat();
+	status writeFrameCount();
+	status writeMiscellaneous();
+	status writeCues();
+	status writeData();
+
+	bool readUUID(UUID *g);
+	bool writeUUID(const UUID *g);
+
+	bool writeZString(const char *);
+	size_t zStringLength(const char *);
+
+	void initCompressionParams();
+	void initIMACompressionParams();
+	void initMSADPCMCompressionParams();
+};
+
+#endif
diff --git a/libaudiofile/aes.cpp b/libaudiofile/aes.cpp
new file mode 100644
index 0000000..fe7bc01
--- /dev/null
+++ b/libaudiofile/aes.cpp
@@ -0,0 +1,108 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	aes.c
+
+	This file contains routines for dealing with AES recording data.
+*/
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+
+void afInitAESChannelData (AFfilesetup setup, int trackid)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	track->aesDataSet = true;
+}
+
+void afInitAESChannelDataTo (AFfilesetup setup, int trackid, int willBeData)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	track->aesDataSet = willBeData;
+}
+
+int afGetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (!track->hasAESData)
+	{
+		if (buf)
+			memset(buf, 0, 24);
+		return 0;
+	}
+
+	if (buf)
+		memcpy(buf, track->aesData, 24);
+
+	return 1;
+}
+
+void afSetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (!file->checkCanWrite())
+		return;
+
+	if (track->hasAESData)
+	{
+		memcpy(track->aesData, buf, 24);
+	}
+	else
+	{
+		_af_error(AF_BAD_NOAESDATA,
+			"unable to store AES channel status data for track %d",
+			trackid);
+	}
+}
diff --git a/libaudiofile/af_vfs.cpp b/libaudiofile/af_vfs.cpp
new file mode 100644
index 0000000..3462d59
--- /dev/null
+++ b/libaudiofile/af_vfs.cpp
@@ -0,0 +1,44 @@
+/*
+	Audio File Library
+	Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	af_vfs.cpp
+
+	Virtual file operations for the Audio File Library.
+*/
+
+#include "config.h"
+
+#include "afinternal.h"
+#include "af_vfs.h"
+
+#include <stdlib.h>
+
+AFvirtualfile *af_virtual_file_new()
+{
+	return (AFvirtualfile *) calloc(sizeof (AFvirtualfile), 1);
+}
+
+void af_virtual_file_destroy(AFvirtualfile *vfile)
+{
+	vfile->destroy(vfile);
+
+	free(vfile);
+}
diff --git a/libaudiofile/af_vfs.h b/libaudiofile/af_vfs.h
new file mode 100644
index 0000000..19c1541
--- /dev/null
+++ b/libaudiofile/af_vfs.h
@@ -0,0 +1,64 @@
+/*
+	Audio File Library
+	Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	af_vfs.h
+
+	Virtual file operations for the Audio File Library.
+*/
+
+#ifndef AUDIOFILE_VFS_H
+#define AUDIOFILE_VFS_H
+
+#include <audiofile.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
+#define AFAPI __attribute__((visibility("default")))
+#else
+#define AFAPI
+#endif
+
+struct _AFvirtualfile
+{
+	ssize_t (*read) (AFvirtualfile *vfile, void *data, size_t nbytes);
+	AFfileoffset (*length) (AFvirtualfile *vfile);
+	ssize_t (*write) (AFvirtualfile *vfile, const void *data, size_t nbytes);
+	void (*destroy) (AFvirtualfile *vfile);
+	AFfileoffset (*seek) (AFvirtualfile *vfile, AFfileoffset offset, int is_relative);
+	AFfileoffset (*tell) (AFvirtualfile *vfile);
+
+	void *closure;
+};
+
+AFAPI AFvirtualfile *af_virtual_file_new (void);
+AFAPI void af_virtual_file_destroy (AFvirtualfile *vfile);
+
+#undef AFAPI
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libaudiofile/afinternal.h b/libaudiofile/afinternal.h
new file mode 100644
index 0000000..ce9a31b
--- /dev/null
+++ b/libaudiofile/afinternal.h
@@ -0,0 +1,120 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	afinternal.h
+
+	This file defines the internal structures for the Audio File Library.
+*/
+
+#ifndef AFINTERNAL_H
+#define AFINTERNAL_H
+
+#include <sys/types.h>
+#include "audiofile.h"
+#include "error.h"
+
+enum status
+{
+	AF_SUCCEED = 0,
+	AF_FAIL = -1
+};
+
+union AFPVu
+{
+	long	l;
+	double	d;
+	void	*v;
+};
+
+struct InstParamInfo
+{
+	int id;
+	int type;
+	const char *name;
+	AFPVu defaultValue;
+};
+
+struct Loop
+{
+	int	id;
+	int	mode;	/* AF_LOOP_MODE_... */
+	int	count;	/* how many times the loop is played */
+	int	beginMarker, endMarker;
+	int	trackid;
+};
+
+struct LoopSetup
+{
+	int	id;
+};
+
+struct Miscellaneous
+{
+	int id;
+	int type;
+	int size;
+
+	void *buffer;
+
+	int position;	// offset within the miscellaneous chunk
+};
+
+struct MiscellaneousSetup
+{
+	int	id;
+	int	type;
+	int	size;
+};
+
+struct TrackSetup;
+
+class File;
+struct Track;
+
+enum
+{
+	_AF_VALID_FILEHANDLE = 38212,
+	_AF_VALID_FILESETUP = 38213
+};
+
+enum
+{
+	_AF_READ_ACCESS = 1,
+	_AF_WRITE_ACCESS = 2
+};
+
+// The following are tokens for compression parameters in PV lists.
+enum
+{
+	_AF_MS_ADPCM_NUM_COEFFICIENTS = 800,	/* type: long */
+	_AF_MS_ADPCM_COEFFICIENTS = 801,		/* type: array of int16_t[2] */
+	_AF_IMA_ADPCM_TYPE = 810,
+	_AF_IMA_ADPCM_TYPE_WAVE = 1,
+	_AF_IMA_ADPCM_TYPE_QT = 2,
+	_AF_CODEC_DATA = 900,		// type: pointer
+	_AF_CODEC_DATA_SIZE = 901	// type: long
+};
+
+/* NeXT/Sun sampling rate */
+#define _AF_SRATE_CODEC (8012.8210513)
+
+#endif
diff --git a/libaudiofile/alac/ALACAudioTypes.h b/libaudiofile/alac/ALACAudioTypes.h
new file mode 100644
index 0000000..1ad71ee
--- /dev/null
+++ b/libaudiofile/alac/ALACAudioTypes.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACAudioTypes.h
+*/
+
+#ifndef ALACAUDIOTYPES_H
+#define ALACAUDIOTYPES_H
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#include "config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if PRAGMA_STRUCT_ALIGN
+    #pragma options align=mac68k
+#elif PRAGMA_STRUCT_PACKPUSH
+    #pragma pack(push, 2)
+#elif PRAGMA_STRUCT_PACK
+    #pragma pack(2)
+#endif
+
+#include <stdint.h>
+
+#ifdef WORDS_BIGENDIAN
+#define TARGET_RT_BIG_ENDIAN 1
+#endif
+
+#define kChannelAtomSize 12
+    
+enum 
+{
+    kALAC_UnimplementedError   = -4,
+    kALAC_FileNotFoundError    = -43,
+    kALAC_ParamError           = -50,
+    kALAC_MemFullError         = -108
+};
+
+enum
+{
+    kALACFormatAppleLossless = 'alac',
+    kALACFormatLinearPCM = 'lpcm'
+};
+
+enum
+{
+    kALACMaxChannels	= 8,
+    kALACMaxEscapeHeaderBytes = 8,
+    kALACMaxSearches	= 16,
+    kALACMaxCoefs		= 16,
+    kALACDefaultFramesPerPacket = 4096
+};
+
+typedef uint32_t ALACChannelLayoutTag;
+
+enum
+{
+    kALACFormatFlagIsFloat                     = (1 << 0),     // 0x1
+    kALACFormatFlagIsBigEndian                 = (1 << 1),     // 0x2
+    kALACFormatFlagIsSignedInteger             = (1 << 2),     // 0x4
+    kALACFormatFlagIsPacked                    = (1 << 3),     // 0x8
+    kALACFormatFlagIsAlignedHigh               = (1 << 4),     // 0x10
+};
+
+enum
+{
+#if TARGET_RT_BIG_ENDIAN
+    kALACFormatFlagsNativeEndian       = kALACFormatFlagIsBigEndian
+#else
+    kALACFormatFlagsNativeEndian       = 0
+#endif
+};
+
+// this is required to be an IEEE 64bit float
+typedef double alac_float64_t;
+
+// These are the Channel Layout Tags used in the Channel Layout Info portion of the ALAC magic cookie
+enum
+{
+    kALACChannelLayoutTag_Mono          = (100<<16) | 1,    // C
+    kALACChannelLayoutTag_Stereo        = (101<<16) | 2,	// L R
+    kALACChannelLayoutTag_MPEG_3_0_B    = (113<<16) | 3,	// C L R
+    kALACChannelLayoutTag_MPEG_4_0_B    = (116<<16) | 4,	// C L R Cs
+    kALACChannelLayoutTag_MPEG_5_0_D    = (120<<16) | 5,    // C L R Ls Rs
+    kALACChannelLayoutTag_MPEG_5_1_D    = (124<<16) | 6,	// C L R Ls Rs LFE
+    kALACChannelLayoutTag_AAC_6_1       = (142<<16) | 7,	// C L R Ls Rs Cs LFE
+    kALACChannelLayoutTag_MPEG_7_1_B	= (127<<16) | 8     // C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
+};
+
+// ALAC currently only utilizes these channels layouts. There is a one for one correspondance between a
+// given number of channels and one of these layout tags
+static const ALACChannelLayoutTag	ALACChannelLayoutTags[kALACMaxChannels] =
+{
+    kALACChannelLayoutTag_Mono,         // C
+    kALACChannelLayoutTag_Stereo,		// L R
+    kALACChannelLayoutTag_MPEG_3_0_B,	// C L R
+    kALACChannelLayoutTag_MPEG_4_0_B,	// C L R Cs
+    kALACChannelLayoutTag_MPEG_5_0_D,	// C L R Ls Rs
+    kALACChannelLayoutTag_MPEG_5_1_D,	// C L R Ls Rs LFE
+    kALACChannelLayoutTag_AAC_6_1,		// C L R Ls Rs Cs LFE
+    kALACChannelLayoutTag_MPEG_7_1_B	// C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
+};
+
+// AudioChannelLayout from CoreAudioTypes.h. We never need the AudioChannelDescription so we remove it
+struct ALACAudioChannelLayout
+{
+    ALACChannelLayoutTag          mChannelLayoutTag;
+    uint32_t                      mChannelBitmap;
+    uint32_t                      mNumberChannelDescriptions;
+};
+typedef struct ALACAudioChannelLayout ALACAudioChannelLayout;
+
+struct AudioFormatDescription
+{
+    alac_float64_t mSampleRate;
+    uint32_t  mFormatID;
+    uint32_t  mFormatFlags;
+    uint32_t  mBytesPerPacket;
+    uint32_t  mFramesPerPacket;
+    uint32_t  mBytesPerFrame;
+    uint32_t  mChannelsPerFrame;
+    uint32_t  mBitsPerChannel;
+    uint32_t  mReserved;
+};
+typedef struct AudioFormatDescription  AudioFormatDescription;
+
+/* Lossless Definitions */
+
+enum
+{
+	kALACCodecFormat		= 'alac',
+	kALACVersion			= 0,
+	kALACCompatibleVersion	= kALACVersion,
+	kALACDefaultFrameSize	= 4096
+};
+
+// note: this struct is wrapped in an 'alac' atom in the sample description extension area
+// note: in QT movies, it will be further wrapped in a 'wave' atom surrounded by 'frma' and 'term' atoms
+typedef struct ALACSpecificConfig
+{
+	uint32_t				frameLength;
+	uint8_t					compatibleVersion;
+	uint8_t					bitDepth;							// max 32
+	uint8_t					pb;									// 0 <= pb <= 255
+	uint8_t					mb;
+	uint8_t					kb;
+	uint8_t					numChannels;
+	uint16_t				maxRun;
+	uint32_t				maxFrameBytes;
+	uint32_t				avgBitRate;
+	uint32_t				sampleRate;
+
+} ALACSpecificConfig;
+
+
+// The AudioChannelLayout atom type is not exposed yet so define it here
+enum
+{
+	AudioChannelLayoutAID = 'chan'
+};
+
+#if PRAGMA_STRUCT_ALIGN
+    #pragma options align=reset
+#elif PRAGMA_STRUCT_PACKPUSH
+    #pragma pack(pop)
+#elif PRAGMA_STRUCT_PACK
+    #pragma pack()
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ALACAUDIOTYPES_H */
diff --git a/libaudiofile/alac/ALACBitUtilities.c b/libaudiofile/alac/ALACBitUtilities.c
new file mode 100644
index 0000000..9414889
--- /dev/null
+++ b/libaudiofile/alac/ALACBitUtilities.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*=============================================================================
+    File:		ALACBitUtilities.c
+
+	$NoKeywords: $
+=============================================================================*/
+
+#include <stdio.h>
+#include "ALACBitUtilities.h"
+
+// BitBufferInit
+//
+void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
+{
+	bits->cur		= buffer;
+	bits->end		= bits->cur + byteSize;
+	bits->bitIndex	= 0;
+	bits->byteSize	= byteSize;
+}
+
+// BitBufferRead
+//
+uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
+{
+	uint32_t		returnBits;
+	
+	//Assert( numBits <= 16 );
+
+	returnBits = ((uint32_t)bits->cur[0] << 16) | ((uint32_t)bits->cur[1] << 8) | ((uint32_t)bits->cur[2]);
+	returnBits = returnBits << bits->bitIndex;
+	returnBits &= 0x00FFFFFF;
+	
+	bits->bitIndex += numBits;
+	
+	returnBits = returnBits >> (24 - numBits);
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return returnBits;
+}
+
+// BitBufferReadSmall
+//
+// Reads up to 8 bits
+uint8_t BitBufferReadSmall( BitBuffer * bits, uint8_t numBits )
+{
+	uint16_t		returnBits;
+	
+	//Assert( numBits <= 8 );
+	
+	returnBits = (bits->cur[0] << 8) | bits->cur[1];
+	returnBits = returnBits << bits->bitIndex;
+	
+	bits->bitIndex += numBits;
+	
+	returnBits = returnBits >> (16 - numBits);
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return (uint8_t)returnBits;
+}
+
+// BitBufferReadOne
+//
+// Reads one byte
+uint8_t BitBufferReadOne( BitBuffer * bits )
+{
+	uint8_t		returnBits;
+
+	returnBits = (bits->cur[0] >> (7 - bits->bitIndex)) & 1;
+
+	bits->bitIndex++;
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return returnBits;
+}
+
+// BitBufferPeek
+//
+uint32_t BitBufferPeek( BitBuffer * bits, uint8_t numBits )
+{
+	return ((((((uint32_t) bits->cur[0] << 16) | ((uint32_t) bits->cur[1] << 8) |
+			((uint32_t) bits->cur[2])) << bits->bitIndex) & 0x00FFFFFF) >> (24 - numBits));
+}
+
+// BitBufferPeekOne
+//
+uint32_t BitBufferPeekOne( BitBuffer * bits )
+{
+	return ((bits->cur[0] >> (7 - bits->bitIndex)) & 1);
+}
+
+// BitBufferUnpackBERSize
+//
+uint32_t BitBufferUnpackBERSize( BitBuffer * bits )
+{
+	uint32_t		size;
+	uint8_t		tmp;
+	
+	for ( size = 0, tmp = 0x80u; tmp &= 0x80u; size = (size << 7u) | (tmp & 0x7fu) )
+		tmp = (uint8_t) BitBufferReadSmall( bits, 8 );
+	
+	return size;
+}
+
+// BitBufferGetPosition
+//
+uint32_t BitBufferGetPosition( BitBuffer * bits )
+{
+	uint8_t *		begin;
+	
+	begin = bits->end - bits->byteSize;
+	
+	return ((uint32_t)(bits->cur - begin) * 8) + bits->bitIndex;
+}
+
+// BitBufferByteAlign
+//
+void BitBufferByteAlign( BitBuffer * bits, int32_t addZeros )
+{
+	// align bit buffer to next byte boundary, writing zeros if requested
+	if ( bits->bitIndex == 0 )
+		return;
+
+	if ( addZeros )
+		BitBufferWrite( bits, 0, 8 - bits->bitIndex );
+	else	
+		BitBufferAdvance( bits, 8 - bits->bitIndex );	
+}
+
+// BitBufferAdvance
+//
+void BitBufferAdvance( BitBuffer * bits, uint32_t numBits )
+{
+	if ( numBits )
+	{
+		bits->bitIndex += numBits;
+		bits->cur += (bits->bitIndex >> 3);
+		bits->bitIndex &= 7;
+	}
+}
+
+// BitBufferRewind
+//
+void BitBufferRewind( BitBuffer * bits, uint32_t numBits )
+{
+	uint32_t	numBytes;
+	
+	if ( numBits == 0 )
+		return;
+	
+	if ( bits->bitIndex >= numBits )
+	{
+		bits->bitIndex -= numBits;
+		return;
+	}
+	
+	numBits -= bits->bitIndex;
+	bits->bitIndex = 0;
+
+	numBytes	= numBits / 8;
+	numBits		= numBits % 8;
+	
+	bits->cur -= numBytes;
+	
+	if ( numBits > 0 )
+	{
+		bits->bitIndex = 8 - numBits;
+		bits->cur--;
+	}
+	
+	if ( bits->cur < (bits->end - bits->byteSize) )
+	{
+		//DebugCMsg("BitBufferRewind: Rewound too far.");
+
+		bits->cur		= (bits->end - bits->byteSize);
+		bits->bitIndex	= 0;
+	}
+}
+
+// BitBufferWrite
+//
+void BitBufferWrite( BitBuffer * bits, uint32_t bitValues, uint32_t numBits )
+{
+	uint32_t				invBitIndex;
+	
+	RequireAction( bits != nil, return; );
+	RequireActionSilent( numBits > 0, return; );
+
+	invBitIndex = 8 - bits->bitIndex;
+
+	while ( numBits > 0 )
+	{
+		uint32_t		tmp;
+		uint8_t		shift;
+		uint8_t		mask;
+		uint32_t		curNum;
+
+		curNum = MIN( invBitIndex, numBits );
+
+		tmp = bitValues >> (numBits - curNum);
+
+		shift  = (uint8_t)(invBitIndex - curNum);
+		mask   = 0xffu >> (8 - curNum);		// must be done in two steps to avoid compiler sequencing ambiguity
+		mask <<= shift;
+
+		bits->cur[0] = (bits->cur[0] & ~mask) | (((uint8_t) tmp << shift)  & mask);
+		numBits -= curNum;
+
+		// increment to next byte if need be
+		invBitIndex -= curNum;
+		if ( invBitIndex == 0 )
+		{
+			invBitIndex = 8;
+			bits->cur++;
+		}
+	}
+
+	bits->bitIndex = 8 - invBitIndex;
+}
+
+void	BitBufferReset( BitBuffer * bits )
+//void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
+{
+	bits->cur		= bits->end - bits->byteSize;
+    bits->bitIndex	= 0;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
diff --git a/libaudiofile/alac/ALACBitUtilities.h b/libaudiofile/alac/ALACBitUtilities.h
new file mode 100644
index 0000000..97e9ebe
--- /dev/null
+++ b/libaudiofile/alac/ALACBitUtilities.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*=============================================================================
+    File:		ALACBitUtilities.h
+	
+	$NoKeywords: $
+=============================================================================*/
+
+#ifndef __ALACBITUTILITIES_H
+#define __ALACBITUTILITIES_H
+
+#include <stdint.h>
+
+#ifndef MIN
+#define MIN(x, y) 			( (x)<(y) ?(x) :(y) )
+#endif //MIN
+#ifndef MAX
+#define MAX(x, y) 			( (x)>(y) ?(x): (y) )
+#endif //MAX
+
+#ifndef nil
+#define nil NULL
+#endif
+
+#define RequireAction(condition, action)			if (!(condition)) { action }
+#define RequireActionSilent(condition, action)			if (!(condition)) { action }
+#define RequireNoErr(condition, action)			if ((condition)) { action }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+    ALAC_noErr = 0
+};
+    
+
+typedef enum
+{
+    
+    ID_SCE = 0,						/* Single Channel Element   */
+    ID_CPE = 1,						/* Channel Pair Element     */
+    ID_CCE = 2,						/* Coupling Channel Element */
+    ID_LFE = 3,						/* LFE Channel Element      */
+    ID_DSE = 4,						/* not yet supported        */
+    ID_PCE = 5,
+    ID_FIL = 6,
+    ID_END = 7
+} ELEMENT_TYPE;
+
+// types
+typedef struct BitBuffer
+{
+	uint8_t *		cur;
+	uint8_t *		end;
+	uint32_t		bitIndex;
+	uint32_t		byteSize;
+	
+} BitBuffer;
+
+/*
+	BitBuffer routines
+	- these routines take a fixed size buffer and read/write to it
+	- bounds checking must be done by the client
+*/
+void	BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize );
+uint32_t	BitBufferRead( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
+uint8_t	BitBufferReadSmall( BitBuffer * bits, uint8_t numBits );
+uint8_t	BitBufferReadOne( BitBuffer * bits );
+uint32_t	BitBufferPeek( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
+uint32_t	BitBufferPeekOne( BitBuffer * bits );
+uint32_t	BitBufferUnpackBERSize( BitBuffer * bits );
+uint32_t	BitBufferGetPosition( BitBuffer * bits );
+void	BitBufferByteAlign( BitBuffer * bits, int32_t addZeros );
+void	BitBufferAdvance( BitBuffer * bits, uint32_t numBits );
+void	BitBufferRewind( BitBuffer * bits, uint32_t numBits );
+void	BitBufferWrite( BitBuffer * bits, uint32_t value, uint32_t numBits );
+void	BitBufferReset( BitBuffer * bits);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __BITUTILITIES_H */
diff --git a/libaudiofile/alac/ALACDecoder.cpp b/libaudiofile/alac/ALACDecoder.cpp
new file mode 100644
index 0000000..35cf06e
--- /dev/null
+++ b/libaudiofile/alac/ALACDecoder.cpp
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACDecoder.cpp
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ALACDecoder.h"
+
+#include "dplib.h"
+#include "aglib.h"
+#include "matrixlib.h"
+
+#include "ALACBitUtilities.h"
+#include "EndianPortable.h"
+
+// constants/data
+const uint32_t kMaxBitDepth = 32;			// max allowed bit depth is 32
+
+
+// prototypes
+static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride );
+static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride );
+static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride );
+
+/*
+	Constructor
+*/
+ALACDecoder::ALACDecoder() :
+	mMixBufferU( nil ),
+	mMixBufferV( nil ),
+	mPredictor( nil ),
+	mShiftBuffer( nil )
+{
+	memset( &mConfig, 0, sizeof(mConfig) );
+}
+
+/*
+	Destructor
+*/
+ALACDecoder::~ALACDecoder()
+{
+	// delete the matrix mixing buffers
+	if ( mMixBufferU )
+    {
+		free(mMixBufferU);
+        mMixBufferU = NULL;
+    }
+	if ( mMixBufferV )
+    {
+		free(mMixBufferV);
+        mMixBufferV = NULL;
+    }
+	
+	// delete the dynamic predictor's "corrector" buffer
+	// - note: mShiftBuffer shares memory with this buffer
+	if ( mPredictor )
+    {
+		free(mPredictor);
+        mPredictor = NULL;
+    }
+}
+
+/*
+	Init()
+	- initialize the decoder with the given configuration
+*/
+int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize )
+{
+	int32_t		status = ALAC_noErr;
+    ALACSpecificConfig theConfig;
+    uint8_t * theActualCookie = (uint8_t *)inMagicCookie;
+    uint32_t theCookieBytesRemaining = inMagicCookieSize;
+
+    // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders.
+    // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating 
+    // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the
+    // ALACSpecificConfig. 
+    // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie'
+    
+    // skip format ('frma') atom if present
+    if (theActualCookie[4] == 'f' && theActualCookie[5] == 'r' && theActualCookie[6] == 'm' && theActualCookie[7] == 'a')
+    {
+        theActualCookie += 12;
+        theCookieBytesRemaining -= 12;
+    }
+    
+    // skip 'alac' atom header if present
+    if (theActualCookie[4] == 'a' && theActualCookie[5] == 'l' && theActualCookie[6] == 'a' && theActualCookie[7] == 'c')
+    {
+        theActualCookie += 12;
+        theCookieBytesRemaining -= 12;
+    }
+
+    // read the ALACSpecificConfig
+    if (theCookieBytesRemaining >= sizeof(ALACSpecificConfig))
+    {
+        memcpy(&theConfig, theActualCookie, sizeof(ALACSpecificConfig));
+
+        theConfig.frameLength = Swap32BtoN(theConfig.frameLength);
+        theConfig.maxRun = Swap16BtoN(theConfig.maxRun);
+        theConfig.maxFrameBytes = Swap32BtoN(theConfig.maxFrameBytes);
+        theConfig.avgBitRate = Swap32BtoN(theConfig.avgBitRate);
+        theConfig.sampleRate = Swap32BtoN(theConfig.sampleRate);
+
+        mConfig = theConfig;
+        
+        RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );
+
+        // allocate mix buffers
+        mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+        mMixBufferV = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+
+        // allocate dynamic predictor buffer
+        mPredictor = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+
+        // "shift off" buffer shares memory with predictor buffer
+        mShiftBuffer = (uint16_t *) mPredictor;
+        
+        RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && (mPredictor != nil),
+                        status = kALAC_MemFullError; goto Exit; );
+     }
+    else
+    {
+        status = kALAC_ParamError;
+    }
+
+    // skip to Channel Layout Info
+    // theActualCookie += sizeof(ALACSpecificConfig);
+    
+    // Currently, the Channel Layout Info portion of the magic cookie (as defined in the 
+    // ALACMagicCookieDescription.txt document) is unused by the decoder. 
+    
+Exit:
+	return status;
+}
+
+/*
+	Decode()
+	- the decoded samples are interleaved into the output buffer in the order they arrive in
+	  the bitstream
+*/
+int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples )
+{
+	BitBuffer			shiftBits;
+	uint32_t            bits1, bits2;
+	uint8_t				tag;
+	uint8_t				elementInstanceTag;
+	AGParamRec			agParams;
+	uint32_t				channelIndex;
+	int16_t				coefsU[32];		// max possible size is 32 although NUMCOEPAIRS is the current limit
+	int16_t				coefsV[32];
+	uint8_t				numU, numV;
+	uint8_t				mixBits;
+	int8_t				mixRes;
+	uint16_t			unusedHeader;
+	uint8_t				escapeFlag;
+	uint32_t			chanBits;
+	uint8_t				bytesShifted;
+	uint32_t			shift;
+	uint8_t				modeU, modeV;
+	uint32_t			denShiftU, denShiftV;
+	uint16_t			pbFactorU, pbFactorV;
+	uint16_t			pb;
+	int16_t *			samples;
+	int16_t *			out16;
+	uint8_t *			out20;
+	uint8_t *			out24;
+	int32_t *			out32;
+	uint8_t				headerByte;
+	uint8_t				partialFrame;
+	uint32_t			extraBits;
+	int32_t				val;
+	uint32_t			i, j;
+	int32_t             status;
+	
+	RequireAction( (bits != nil) && (sampleBuffer != nil) && (outNumSamples != nil), return kALAC_ParamError; );
+	RequireAction( numChannels > 0, return kALAC_ParamError; );
+
+	mActiveElements = 0;
+	channelIndex	= 0;
+	
+	samples = (int16_t *) sampleBuffer;
+
+	status = ALAC_noErr;
+	*outNumSamples = numSamples;
+
+	while ( status == ALAC_noErr )
+	{
+		// bail if we ran off the end of the buffer
+    	RequireAction( bits->cur < bits->end, status = kALAC_ParamError; goto Exit; );
+
+		// copy global decode params for this element
+		pb = mConfig.pb;
+
+		// read element tag
+		tag = BitBufferReadSmall( bits, 3 );
+		switch ( tag )
+		{
+			case ID_SCE:
+			case ID_LFE:
+			{
+				// mono/LFE channel
+				elementInstanceTag = BitBufferReadSmall( bits, 4 );
+				mActiveElements |= (1u << elementInstanceTag);
+
+				// read the 12 unused header bits
+				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
+				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
+
+				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
+				headerByte = (uint8_t) BitBufferRead( bits, 4 );
+				
+				partialFrame = headerByte >> 3;
+				
+				bytesShifted = (headerByte >> 1) & 0x3u;
+				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
+
+				shift = bytesShifted * 8;
+
+				escapeFlag = headerByte & 0x1;
+
+				chanBits = mConfig.bitDepth - (bytesShifted * 8);
+				
+				// check for partial frame to override requested numSamples
+				if ( partialFrame != 0 )
+				{
+					numSamples  = BitBufferRead( bits, 16 ) << 16;
+					numSamples |= BitBufferRead( bits, 16 );
+				}
+
+				if ( escapeFlag == 0 )
+				{
+					// compressed frame, read rest of parameters
+					mixBits	= (uint8_t) BitBufferRead( bits, 8 );
+					mixRes	= (int8_t) BitBufferRead( bits, 8 );
+					//Assert( (mixBits == 0) && (mixRes == 0) );		// no mixing for mono
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeU		= headerByte >> 4;
+					denShiftU	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorU	= headerByte >> 5;
+					numU		= headerByte & 0x1fu;
+
+					for ( i = 0; i < numU; i++ )
+						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
+					
+					// if shift active, skip the the shift buffer but remember where it starts
+					if ( bytesShifted != 0 )
+					{
+						shiftBits = *bits;
+						BitBufferAdvance( bits, (bytesShifted * 8) * numSamples ); 
+					}
+
+					// decompress
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeU == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+				}
+				else
+				{
+					//Assert( bytesShifted == 0 );
+
+					// uncompressed frame, copy data into the mix buffer to use common output code
+					shift = 32 - chanBits;
+					if ( chanBits <= 16 )
+					{
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferU[i] = val;
+						}
+					}
+					else
+					{
+						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
+						extraBits = chanBits - 16;
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t) extraBits );
+						}
+					}
+
+					mixBits = mixRes = 0;
+					bits1 = chanBits * numSamples;
+					bytesShifted = 0;
+				}
+
+				// now read the shifted values into the shift buffer
+				if ( bytesShifted != 0 )
+				{
+					shift = bytesShifted * 8;
+					//Assert( shift <= 16 );
+
+					for ( i = 0; i < numSamples; i++ )
+						mShiftBuffer[i] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+				}
+
+				// convert 32-bit integers into output buffer
+				switch ( mConfig.bitDepth )
+				{
+					case 16:
+						out16 = &((int16_t *)sampleBuffer)[channelIndex];
+						for ( i = 0, j = 0; i < numSamples; i++, j += numChannels )
+							out16[j] = (int16_t) mMixBufferU[i];
+						break;
+					case 20:
+						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						copyPredictorTo20( mMixBufferU, out20, numChannels, numSamples );
+						break;
+					case 24:
+						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						if ( bytesShifted != 0 )
+							copyPredictorTo24Shift( mMixBufferU, mShiftBuffer, out24, numChannels, numSamples, bytesShifted );
+						else
+							copyPredictorTo24( mMixBufferU, out24, numChannels, numSamples );							
+						break;
+					case 32:
+						out32 = &((int32_t *)sampleBuffer)[channelIndex];
+						if ( bytesShifted != 0 )
+							copyPredictorTo32Shift( mMixBufferU, mShiftBuffer, out32, numChannels, numSamples, bytesShifted );
+						else
+							copyPredictorTo32( mMixBufferU, out32, numChannels, numSamples);
+						break;
+				}
+
+				channelIndex += 1;
+				*outNumSamples = numSamples;
+				break;
+			}
+
+			case ID_CPE:
+			{
+				// if decoding this pair would take us over the max channels limit, bail
+				if ( (channelIndex + 2) > numChannels )
+					goto NoMoreChannels;
+
+				// stereo channel pair
+				elementInstanceTag = BitBufferReadSmall( bits, 4 );
+				mActiveElements |= (1u << elementInstanceTag);
+
+				// read the 12 unused header bits
+				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
+				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
+
+				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
+				headerByte = (uint8_t) BitBufferRead( bits, 4 );
+				
+				partialFrame = headerByte >> 3;
+				
+				bytesShifted = (headerByte >> 1) & 0x3u;
+				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
+
+				shift = bytesShifted * 8;
+
+				escapeFlag = headerByte & 0x1;
+
+				chanBits = mConfig.bitDepth - (bytesShifted * 8) + 1;
+				
+				// check for partial frame length to override requested numSamples
+				if ( partialFrame != 0 )
+				{
+					numSamples  = BitBufferRead( bits, 16 ) << 16;
+					numSamples |= BitBufferRead( bits, 16 );
+				}
+
+				if ( escapeFlag == 0 )
+				{
+					// compressed frame, read rest of parameters
+					mixBits		= (uint8_t) BitBufferRead( bits, 8 );
+					mixRes		= (int8_t) BitBufferRead( bits, 8 );
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeU		= headerByte >> 4;
+					denShiftU	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorU	= headerByte >> 5;
+					numU		= headerByte & 0x1fu;
+					for ( i = 0; i < numU; i++ )
+						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeV		= headerByte >> 4;
+					denShiftV	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorV	= headerByte >> 5;
+					numV		= headerByte & 0x1fu;
+					for ( i = 0; i < numV; i++ )
+						coefsV[i] = (int16_t) BitBufferRead( bits, 16 );
+
+					// if shift active, skip the interleaved shifted values but remember where they start
+					if ( bytesShifted != 0 )
+					{
+						shiftBits = *bits;
+						BitBufferAdvance( bits, (bytesShifted * 8) * 2 * numSamples );
+					}
+
+					// decompress and run predictor for "left" channel
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeU == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+
+					// decompress and run predictor for "right" channel
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorV) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits2 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeV == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
+					}
+				}
+				else
+				{
+					//Assert( bytesShifted == 0 );
+
+					// uncompressed frame, copy data into the mix buffers to use common output code
+					chanBits = mConfig.bitDepth;
+					shift = 32 - chanBits;
+					if ( chanBits <= 16 )
+					{
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferU[i] = val;
+
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferV[i] = val;
+						}
+					}
+					else
+					{
+						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
+						extraBits = chanBits - 16;
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
+
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferV[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
+						}
+					}
+
+					bits1 = chanBits * numSamples;
+					bits2 = chanBits * numSamples;
+					mixBits = mixRes = 0;
+					bytesShifted = 0;
+				}
+
+				// now read the shifted values into the shift buffer
+				if ( bytesShifted != 0 )
+				{
+					shift = bytesShifted * 8;
+					//Assert( shift <= 16 );
+
+					for ( i = 0; i < (numSamples * 2); i += 2 )
+					{
+						mShiftBuffer[i + 0] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+						mShiftBuffer[i + 1] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+					}
+				}
+
+				// un-mix the data and convert to output format
+				// - note that mixRes = 0 means just interleave so we use that path for uncompressed frames
+				switch ( mConfig.bitDepth )
+				{
+					case 16:
+						out16 = &((int16_t *)sampleBuffer)[channelIndex];
+						unmix16( mMixBufferU, mMixBufferV, out16, numChannels, numSamples, mixBits, mixRes );
+						break;
+					case 20:
+						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						unmix20( mMixBufferU, mMixBufferV, out20, numChannels, numSamples, mixBits, mixRes );
+						break;
+					case 24:
+						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						unmix24( mMixBufferU, mMixBufferV, out24, numChannels, numSamples,
+									mixBits, mixRes, mShiftBuffer, bytesShifted );
+						break;
+					case 32:
+						out32 = &((int32_t *)sampleBuffer)[channelIndex];
+						unmix32( mMixBufferU, mMixBufferV, out32, numChannels, numSamples,
+									mixBits, mixRes, mShiftBuffer, bytesShifted );
+						break;
+				}
+
+				channelIndex += 2;
+				*outNumSamples = numSamples;
+				break;
+			}
+
+			case ID_CCE:
+			case ID_PCE:
+			{
+				// unsupported element, bail
+				//AssertNoErr( tag );
+				status = kALAC_ParamError;
+				break;
+			}
+
+			case ID_DSE:
+			{
+				// data stream element -- parse but ignore
+				status = this->DataStreamElement( bits );
+				break;
+			}
+			
+			case ID_FIL:
+			{
+				// fill element -- parse but ignore
+				status = this->FillElement( bits );
+				break;
+			}
+
+			case ID_END:
+			{
+				// frame end, all done so byte align the frame and check for overruns
+				BitBufferByteAlign( bits, false );
+				//Assert( bits->cur == bits->end );
+				goto Exit;
+			}
+		}
+
+#if ! DEBUG
+		// if we've decoded all of our channels, bail (but not in debug b/c we want to know if we're seeing bad bits)
+		// - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits
+		if ( channelIndex >= numChannels )
+			break;
+#endif
+	}
+
+NoMoreChannels:
+
+	// if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros
+	for ( ; channelIndex < numChannels; channelIndex++ )
+	{
+		switch ( mConfig.bitDepth )
+		{
+			case 16:
+			{
+				int16_t *	fill16 = &((int16_t *)sampleBuffer)[channelIndex];
+				Zero16( fill16, numSamples, numChannels );
+				break;
+			}
+			case 24:
+			{
+				uint8_t *	fill24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+				Zero24( fill24, numSamples, numChannels );
+				break;
+			}
+			case 32:
+			{
+				int32_t *	fill32 = &((int32_t *)sampleBuffer)[channelIndex];
+				Zero32( fill32, numSamples, numChannels );
+				break;
+			}
+		}
+	}
+
+Exit:
+	return status;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	FillElement()
+	- they're just filler so we don't need 'em
+*/
+int32_t ALACDecoder::FillElement( BitBuffer * bits )
+{
+	int16_t		count;
+	
+	// 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15
+	// - plus this weird -1 thing I still don't fully understand
+	count = BitBufferReadSmall( bits, 4 );
+	if ( count == 15 )
+		count += (int16_t) BitBufferReadSmall( bits, 8 ) - 1;
+
+	BitBufferAdvance( bits, count * 8 );
+
+	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
+
+	return ALAC_noErr;	
+}
+
+/*
+	DataStreamElement()
+	- we don't care about data stream elements so just skip them
+*/
+int32_t ALACDecoder::DataStreamElement( BitBuffer * bits )
+{
+	uint8_t		element_instance_tag;
+	int32_t		data_byte_align_flag;
+	uint16_t		count;
+	
+	// the tag associates this data stream element with a given audio element
+	element_instance_tag = BitBufferReadSmall( bits, 4 );
+	
+	data_byte_align_flag = BitBufferReadOne( bits );
+
+	// 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255
+	count = BitBufferReadSmall( bits, 8 );
+	if ( count == 255 )
+		count += BitBufferReadSmall( bits, 8 );
+
+	// the align flag means the bitstream should be byte-aligned before reading the following data bytes
+	if ( data_byte_align_flag )
+		BitBufferByteAlign( bits, false );
+
+	// skip the data bytes
+	BitBufferAdvance( bits, count * 8 );
+
+	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
+
+	return ALAC_noErr;
+}
+
+/*
+	ZeroN()
+	- helper routines to clear out output channel buffers when decoding fewer channels than requested
+*/
+static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * sizeof(int16_t) );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
+			buffer[index] = 0;
+	}
+}
+
+static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * 3 );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride * 3); index += (stride * 3) )
+		{
+			buffer[index + 0] = 0;
+			buffer[index + 1] = 0;
+			buffer[index + 2] = 0;
+		}
+	}
+}
+
+static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * sizeof(int32_t) );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
+			buffer[index] = 0;
+	}
+}
diff --git a/libaudiofile/alac/ALACDecoder.h b/libaudiofile/alac/ALACDecoder.h
new file mode 100644
index 0000000..7802eab
--- /dev/null
+++ b/libaudiofile/alac/ALACDecoder.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACDecoder.h
+*/
+
+#ifndef _ALACDECODER_H
+#define _ALACDECODER_H
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#include <stdint.h>
+
+#include "ALACAudioTypes.h"
+
+struct BitBuffer;
+
+class ALACDecoder
+{
+	public:
+		ALACDecoder();
+		~ALACDecoder();
+
+		int32_t	Init( void * inMagicCookie, uint32_t inMagicCookieSize );
+		int32_t	Decode( struct BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples );
+
+	public:
+		// decoding parameters (public for use in the analyzer)
+		ALACSpecificConfig		mConfig;
+
+	protected:
+		int32_t	FillElement( struct BitBuffer * bits );
+		int32_t	DataStreamElement( struct BitBuffer * bits );
+
+		uint16_t					mActiveElements;
+
+		// decoding buffers
+		int32_t *				mMixBufferU;
+		int32_t *				mMixBufferV;
+		int32_t *				mPredictor;
+		uint16_t *				mShiftBuffer;	// note: this points to mPredictor's memory but different
+												//		 variable for clarity and type difference
+};
+
+#endif	/* _ALACDECODER_H */
diff --git a/libaudiofile/alac/ALACEncoder.cpp b/libaudiofile/alac/ALACEncoder.cpp
new file mode 100644
index 0000000..da922c2
--- /dev/null
+++ b/libaudiofile/alac/ALACEncoder.cpp
@@ -0,0 +1,1421 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACEncoder.cpp
+*/
+
+// build stuff
+#define VERBOSE_DEBUG		0
+
+// headers
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ALACEncoder.h"
+
+#include "aglib.h"
+#include "dplib.h"
+#include "matrixlib.h"
+
+#include "ALACBitUtilities.h"
+#include "ALACAudioTypes.h"
+#include "EndianPortable.h"
+
+// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when
+// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type
+typedef int16_t (*SearchCoefs)[kALACMaxCoefs];
+
+// defines/constants
+const uint32_t kALACEncoderMagic	= 'dpge';
+const uint32_t kMaxSampleSize		= 32;			// max allowed bit width is 32
+const uint32_t kDefaultMixBits	= 2;
+const uint32_t kDefaultMixRes		= 0;
+const uint32_t kMaxRes			= 4;
+const uint32_t kDefaultNumUV		= 8;
+const uint32_t kMinUV				= 4;
+const uint32_t kMaxUV				= 8;
+
+// static functions
+#if VERBOSE_DEBUG
+static void AddFiller( BitBuffer * bits, int32_t numBytes );
+#endif
+
+
+/*
+	Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed
+				at the beginning of the frame for that channel.  Indicates whether SCE, CPE, or LFE.
+				Each particular field is accessed via the current channel index.  Note that the channel
+				index increments by two for channel pairs.
+				
+	For example:
+	
+			C L R 3-channel input		= (ID_CPE << 3) | (ID_SCE)
+				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
+				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
+
+			C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
+				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
+				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
+				index 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3)
+				index 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3)
+				index 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3)
+*/
+static const uint32_t	sChannelMaps[kALACMaxChannels] =
+{
+	ID_SCE,
+	ID_CPE,
+	(ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
+};
+
+static const uint32_t sSupportediPodSampleRates[] =
+{
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+/*
+	Constructor
+*/
+ALACEncoder::ALACEncoder() :
+	mBitDepth( 0 ),
+    mFastMode( 0 ),
+	mMixBufferU( nil ),
+	mMixBufferV( nil ),
+	mPredictorU( nil ),
+	mPredictorV( nil ),
+	mShiftBufferUV( nil ),
+	mWorkBuffer( nil ),
+
+
+	mTotalBytesGenerated( 0 ),
+	mAvgBitRate( 0 ),
+	mMaxFrameBytes( 0 )
+{
+	// overrides
+	mFrameSize = kALACDefaultFrameSize;
+}
+
+/*
+	Destructor
+*/
+ALACEncoder::~ALACEncoder()
+{
+	// delete the matrix mixing buffers
+	if ( mMixBufferU )
+    {
+		free(mMixBufferU);
+        mMixBufferU = NULL;
+    }
+	if ( mMixBufferV )
+    {
+		free(mMixBufferV);
+        mMixBufferV = NULL;
+    }
+	
+	// delete the dynamic predictor's "corrector" buffers
+	if ( mPredictorU )
+    {
+		free(mPredictorU);
+        mPredictorU = NULL;
+    }
+	if ( mPredictorV )
+    {
+		free(mPredictorV);
+        mPredictorV = NULL;
+    }
+
+	// delete the unused byte shift buffer
+	if ( mShiftBufferUV )
+    {
+		free(mShiftBufferUV);
+        mShiftBufferUV = NULL;
+    }
+
+	// delete the work buffer
+	if ( mWorkBuffer )
+    {
+		free(mWorkBuffer);
+        mWorkBuffer = NULL;
+    }	
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	HEADER SPECIFICATION  
+
+        For every segment we adopt the following header:
+        
+			1 byte reserved			(always 0)
+			1 byte flags			(see below)
+			[4 byte frame length]	(optional, see below)
+			     ---Next, the per-segment ALAC parameters---
+			1 byte mixBits			(middle-side parameter)
+			1 byte mixRes			(middle-side parameter, interpreted as signed char)
+
+			1 byte shiftU			(4 bits modeU, 4 bits denShiftU)
+			1 byte filterU			(3 bits pbFactorU, 5 bits numU)
+			(numU) shorts			(signed DP coefficients for V channel)
+			     ---Next, 2nd-channel ALAC parameters in case of stereo mode---
+			1 byte shiftV			(4 bits modeV, 4 bits denShiftV)
+			1 byte filterV			(3 bits pbFactorV, 5 bits numV)
+			(numV) shorts			(signed DP coefficients for V channel)
+			     ---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated---
+			     ---Then comes the AG-compressor bitstream---
+
+
+        FLAGS
+        -----
+
+		The presence of certain flag bits changes the header format such that the parameters might
+		not even be sent.  The currently defined flags format is:
+
+			0000psse
+			
+			where		0 	= reserved, must be 0
+						p	= 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte
+						ss	= 2-bit field indicating "number of shift-off bytes ignored by compression"
+						e	= 1-bit field indicating "escape"
+
+		The "partial frame" flag means that the following segment is not equal to the frame length specified
+		in the out-of-band decoder configuration.  This allows the decoder to deal with end-of-file partial
+		segments without incurring the 32-bit overhead for each segment.
+
+		The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through
+		uncompressed.  The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words
+		quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the
+		uncompressed size.  However, by shifting the input values down and running the remaining bits through
+		the normal compression algorithm, a net win can be achieved.  If this field is non-zero, it means that
+		the shifted-off bytes follow after the parameter section of the header and before the compressed
+		bitstream.  Note that doing this also allows us to use matrixing on 32-bit inputs after one or more
+		bytes are shifted off the bottom which helps the eventual compression ratio.  For stereo channels,
+		the shifted off bytes are interleaved.
+
+        The "escape" flag means that this segment was not compressed b/c the compressed size would be
+        >= uncompressed size.  In that case, the audio data was passed through uncompressed after the header.
+        The other header parameter bytes will not be sent.
+        
+
+		PARAMETERS
+		----------
+
+		If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by:
+
+			4 + (2 + 2 * numU)                   (mono mode)
+			4 + (2 + 2 * numV) + (2 + 2 * numV)  (stereo mode)
+
+        where the ALAC filter-lengths numU, numV are bounded by a
+        constant (in the current source, numU, numV <= NUMCOEPAIRS), and
+        this forces an absolute upper bound on header size.
+
+        Each segment-decode process loads up these bytes from the front of the
+        local stream, in the above order, then follows with the entropy-encoded
+        bits for the given segment.
+
+        To generalize middle-side, there are various mixing modes including middle-side, each lossless,
+        as embodied in the mix() and unmix() functions.  These functions exploit a generalized middle-side
+        transformation:
+
+        u := [(rL + (m-r)R)/m];
+        v := L - R;
+
+        where [ ] denotes integer floor.  The (lossless) inverse is
+
+        L = u + v - [rV/m];
+        R = L - v;
+
+        In the segment header, m and r are encoded in mixBits and mixRes.
+        Classical "middle-side" is obtained with m = 2, r = 1, but now
+        we have more generalized mixes.
+
+        NOTES
+        -----
+        The relevance of the ALAC coefficients is explained in detail
+        in patent documents.
+*/
+
+/*
+	EncodeStereo()
+	- encode a channel pair
+*/
+int32_t ALACEncoder::EncodeStereo( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		workBits;
+	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
+	AGParamRec		agParams;
+	uint32_t          bits1, bits2;
+	uint32_t			dilate;
+	int32_t			mixBits, mixRes, maxRes;
+	uint32_t			minBits, minBits1, minBits2;
+	uint32_t			numU, numV;
+	uint32_t			mode;
+	uint32_t			pbFactor;
+	uint32_t			chanBits;
+	uint32_t			denShift;
+	uint8_t			bytesShifted;
+	SearchCoefs		coefsU;
+	SearchCoefs		coefsV;
+	uint32_t			index;
+	uint8_t			partialFrame;
+	uint32_t			escapeBits;
+	bool			doEscape;
+	int32_t		status = ALAC_noErr;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	// reload coefs pointers for this channel pair
+	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
+	//	 actually results in better overall compression
+	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
+	//	 different coefs for the different passes of "mixRes" results in even better compression
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+	coefsV = (SearchCoefs) mCoefsV[channelIndex];
+
+	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
+	// so enable 16-bit "shift off" and encode in 17-bit mode
+	// - in addition, 24-bit mode really improves with one byte shifted off
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	chanBits = mBitDepth - (bytesShifted * 8) + 1;
+	
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// brute-force encode optimization loop
+	// - run over variations of the encoding params to find the best choice
+	mixBits		= kDefaultMixBits;
+	maxRes		= kMaxRes;
+	numU = numV = kDefaultNumUV;
+	denShift	= DENSHIFT_DEFAULT;
+	mode		= 0;
+	pbFactor	= 4;
+	dilate		= 8;
+
+	minBits	= minBits1 = minBits2 = 1ul << 31;
+	
+    int32_t		bestRes = mLastMixRes[channelIndex];
+
+    for ( mixRes = 0; mixRes <= maxRes; mixRes++ )
+    {
+        // mix the stereo inputs
+        switch ( mBitDepth )
+        {
+            case 16:
+                mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
+                break;
+            case 20:
+                mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
+                break;
+            case 24:
+                // includes extraction of shifted-off bytes
+                mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
+                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
+                break;
+            case 32:
+                // includes extraction of shifted-off bytes
+                mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
+                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
+                break;
+        }
+
+        BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
+        
+        // run the dynamic predictors
+        pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+        pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+
+        // run the lossless compressor on each channel
+        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+        status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+        RequireNoErr( status, goto Exit; );
+
+        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+        status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
+        RequireNoErr( status, goto Exit; );
+
+        // look for best match
+        if ( (bits1 + bits2) < minBits1 )
+        {
+            minBits1 = bits1 + bits2;
+            bestRes = mixRes;
+        }
+    }
+    
+    mLastMixRes[channelIndex] = (int16_t)bestRes;
+
+	// mix the stereo inputs with the current best mixRes
+	mixRes = mLastMixRes[channelIndex];
+	switch ( mBitDepth )
+	{
+		case 16:
+			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 20:
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 24:
+			// also extracts the shifted off bytes into the shift buffers
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+		case 32:
+			// also extracts the shifted off bytes into the shift buffers
+			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+	}
+
+	// now it's time for the predictor coefficient search loop
+	numU = numV = kMinUV;
+	minBits1 = minBits2 = 1ul << 31;
+
+	for ( uint32_t numUV = kMinUV; numUV <= kMaxUV; numUV += 4 )
+	{
+		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );		
+
+		dilate = 32;
+
+		// run the predictor over the same data multiple times to help it converge
+		for ( uint32_t converge = 0; converge < 8; converge++ )
+		{
+		    pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
+		    pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
+		}
+
+		dilate = 8;
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+
+		if ( (bits1 * dilate + 16 * numUV) < minBits1 )
+		{
+			minBits1 = bits1 * dilate + 16 * numUV;
+			numU = numUV;
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
+
+		if ( (bits2 * dilate + 16 * numUV) < minBits2 )
+		{
+			minBits2 = bits2 * dilate + 16 * numUV;
+			numV = numUV;
+		}
+	}
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8) * 2);
+
+	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		// write bitstream header and coefs
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+		BitBufferWrite( bitstream, mixBits, 8 );
+		BitBufferWrite( bitstream, mixRes, 8 );
+		
+		//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
+		//Assert( (pbFactor < 8) && (numU < 32) );
+		//Assert( (pbFactor < 8) && (numV < 32) );
+
+		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+		for ( index = 0; index < numU; index++ )
+			BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );
+
+		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+		BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
+		for ( index = 0; index < numV; index++ )
+			BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );
+
+		// if shift active, write the interleaved shift buffers
+		if ( bytesShifted != 0 )
+		{
+			uint32_t		bitShift = bytesShifted * 8;
+
+			//Assert( bitShift <= 16 );
+
+			for ( index = 0; index < (numSamples * 2); index += 2 )
+			{
+				uint32_t			shiftedVal;
+				
+				shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
+				BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
+			}
+		}
+
+		// run the dynamic predictor and lossless compression for the "left" channel
+		// - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead
+		//		   of only using "U" buffers for the U-channel and "V" buffers for the V-channel
+		if ( mode == 0 )
+		{
+			pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+		}
+		else
+		{
+			pc_block( mMixBufferU, mPredictorV, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+			pc_block( mPredictorV, mPredictorU, numSamples, nil, 31, chanBits, 0 );
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+		RequireNoErr( status, goto Exit; );
+
+		// run the dynamic predictor and lossless compression for the "right" channel
+		if ( mode == 0 )
+		{
+			pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+		}
+		else
+		{
+			pc_block( mMixBufferV, mPredictorU, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+			pc_block( mPredictorU, mPredictorV, numSamples, nil, 31, chanBits, 0 );
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
+		RequireNoErr( status, goto Exit; );
+
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			*bitstream = startBits;		// reset bitstream state
+			doEscape = true;
+		}
+	}
+
+	if ( doEscape == true )
+	{
+		/* escape */
+		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );
+
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %lu vs %lu", minBits, escapeBits );
+#endif
+	}
+	
+Exit:
+	return status;
+}
+
+/*
+	EncodeStereoFast()
+	- encode a channel pair without the search loop for maximum possible speed
+*/
+int32_t ALACEncoder::EncodeStereoFast( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		startBits = *bitstream;			// squirrel away current bit position in case we decide to use escape hatch
+	AGParamRec		agParams;
+	uint32_t	bits1, bits2;
+	int32_t			mixBits, mixRes;
+	uint32_t			minBits, minBits1, minBits2;
+	uint32_t			numU, numV;
+	uint32_t			mode;
+	uint32_t			pbFactor;
+	uint32_t			chanBits;
+	uint32_t			denShift;
+	uint8_t			bytesShifted;
+	SearchCoefs		coefsU;
+	SearchCoefs		coefsV;
+	uint32_t			index;
+	uint8_t			partialFrame;
+	uint32_t			escapeBits;
+	bool			doEscape;	
+	int32_t		status;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	// reload coefs pointers for this channel pair
+	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
+	//	 actually results in better overall compression
+	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
+	//	 different coefs for the different passes of "mixRes" results in even better compression
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+	coefsV = (SearchCoefs) mCoefsV[channelIndex];
+
+	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
+	// so enable 16-bit "shift off" and encode in 17-bit mode
+	// - in addition, 24-bit mode really improves with one byte shifted off
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	chanBits = mBitDepth - (bytesShifted * 8) + 1;
+	
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// set up default encoding parameters for "fast" mode
+	mixBits		= kDefaultMixBits;
+	mixRes		= kDefaultMixRes;
+	numU = numV = kDefaultNumUV;
+	denShift	= DENSHIFT_DEFAULT;
+	mode		= 0;
+	pbFactor	= 4;
+
+	minBits	= minBits1 = minBits2 = 1ul << 31;
+	
+	// mix the stereo inputs with default mixBits/mixRes
+	switch ( mBitDepth )
+	{
+		case 16:
+			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 20:
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 24:
+			// also extracts the shifted off bytes into the shift buffers
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+		case 32:
+			// also extracts the shifted off bytes into the shift buffers
+			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+	}
+
+	/* speculatively write the bitstream assuming the compressed version will be smaller */
+
+	// write bitstream header and coefs
+	BitBufferWrite( bitstream, 0, 12 );
+	BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+	if ( partialFrame )
+		BitBufferWrite( bitstream, numSamples, 32 );
+	BitBufferWrite( bitstream, mixBits, 8 );
+	BitBufferWrite( bitstream, mixRes, 8 );
+	
+	//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
+	//Assert( (pbFactor < 8) && (numU < 32) );
+	//Assert( (pbFactor < 8) && (numV < 32) );
+
+	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+	BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+	for ( index = 0; index < numU; index++ )
+		BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );
+
+	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+	BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
+	for ( index = 0; index < numV; index++ )
+		BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );
+
+	// if shift active, write the interleaved shift buffers
+	if ( bytesShifted != 0 )
+	{
+		uint32_t		bitShift = bytesShifted * 8;
+
+		//Assert( bitShift <= 16 );
+
+		for ( index = 0; index < (numSamples * 2); index += 2 )
+		{
+			uint32_t			shiftedVal;
+			
+			shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
+			BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
+		}
+	}
+
+	// run the dynamic predictor and lossless compression for the "left" channel
+	// - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0
+	pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+
+	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+	status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+	RequireNoErr( status, goto Exit; );
+
+	// run the dynamic predictor and lossless compression for the "right" channel
+	pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+
+	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+	status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
+	RequireNoErr( status, goto Exit; );
+
+	// do bit requirement calculations
+	minBits1 = bits1 + (numU * sizeof(int16_t) * 8);
+	minBits2 = bits2 + (numV * sizeof(int16_t) * 8);
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8) * 2);
+
+	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			doEscape = true;
+		}
+
+	}
+
+	if ( doEscape == true )
+	{
+		/* escape */
+
+		// reset bitstream position since we speculatively wrote the compressed version
+		*bitstream = startBits;
+
+		// write escape frame
+		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );
+
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %u vs %u", minBits, (numSamples * mBitDepth * 2) );
+#endif
+	}
+	
+Exit:
+	return status;
+}
+
+/*
+	EncodeStereoEscape()
+	- encode stereo escape frame
+*/
+int32_t ALACEncoder::EncodeStereoEscape( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t numSamples )
+{
+	int16_t *		input16;
+	int32_t *		input32;
+	uint8_t			partialFrame;
+	uint32_t			index;
+
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// write bitstream header
+	BitBufferWrite( bitstream, 0, 12 );
+	BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
+	if ( partialFrame )
+		BitBufferWrite( bitstream, numSamples, 32 );
+
+	// just copy the input data to the output buffer
+	switch ( mBitDepth )
+	{
+		case 16:
+			input16 = (int16_t *) inputBuffer;
+			
+			for ( index = 0; index < (numSamples * stride); index += stride )
+			{
+				BitBufferWrite( bitstream, input16[index + 0], 16 );
+				BitBufferWrite( bitstream, input16[index + 1], 16 );
+			}
+			break;
+		case 20:
+			// mix20() with mixres param = 0 means de-interleave so use it to simplify things
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0 );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				BitBufferWrite( bitstream, mMixBufferU[index], 20 );
+				BitBufferWrite( bitstream, mMixBufferV[index], 20 );
+			}				
+			break;
+		case 24:
+			// mix24() with mixres param = 0 means de-interleave so use it to simplify things
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0, mShiftBufferUV, 0 );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				BitBufferWrite( bitstream, mMixBufferU[index], 24 );
+				BitBufferWrite( bitstream, mMixBufferV[index], 24 );
+			}				
+			break;
+		case 32:
+			input32 = (int32_t *) inputBuffer;
+
+			for ( index = 0; index < (numSamples * stride); index += stride )
+			{
+				BitBufferWrite( bitstream, input32[index + 0], 32 );
+				BitBufferWrite( bitstream, input32[index + 1], 32 );
+			}				
+			break;
+	}
+	
+	return ALAC_noErr;
+}
+
+/*
+	EncodeMono()
+	- encode a mono input buffer
+*/
+int32_t ALACEncoder::EncodeMono( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
+	AGParamRec		agParams;
+	uint32_t	bits1;
+	uint32_t			numU;
+	SearchCoefs		coefsU;
+	uint32_t			dilate;
+	uint32_t			minBits, bestU;
+	uint32_t			minU, maxU;
+	uint32_t			index, index2;
+	uint8_t			bytesShifted;
+	uint32_t			shift;
+	uint32_t			mask;
+	uint32_t			chanBits;
+	uint8_t			pbFactor;
+	uint8_t			partialFrame;
+	int16_t *		input16;
+	int32_t *		input32;
+	uint32_t			escapeBits;
+	bool			doEscape;
+	int32_t		status;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	status = ALAC_noErr;
+	
+	// reload coefs array from previous frame
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+
+	// pick bit depth for actual encoding
+	// - we lop off the lower byte(s) for 24-/32-bit encodings
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	shift = bytesShifted * 8;
+	mask = (1ul << shift) - 1;
+	chanBits = mBitDepth - (bytesShifted * 8);
+
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// convert N-bit data to 32-bit for predictor
+	switch ( mBitDepth )
+	{
+		case 16:
+		{
+			// convert 16-bit data to 32-bit for predictor
+			input16 = (int16_t *) inputBuffer;
+			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
+				mMixBufferU[index] = (int32_t) input16[index2];
+			break;
+		}
+		case 20:
+			// convert 20-bit data to 32-bit for predictor
+			copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+			break;
+		case 24:
+			// convert 24-bit data to 32-bit for the predictor and extract the shifted off byte(s)
+			copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				mShiftBufferUV[index] = (uint16_t)(mMixBufferU[index] & mask);
+				mMixBufferU[index] >>= shift;
+			}
+			break;
+		case 32:
+		{
+			// just copy the 32-bit input data for the predictor and extract the shifted off byte(s)
+			input32 = (int32_t *) inputBuffer;
+
+			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
+			{
+				int32_t			val = input32[index2];
+				
+				mShiftBufferUV[index] = (uint16_t)(val & mask);
+				mMixBufferU[index] = val >> shift;
+			}
+			break;
+		}
+	}
+
+	// brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool)
+	// - run over variations of the encoding params to find the best choice
+	minU		= 4;
+	maxU		= 8;
+	minBits		= 1ul << 31;
+	pbFactor	= 4;
+	
+	minBits	= 1ul << 31;
+	bestU	= minU;
+
+	for ( numU = minU; numU <= maxU; numU += 4 )
+	{
+		BitBuffer		workBits;
+		uint32_t			numBits;
+
+		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
+	
+		dilate = 32;
+		for ( uint32_t converge = 0; converge < 7; converge++ )	
+			pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		dilate = 8;
+		pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+		RequireNoErr( status, goto Exit; );
+
+		numBits = (dilate * bits1) + (16 * numU);
+		if ( numBits < minBits )
+		{
+			bestU	= numU;
+			minBits = numBits;
+		}
+	}             
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	// - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU
+	minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8));
+
+	escapeBits = (numSamples * mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		// write bitstream header
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+		BitBufferWrite( bitstream, 0, 16 );								// mixBits = mixRes = 0
+		
+		// write the params and predictor coefs
+		numU = bestU;
+		BitBufferWrite( bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8 );	// modeU = 0
+		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+		for ( index = 0; index < numU; index++ )
+			BitBufferWrite( bitstream, coefsU[numU-1][index], 16 );
+
+		// if shift active, write the interleaved shift buffers
+		if ( bytesShifted != 0 )
+		{
+			for ( index = 0; index < numSamples; index++ )
+				BitBufferWrite( bitstream, mShiftBufferUV[index], shift );
+		}
+
+		// run the dynamic predictor with the best result
+		pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		// do lossless compression
+		set_standard_ag_params( &agParams, numSamples, numSamples );
+		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+		//AssertNoErr( status );
+
+
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			*bitstream = startBits;		// reset bitstream state
+			doEscape = true;
+		}
+	}
+
+	if ( doEscape == true )
+	{
+		// write bitstream header and coefs
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+
+		// just copy the input data to the output buffer
+		switch ( mBitDepth )
+		{
+			case 16:
+				input16 = (int16_t *) inputBuffer;
+				for ( index = 0; index < (numSamples * stride); index += stride )
+					BitBufferWrite( bitstream, input16[index], 16 );
+				break;
+			case 20:
+				// convert 20-bit data to 32-bit for simplicity
+				copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+				for ( index = 0; index < numSamples; index++ )
+					BitBufferWrite( bitstream, mMixBufferU[index], 20 );
+				break;
+			case 24:
+				// convert 24-bit data to 32-bit for simplicity
+				copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+				for ( index = 0; index < numSamples; index++ )
+					BitBufferWrite( bitstream, mMixBufferU[index], 24 );
+				break;
+			case 32:
+				input32 = (int32_t *) inputBuffer;
+				for ( index = 0; index < (numSamples * stride); index += stride )
+					BitBufferWrite( bitstream, input32[index], 32 );
+				break;
+		}
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %lu vs %lu", minBits, (numSamples * mBitDepth) );
+#endif
+	}
+
+Exit:
+	return status;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	Encode()
+	- encode the next block of samples
+*/
+int32_t ALACEncoder::Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
+                             unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes)
+{
+	uint32_t				numFrames;
+	uint32_t				outputSize;
+	BitBuffer			bitstream;
+	int32_t			status;
+
+	numFrames = *ioNumBytes/theInputFormat.mBytesPerPacket;
+
+	// create a bit buffer structure pointing to our output buffer
+	BitBufferInit( &bitstream, theWriteBuffer, mMaxOutputBytes );
+
+	if ( theInputFormat.mChannelsPerFrame == 2 )
+	{
+		// add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0
+		BitBufferWrite( &bitstream, ID_CPE, 3 );
+		BitBufferWrite( &bitstream, 0, 4 );
+
+		// encode stereo input buffer
+		if ( mFastMode == false )
+			status = this->EncodeStereo( &bitstream, theReadBuffer, 2, 0, numFrames );
+		else
+			status = this->EncodeStereoFast( &bitstream, theReadBuffer, 2, 0, numFrames );
+		RequireNoErr( status, goto Exit; );
+	}
+	else if ( theInputFormat.mChannelsPerFrame == 1 )
+	{
+		// add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0
+		BitBufferWrite( &bitstream, ID_SCE, 3 );
+		BitBufferWrite( &bitstream, 0, 4 );
+
+		// encode mono input buffer
+		status = this->EncodeMono( &bitstream, theReadBuffer, 1, 0, numFrames );
+		RequireNoErr( status, goto Exit; );
+	}
+	else
+	{
+		char *					inputBuffer;
+		uint32_t				tag;
+		uint32_t				channelIndex;
+		uint32_t				inputIncrement;
+		uint8_t				stereoElementTag;
+		uint8_t				monoElementTag;
+		uint8_t				lfeElementTag;
+		
+		inputBuffer		= (char *) theReadBuffer;
+		inputIncrement	= ((mBitDepth + 7) / 8);
+		
+		stereoElementTag	= 0;
+		monoElementTag		= 0;
+		lfeElementTag		= 0;
+
+		for ( channelIndex = 0; channelIndex < theInputFormat.mChannelsPerFrame; )
+		{
+			tag = (sChannelMaps[theInputFormat.mChannelsPerFrame - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3);
+	
+			BitBufferWrite( &bitstream, tag, 3 );
+			switch ( tag )
+			{
+				case ID_SCE:
+					// mono
+					BitBufferWrite( &bitstream, monoElementTag, 4 );
+
+					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+					
+					inputBuffer += inputIncrement;
+					channelIndex++;
+					monoElementTag++;
+					break;
+
+				case ID_CPE:
+					// stereo
+					BitBufferWrite( &bitstream, stereoElementTag, 4 );
+
+					status = this->EncodeStereo( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+
+					inputBuffer += (inputIncrement * 2);
+					channelIndex += 2;
+					stereoElementTag++;
+					break;
+
+				case ID_LFE:
+					// LFE channel (subwoofer)
+					BitBufferWrite( &bitstream, lfeElementTag, 4 );
+
+					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+
+					inputBuffer += inputIncrement;
+					channelIndex++;
+					lfeElementTag++;
+					break;
+
+				default:
+					status = kALAC_ParamError;
+					goto Exit;
+			}
+
+			RequireNoErr( status, goto Exit; );
+		}
+	}
+
+#if VERBOSE_DEBUG
+{
+	// if there is room left in the output buffer, add some random fill data to test decoder
+	int32_t			bitsLeft;
+	int32_t			bytesLeft;
+	
+	bitsLeft = BitBufferGetPosition( &bitstream ) - 3;	// - 3 for ID_END tag
+	bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8);
+	
+	if ( (bytesLeft > 20) && ((bytesLeft & 0x4u) != 0) )
+		AddFiller( &bitstream, bytesLeft );
+}
+#endif
+
+	// add 3-bit frame end tag: ID_END
+	BitBufferWrite( &bitstream, ID_END, 3 );
+
+	// byte-align the output data
+	BitBufferByteAlign( &bitstream, true );
+
+	outputSize = BitBufferGetPosition( &bitstream ) / 8;
+	//Assert( outputSize <= mMaxOutputBytes );
+
+
+	// all good, let iTunes know what happened and remember the total number of input sample frames
+	*ioNumBytes = outputSize;
+	//mEncodedFrames		   	   += encodeMsg->numInputSamples;
+
+	// gather encoding stats
+	mTotalBytesGenerated += outputSize;
+	mMaxFrameBytes = MAX( mMaxFrameBytes, outputSize );
+
+	status = ALAC_noErr;
+
+Exit:
+	return status;
+}
+
+/*
+	Finish()
+	- drain out any leftover samples
+*/
+
+int32_t ALACEncoder::Finish()
+{
+/*	// finalize bit rate statistics
+	if ( mSampleSize.numEntries != 0 )
+		mAvgBitRate = (uint32_t)( (((float)mTotalBytesGenerated * 8.0f) / (float)mSampleSize.numEntries) * ((float)mSampleRate / (float)mFrameSize) );
+	else
+		mAvgBitRate = 0;
+*/
+	return ALAC_noErr;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	GetConfig()
+*/
+void ALACEncoder::GetConfig( ALACSpecificConfig & config )
+{
+	config.frameLength			= Swap32NtoB(mFrameSize);
+	config.compatibleVersion	= (uint8_t) kALACCompatibleVersion;
+	config.bitDepth				= (uint8_t) mBitDepth;
+	config.pb					= (uint8_t) PB0;
+	config.kb					= (uint8_t) KB0;
+	config.mb					= (uint8_t) MB0;
+	config.numChannels			= (uint8_t) mNumChannels;
+	config.maxRun				= Swap16NtoB((uint16_t) MAX_RUN_DEFAULT);
+	config.maxFrameBytes		= Swap32NtoB(mMaxFrameBytes);
+	config.avgBitRate			= Swap32NtoB(mAvgBitRate);
+	config.sampleRate			= Swap32NtoB(mOutputSampleRate);
+}
+
+uint32_t ALACEncoder::GetMagicCookieSize(uint32_t inNumChannels)
+{
+    if (inNumChannels > 2)
+    {
+        return sizeof(ALACSpecificConfig) + kChannelAtomSize + sizeof(ALACAudioChannelLayout);
+    }
+    else
+    {
+        return sizeof(ALACSpecificConfig);
+    }
+}
+
+void ALACEncoder::GetMagicCookie(void * outCookie, uint32_t * ioSize)
+{
+    ALACSpecificConfig theConfig = {0};
+    ALACAudioChannelLayout theChannelLayout = {0};
+    uint8_t theChannelAtom[kChannelAtomSize] = {0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0};
+    uint32_t theCookieSize = sizeof(ALACSpecificConfig);
+    uint8_t * theCookiePointer = (uint8_t *)outCookie;
+    
+    GetConfig(theConfig);
+    if (theConfig.numChannels > 2)
+    {
+        theChannelLayout.mChannelLayoutTag = Swap32NtoB(ALACChannelLayoutTags[theConfig.numChannels - 1]);
+        theCookieSize += (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
+    }
+     if (*ioSize >= theCookieSize)
+    {
+        memcpy(theCookiePointer, &theConfig, sizeof(ALACSpecificConfig));
+        theChannelAtom[3] = (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
+        if (theConfig.numChannels > 2)
+        {
+            theCookiePointer += sizeof(ALACSpecificConfig);
+            memcpy(theCookiePointer, theChannelAtom, kChannelAtomSize);
+            theCookiePointer += kChannelAtomSize;
+            memcpy(theCookiePointer, &theChannelLayout, sizeof(ALACAudioChannelLayout));
+        }
+        *ioSize = theCookieSize;
+    }
+    else
+    {
+        *ioSize = 0; // no incomplete cookies
+    }
+}
+
+/*
+	InitializeEncoder()
+	- initialize the encoder component with the current config
+*/
+int32_t ALACEncoder::InitializeEncoder(AudioFormatDescription theOutputFormat)
+{
+	int32_t			status;
+    
+    mOutputSampleRate = theOutputFormat.mSampleRate;
+    mNumChannels = theOutputFormat.mChannelsPerFrame;
+    switch(theOutputFormat.mFormatFlags)
+    {
+        case 1:
+            mBitDepth = 16;
+            break;
+        case 2:
+            mBitDepth = 20;
+            break;
+        case 3:
+            mBitDepth = 24;
+            break;
+        case 4:
+            mBitDepth = 32;
+            break;
+        default:
+            break;
+    }
+
+	// set up default encoding parameters and state
+	// - note: mFrameSize is set in the constructor or via SetFrameSize() which must be called before this routine
+	for ( uint32_t index = 0; index < kALACMaxChannels; index++ )
+		mLastMixRes[index] = kDefaultMixRes;
+
+	// the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1)
+	// but note that this can be bigger than the input size!
+	// - since we don't yet know what our input format will be, use our max allowed sample size in the calculation
+	mMaxOutputBytes = mFrameSize * mNumChannels * ((10 + kMaxSampleSize) / 8)  + 1;
+
+	// allocate mix buffers
+	mMixBufferU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	mMixBufferV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+
+	// allocate dynamic predictor buffers
+	mPredictorU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	mPredictorV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	
+	// allocate combined shift buffer
+	mShiftBufferUV = (uint16_t *) calloc( mFrameSize * 2 * sizeof(uint16_t),1 );
+	
+	// allocate work buffer for search loop
+	mWorkBuffer = (uint8_t *) calloc( mMaxOutputBytes, 1 );
+
+	RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) &&
+					(mPredictorU != nil) && (mPredictorV != nil) &&
+					(mShiftBufferUV != nil) && (mWorkBuffer != nil ),
+					status = kALAC_MemFullError; goto Exit; );
+
+	status = ALAC_noErr;
+
+
+	// initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio
+	for ( int32_t channel = 0; channel < (int32_t)mNumChannels; channel++ )
+	{
+		for ( int32_t search = 0; search < kALACMaxSearches; search++ )
+		{
+			init_coefs( mCoefsU[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
+			init_coefs( mCoefsV[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
+		}
+	}
+
+Exit:
+	return status;
+}
+
+/*
+	GetSourceFormat()
+	- given the input format, return one of our supported formats
+*/
+void ALACEncoder::GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output )
+{
+	// default is 16-bit native endian
+	// - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense
+	//		   to encode to 16-bit since the source was lossy in the first place
+	// - note: if not a supported bit depth, find the closest supported bit depth to the input one
+	if ( (source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) ||
+		( source->mBitsPerChannel <= 16 ) )
+		mBitDepth = 16;
+	else if ( source->mBitsPerChannel <= 20 )
+		mBitDepth = 20;
+	else if ( source->mBitsPerChannel <= 24 )
+		mBitDepth = 24;
+	else
+		mBitDepth = 32;
+		
+	// we support 16/20/24/32-bit integer data at any sample rate and our target number of channels
+	// and sample rate were specified when we were configured
+	/*
+    MakeUncompressedAudioFormat( mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output );
+     */
+}
+
+
+
+#if VERBOSE_DEBUG
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	AddFiller()
+	- add fill and data stream elements to the bitstream to test the decoder
+*/
+static void AddFiller( BitBuffer * bits, int32_t numBytes )
+{
+	uint8_t		tag;
+	uint32_t		index;
+
+	// out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements
+	numBytes -= 6;
+	if ( numBytes <= 0 )
+		return;
+	
+	// randomly pick Fill or Data Stream Element based on numBytes requested
+	tag = (numBytes & 0x8) ? ID_FIL : ID_DSE;
+
+	BitBufferWrite( bits, tag, 3 );
+	if ( tag == ID_FIL )
+	{
+		// can't write more than 269 bytes in a fill element
+		numBytes = (numBytes > 269) ? 269 : numBytes;
+
+		// fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size
+		if ( numBytes >= 15 )
+		{
+			uint16_t			extensionSize;
+
+			BitBufferWrite( bits, 15, 4 );
+
+			// 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax
+			// - otherwise, there's no way to represent 15
+			// - for example, to really mean 15 bytes you must encode extensionSize = 1
+			// - why it's not like data stream elements I have no idea
+			extensionSize = (numBytes - 15) + 1;
+			Assert( extensionSize <= 255 );
+			BitBufferWrite( bits, extensionSize, 8 );
+		}
+		else
+			BitBufferWrite( bits, numBytes, 4 );
+
+		BitBufferWrite( bits, 0x10, 8 );		// extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000
+		for ( index = 0; index < (numBytes - 1); index++ )
+			BitBufferWrite( bits, 0xa5, 8 );	// fill_byte = b10100101 = 0xa5
+	}
+	else
+	{
+		// can't write more than 510 bytes in a data stream element
+		numBytes = (numBytes > 510) ? 510 : numBytes;
+
+		BitBufferWrite( bits, 0, 4 );			// element instance tag
+		BitBufferWrite( bits, 1, 1 );			// byte-align flag = true
+
+		// data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size
+		if ( numBytes >= 255 )
+		{
+			BitBufferWrite( bits, 255, 8 );
+			BitBufferWrite( bits, numBytes - 255, 8 );
+		}
+		else
+			BitBufferWrite( bits, numBytes, 8 );
+		
+		BitBufferByteAlign( bits, true );		// byte-align with zeros
+
+		for ( index = 0; index < numBytes; index++ )
+			BitBufferWrite( bits, 0x5a, 8 );
+	}
+}
+
+#endif	/* VERBOSE_DEBUG */
diff --git a/libaudiofile/alac/ALACEncoder.h b/libaudiofile/alac/ALACEncoder.h
new file mode 100644
index 0000000..0e6c689
--- /dev/null
+++ b/libaudiofile/alac/ALACEncoder.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACEncoder.h
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "ALACAudioTypes.h"
+
+
+struct BitBuffer;
+
+class ALACEncoder
+{
+	public:
+		ALACEncoder();
+		virtual ~ALACEncoder();
+
+		virtual int32_t	Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
+                                   unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes);
+		virtual int32_t	Finish( );
+
+		void				SetFastMode( bool fast ) { mFastMode = fast; };
+
+		// this must be called *before* InitializeEncoder()
+		void				SetFrameSize( uint32_t frameSize ) { mFrameSize = frameSize; };
+
+		void				GetConfig( ALACSpecificConfig & config );
+        uint32_t            GetMagicCookieSize(uint32_t inNumChannels);
+        void				GetMagicCookie( void * config, uint32_t * ioSize ); 
+
+        virtual int32_t	InitializeEncoder(AudioFormatDescription theOutputFormat);
+
+    protected:
+		virtual void		GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output );
+		
+		int32_t			EncodeStereo( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+		int32_t			EncodeStereoFast( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+		int32_t			EncodeStereoEscape( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t numSamples );
+		int32_t			EncodeMono( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+
+
+		// ALAC encoder parameters
+		int16_t					mBitDepth;
+		bool					mFastMode;
+
+		// encoding state
+		int16_t					mLastMixRes[kALACMaxChannels];
+
+		// encoding buffers
+		int32_t *				mMixBufferU;
+		int32_t *				mMixBufferV;
+		int32_t *				mPredictorU;
+		int32_t *				mPredictorV;
+		uint16_t *				mShiftBufferUV;
+		
+		uint8_t *					mWorkBuffer;
+
+		// per-channel coefficients buffers
+		int16_t					mCoefsU[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];
+		int16_t					mCoefsV[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];
+
+		// encoding statistics
+		uint32_t					mTotalBytesGenerated;
+		uint32_t					mAvgBitRate;
+		uint32_t					mMaxFrameBytes;
+        uint32_t                  mFrameSize;
+        uint32_t                  mMaxOutputBytes;
+        uint32_t                  mNumChannels;
+        uint32_t                  mOutputSampleRate;		
+};
diff --git a/libaudiofile/alac/EndianPortable.c b/libaudiofile/alac/EndianPortable.c
new file mode 100644
index 0000000..261a87d
--- /dev/null
+++ b/libaudiofile/alac/EndianPortable.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+//
+//  EndianPortable.c
+//
+//  Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#include "config.h"
+#include "EndianPortable.h"
+
+#define BSWAP16(x) (((x << 8) | ((x >> 8) & 0x00ff)))
+#define BSWAP32(x) (((x << 24) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff)))
+#define BSWAP64(x) ((((int64_t)x << 56) | (((int64_t)x << 40) & 0x00ff000000000000LL) | \
+                    (((int64_t)x << 24) & 0x0000ff0000000000LL) | (((int64_t)x << 8) & 0x000000ff00000000LL) | \
+                    (((int64_t)x >> 8) & 0x00000000ff000000LL) | (((int64_t)x >> 24) & 0x0000000000ff0000LL) | \
+                    (((int64_t)x >> 40) & 0x000000000000ff00LL) | (((int64_t)x >> 56) & 0x00000000000000ffLL)))
+
+#ifndef WORDS_BIGENDIAN
+#define TARGET_RT_LITTLE_ENDIAN 1
+#endif
+
+uint16_t Swap16NtoB(uint16_t inUInt16)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP16(inUInt16);
+#else
+    return inUInt16;
+#endif
+}
+
+uint16_t Swap16BtoN(uint16_t inUInt16)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP16(inUInt16);
+#else
+    return inUInt16;
+#endif
+}
+
+uint32_t Swap32NtoB(uint32_t inUInt32)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP32(inUInt32);
+#else
+    return inUInt32;
+#endif
+}
+
+uint32_t Swap32BtoN(uint32_t inUInt32)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP32(inUInt32);
+#else
+    return inUInt32;
+#endif
+}
+
+uint64_t Swap64BtoN(uint64_t inUInt64)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP64(inUInt64);
+#else
+    return inUInt64;
+#endif
+}
+
+uint64_t Swap64NtoB(uint64_t inUInt64)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP64(inUInt64);
+#else
+    return inUInt64;
+#endif
+}
+
+float SwapFloat32BtoN(float in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		float f;
+		int32_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP32(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+float SwapFloat32NtoB(float in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		float f;
+		int32_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP32(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+double SwapFloat64BtoN(double in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		double f;
+		int64_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP64(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+double SwapFloat64NtoB(double in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		double f;
+		int64_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP64(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+void Swap16(uint16_t * inUInt16)
+{
+	*inUInt16 = BSWAP16(*inUInt16);
+}
+
+void Swap24(uint8_t * inUInt24)
+{
+	uint8_t tempVal = inUInt24[0];
+	inUInt24[0] = inUInt24[2];
+	inUInt24[2] = tempVal;
+}
+
+void Swap32(uint32_t * inUInt32)
+{
+	*inUInt32 = BSWAP32(*inUInt32);
+}
+
diff --git a/libaudiofile/alac/EndianPortable.h b/libaudiofile/alac/EndianPortable.h
new file mode 100644
index 0000000..f7f50a7
--- /dev/null
+++ b/libaudiofile/alac/EndianPortable.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+//
+//  EndianPortable.h
+//
+//  Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#ifndef _EndianPortable_h
+#define _EndianPortable_h
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint16_t Swap16NtoB(uint16_t inUInt16);
+uint16_t Swap16BtoN(uint16_t inUInt16);
+
+uint32_t Swap32NtoB(uint32_t inUInt32);
+uint32_t Swap32BtoN(uint32_t inUInt32);
+
+uint64_t Swap64BtoN(uint64_t inUInt64);
+uint64_t Swap64NtoB(uint64_t inUInt64);
+
+float SwapFloat32BtoN(float in);
+float SwapFloat32NtoB(float in);
+
+double SwapFloat64BtoN(double in);
+double SwapFloat64NtoB(double in);
+
+void Swap16(uint16_t * inUInt16);
+void Swap24(uint8_t * inUInt24);
+void Swap32(uint32_t * inUInt32);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libaudiofile/alac/Makefile.am b/libaudiofile/alac/Makefile.am
new file mode 100644
index 0000000..08f2a74
--- /dev/null
+++ b/libaudiofile/alac/Makefile.am
@@ -0,0 +1,31 @@
+noinst_LTLIBRARIES = libalac.la
+
+libalac_la_SOURCES = \
+	ag_dec.c \
+	ag_enc.c \
+	aglib.h \
+	ALACAudioTypes.h \
+	ALACBitUtilities.c \
+	ALACBitUtilities.h \
+	ALACDecoder.cpp \
+	ALACDecoder.h \
+	ALACEncoder.cpp \
+	ALACEncoder.h \
+	dp_dec.c \
+	dp_enc.c \
+	dplib.h \
+	EndianPortable.c \
+	EndianPortable.h \
+	matrix_dec.c \
+	matrix_enc.c \
+	matrixlib.h
+
+AM_CFLAGS = \
+	-DNDEBUG \
+	-Wall \
+	-Wno-multichar \
+	$(COVERAGE_CFLAGS) \
+	-fvisibility=hidden
+AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden
+
+CLEANFILES = *.gcda *.gcno
diff --git a/libaudiofile/alac/ag_dec.c b/libaudiofile/alac/ag_dec.c
new file mode 100644
index 0000000..df44ff2
--- /dev/null
+++ b/libaudiofile/alac/ag_dec.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ag_dec.c
+	
+	Contains:   Adaptive Golomb decode routines.
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "aglib.h"
+#include "ALACBitUtilities.h"
+#include "ALACAudioTypes.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CODE_TO_LONG_MAXBITS	32
+#define N_MAX_MEAN_CLAMP		0xffff
+#define N_MEAN_CLAMP_VAL		0xffff
+#define REPORT_VAL  40
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
+	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
+	if it is ugly but the performance gains are well worth it.
+	- WSK 5/19/04
+*/
+
+void set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth)
+{
+	/* Use
+		fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data,
+		but use
+		fullwidth = full image width, sectorwidth = sector (patch) width
+		for such as image (2-dim.) data.
+	*/
+	set_ag_params( params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT );
+}
+
+void set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun)
+{
+	params->mb = params->mb0 = m;
+	params->pb = p;
+	params->kb = k;
+	params->wb = (1u<<params->kb)-1;
+	params->qb = QB-params->pb; 
+	params->fw = f;
+	params->sw = s;
+	params->maxrun = maxrun;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+
+// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
+static inline int32_t lead( int32_t m )
+{
+	long j;
+	unsigned long c = (1ul << 31);
+
+	for(j=0; j < 32; j++)
+	{
+		if((c & m) != 0)
+			break;
+		c >>= 1;
+	}
+	return (j);
+}
+
+#define arithmin(a, b) ((a) < (b) ? (a) : (b))
+
+static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
+{
+    int32_t result;
+
+    x += 3;
+    result = lead(x);
+
+    return 31 - result;
+}
+
+static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer )
+{
+	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
+	uint32_t		value;
+	
+	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
+			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
+	return value;
+
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+#define get_next_fromlong(inlong, suff)		((inlong) >> (32 - (suff)))
+
+
+static inline uint32_t ALWAYS_INLINE
+getstreambits( uint8_t *in, int32_t bitoffset, int32_t numbits )
+{
+	uint32_t	load1, load2;
+	uint32_t	byteoffset = bitoffset / 8;
+	uint32_t	result;
+	
+	//Assert( numbits <= 32 );
+
+	load1 = read32bit( in + byteoffset );
+
+	if ( (numbits + (bitoffset & 0x7)) > 32)
+	{
+		int32_t load2shift;
+
+		result = load1 << (bitoffset & 0x7);
+		load2 = (uint32_t) in[byteoffset+4];
+		load2shift = (8-(numbits + (bitoffset & 0x7)-32));
+		load2 >>= load2shift;
+		result >>= (32-numbits);
+		result |= load2;		
+	}
+	else
+	{
+		result = load1 >> (32-numbits-(bitoffset & 7));
+	}
+
+	// a shift of >= "the number of bits in the type of the value being shifted" results in undefined
+	// behavior so don't try to shift by 32
+	if ( numbits != (sizeof(result) * 8) )
+		result &= ~(0xfffffffful << numbits);
+	
+	return result;
+}
+
+
+static inline int32_t dyn_get(unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k)
+{
+    uint32_t	tempbits = *bitPos;
+    uint32_t		result;
+    uint32_t		pre = 0, v;
+    uint32_t		streamlong;
+
+	streamlong = read32bit( in + (tempbits >> 3) );
+    streamlong <<= (tempbits & 7);
+
+    /* find the number of bits in the prefix */ 
+    {
+        uint32_t	notI = ~streamlong;
+    	pre = lead( notI);
+    }
+
+    if(pre >= MAX_PREFIX_16)
+    {
+        pre = MAX_PREFIX_16;
+        tempbits += pre;
+        streamlong <<= pre;
+        result = get_next_fromlong(streamlong,MAX_DATATYPE_BITS_16);
+        tempbits += MAX_DATATYPE_BITS_16;
+
+    }
+    else
+    {
+        // all of the bits must fit within the long we have loaded
+        //Assert(pre+1+k <= 32);
+
+        tempbits += pre;
+        tempbits += 1;
+        streamlong <<= pre+1;
+        v = get_next_fromlong(streamlong, k);
+        tempbits += k;
+    
+        result = pre*m + v-1;
+
+        if(v<2) {
+            result -= (v-1);
+            tempbits -= 1;
+        }
+    }
+
+    *bitPos = tempbits;
+    return result;
+}
+
+
+static inline int32_t dyn_get_32bit( uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits )
+{
+	uint32_t	tempbits = *bitPos;
+	uint32_t		v;
+	uint32_t		streamlong;
+	uint32_t		result;
+	
+	streamlong = read32bit( in + (tempbits >> 3) );
+	streamlong <<= (tempbits & 7);
+
+	/* find the number of bits in the prefix */ 
+	{
+		uint32_t notI = ~streamlong;
+		result = lead( notI);
+	}
+	
+	if(result >= MAX_PREFIX_32)
+	{
+		result = getstreambits(in, tempbits+MAX_PREFIX_32, maxbits);
+		tempbits += MAX_PREFIX_32 + maxbits;
+	}
+	else
+	{		
+		/* all of the bits must fit within the long we have loaded*/
+		//Assert(k<=14);
+		//Assert(result<MAX_PREFIX_32);
+		//Assert(result+1+k <= 32);
+		
+		tempbits += result;
+		tempbits += 1;
+		
+		if (k != 1)
+		{
+			streamlong <<= result+1;
+			v = get_next_fromlong(streamlong, k);
+			tempbits += k;
+			tempbits -= 1;
+			result = result*m;
+			
+			if(v>=2)
+			{
+				result += (v-1);
+				tempbits += 1;
+			}
+		}
+	}
+
+	*bitPos = tempbits;
+
+	return result;
+}
+
+int32_t dyn_decomp( AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits )
+{
+    uint8_t 		*in;
+    int32_t			*outPtr = pc;
+    uint32_t 	bitPos, startPos, maxPos;
+    uint32_t		j, m, k, n, c, mz;
+    int32_t			del, zmode;
+    uint32_t 	mb;
+    uint32_t	pb_local = params->pb;
+    uint32_t	kb_local = params->kb;
+    uint32_t	wb_local = params->wb;
+    int32_t				status;
+
+	RequireAction( (bitstream != nil) && (pc != nil) && (outNumBits != nil), return kALAC_ParamError; );
+	*outNumBits = 0;
+
+	in = bitstream->cur;
+	startPos = bitstream->bitIndex;
+	maxPos = bitstream->byteSize * 8;
+	bitPos = startPos;
+
+    mb = params->mb0;
+    zmode = 0;
+
+    c = 0;
+	status = ALAC_noErr;
+
+    while (c < numSamples)
+    {
+		// bail if we've run off the end of the buffer
+    	RequireAction( bitPos < maxPos, status = kALAC_ParamError; goto Exit; );
+
+        m = (mb)>>QBSHIFT;
+        k = lg3a(m);
+
+        k = arithmin(k, kb_local);
+        m = (1<<k)-1;
+        
+		n = dyn_get_32bit( in, &bitPos, m, k, maxSize );
+
+        // least significant bit is sign bit
+        {
+        	uint32_t	ndecode = n + zmode;
+            int32_t		multiplier = (- (ndecode&1));
+
+            multiplier |= 1;
+            del = ((ndecode+1) >> 1) * (multiplier);
+        }
+
+        *outPtr++ = del;
+
+        c++;
+
+        mb = pb_local*(n+zmode) + mb - ((pb_local*mb)>>QBSHIFT);
+
+		// update mean tracking
+		if (n > N_MAX_MEAN_CLAMP)
+			mb = N_MEAN_CLAMP_VAL;
+
+        zmode = 0;
+
+        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
+        {
+            zmode = 1;
+            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
+            mz = ((1<<k)-1) & wb_local;
+
+            n = dyn_get(in, &bitPos, mz, k);
+
+            RequireAction(c+n <= numSamples, status = kALAC_ParamError; goto Exit; );
+
+            for(j=0; j < n; j++)
+            {
+                *outPtr++ = 0;
+                ++c;                    
+            }
+
+            if(n >= 65535)
+            	zmode = 0;
+
+            mb = 0;
+        }
+    }
+
+Exit:
+	*outNumBits = (bitPos - startPos);
+	BitBufferAdvance( bitstream, *outNumBits );
+	RequireAction( bitstream->cur <= bitstream->end, status = kALAC_ParamError; );
+
+    return status;
+}
diff --git a/libaudiofile/alac/ag_enc.c b/libaudiofile/alac/ag_enc.c
new file mode 100644
index 0000000..79a5870
--- /dev/null
+++ b/libaudiofile/alac/ag_enc.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ag_enc.c
+	
+	Contains:   Adaptive Golomb encode routines.
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "aglib.h"
+#include "ALACBitUtilities.h"
+#include "EndianPortable.h"
+#include "ALACAudioTypes.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CODE_TO_LONG_MAXBITS	32
+#define N_MAX_MEAN_CLAMP		0xffff
+#define N_MEAN_CLAMP_VAL		0xffff
+#define REPORT_VAL  40
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+
+/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
+	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
+	if it is ugly but the performance gains are well worth it.
+	- WSK 5/19/04
+*/
+
+// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
+static inline int32_t lead( int32_t m )
+{
+	long j;
+	unsigned long c = (1ul << 31);
+
+	for(j=0; j < 32; j++)
+	{
+		if((c & m) != 0)
+			break;
+		c >>= 1;
+	}
+	return (j);
+}
+
+#define arithmin(a, b) ((a) < (b) ? (a) : (b))
+
+static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
+{
+    int32_t result;
+
+    x += 3;
+    result = lead(x);
+
+    return 31 - result;
+}
+
+static inline int32_t ALWAYS_INLINE abs_func( int32_t a )
+{
+	// note: the CW PPC intrinsic __abs() turns into these instructions so no need to try and use it
+	int32_t isneg  = a >> 31;
+	int32_t xorval = a ^ isneg;
+	int32_t result = xorval-isneg;
+	
+	return result;	
+}
+
+static inline uint32_t ALWAYS_INLINE unaligned_read32_be(const uint8_t *buffer)
+{
+	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
+	uint32_t		value;
+	
+	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
+			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
+	return value;
+}
+
+static inline void ALWAYS_INLINE unaligned_write32_be(uint8_t *buffer, uint32_t value)
+{
+	buffer[0] = value >> 24;
+	buffer[1] = (value >> 16) & 0xff;
+	buffer[2] = (value >> 8) & 0xff;
+	buffer[3] = value & 0xff;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+static inline int32_t dyn_code(int32_t m, int32_t k, int32_t n, uint32_t *outNumBits)
+{
+	uint32_t 	div, mod, de;
+	uint32_t	numBits;
+	uint32_t	value;
+
+	//Assert( n >= 0 );
+
+	div = n/m;
+
+	if(div >= MAX_PREFIX_16)
+	{
+		numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
+		value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;
+	}
+	else
+	{
+		mod = n%m;
+		de = (mod == 0);
+		numBits = div + k + 1 - de;
+		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;
+
+		// if coding this way is bigger than doing escape, then do escape
+		if (numBits > MAX_PREFIX_16 + MAX_DATATYPE_BITS_16)
+		{
+		    numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
+		    value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;            
+		}
+	}
+	
+	*outNumBits = numBits;
+
+	return (int32_t) value;
+}
+
+
+static inline int32_t dyn_code_32bit(int32_t maxbits, uint32_t m, uint32_t k, uint32_t n, uint32_t *outNumBits, uint32_t *outValue, uint32_t *overflow, uint32_t *overflowbits)
+{
+	uint32_t 	div, mod, de;
+	uint32_t	numBits;
+	uint32_t	value;
+	int32_t			didOverflow = 0;
+
+	div = n/m;
+
+	if (div < MAX_PREFIX_32)
+	{
+		mod = n - (m * div);
+
+		de = (mod == 0);
+		numBits = div + k + 1 - de;
+		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;		
+		if (numBits > 25)
+			goto codeasescape;
+	}
+	else
+	{
+codeasescape:
+		numBits = MAX_PREFIX_32;
+		value = (((1<<MAX_PREFIX_32)-1));
+		*overflow = n;
+		*overflowbits = maxbits;
+		didOverflow = 1;
+	}
+	
+	*outNumBits = numBits;
+	*outValue = value;
+
+	return didOverflow;
+}
+
+
+static inline void ALWAYS_INLINE dyn_jam_noDeref(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
+{
+	uint8_t		*i = out + (bitPos >> 3);
+	uint32_t	mask;
+	uint32_t	curr;
+	uint32_t	shift;
+
+	//Assert( numBits <= 32 );
+
+	curr = unaligned_read32_be(i);
+
+	shift = 32 - (bitPos & 7) - numBits;
+
+	mask = ~0u >> (32 - numBits);		// mask must be created in two steps to avoid compiler sequencing ambiguity
+	mask <<= shift;
+
+	value  = (value << shift) & mask;
+	value |= curr & ~mask;
+	
+	unaligned_write32_be(i, value);
+}
+
+
+static inline void ALWAYS_INLINE dyn_jam_noDeref_large(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
+{
+	uint8_t		*i = out + (bitPos>>3);
+	uint32_t	w;
+	uint32_t	curr;
+	uint32_t	mask;
+	int32_t			shiftvalue = (32 - (bitPos&7) - numBits);
+	
+	//Assert(numBits <= 32);
+
+	curr = unaligned_read32_be(i);
+
+	if (shiftvalue < 0)
+	{
+		uint8_t 	tailbyte;
+		uint8_t 	*tailptr;
+
+		w = value >> -shiftvalue;
+		mask = ~0u >> -shiftvalue;
+		w |= (curr & ~mask);
+
+		tailptr = i + 4;
+		tailbyte = (value << ((8+shiftvalue))) & 0xff;
+		*tailptr = (uint8_t)tailbyte;
+	}
+	else
+	{
+		mask = ~0u >> (32 - numBits);
+		mask <<= shiftvalue;			// mask must be created in two steps to avoid compiler sequencing ambiguity
+
+		w  = (value << shiftvalue) & mask;
+		w |= curr & ~mask;
+	}
+	
+	unaligned_write32_be(i, w);
+}
+
+
+int32_t dyn_comp( AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits )
+{
+    unsigned char *		out;
+    uint32_t		bitPos, startPos;
+    uint32_t			m, k, n, c, mz, nz;
+    uint32_t		numBits;
+    uint32_t			value;
+    int32_t				del, zmode;
+	uint32_t		overflow, overflowbits;
+    int32_t					status;
+
+    // shadow the variables in params so there's not the dereferencing overhead
+    uint32_t		mb, pb, kb, wb;
+    int32_t					rowPos = 0;
+    int32_t					rowSize = params->sw;
+    int32_t					rowJump = (params->fw) - rowSize;
+    int32_t *			inPtr = pc;
+
+	*outNumBits = 0;
+	RequireAction( (bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError; );
+
+	out = bitstream->cur;
+	startPos = bitstream->bitIndex;
+    bitPos = startPos;
+
+    mb = params->mb = params->mb0;
+    pb = params->pb;
+    kb = params->kb;
+    wb = params->wb;
+    zmode = 0;
+
+    c=0;
+	status = ALAC_noErr;
+
+    while (c < numSamples)
+    {
+        m  = mb >> QBSHIFT;
+        k = lg3a(m);
+        if ( k > kb)
+        {
+        	k = kb;
+        }
+        m = (1<<k)-1;
+
+        del = *inPtr++;
+        rowPos++;
+
+        n = (abs_func(del) << 1) - ((del >> 31) & 1) - zmode;
+		//Assert( 32-lead(n) <= bitSize );
+
+		if ( dyn_code_32bit(bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits) )
+		{
+			dyn_jam_noDeref(out, bitPos, numBits, value);
+			bitPos += numBits;			
+			dyn_jam_noDeref_large(out, bitPos, overflowbits, overflow);			
+			bitPos += overflowbits;
+		}
+		else
+		{
+			dyn_jam_noDeref(out, bitPos, numBits, value);
+			bitPos += numBits;
+		}
+      
+        c++;
+        if ( rowPos >= rowSize)
+        {
+        	rowPos = 0;
+        	inPtr += rowJump;
+        }
+
+        mb = pb * (n + zmode) + mb - ((pb *mb)>>QBSHIFT);
+
+		// update mean tracking if it's overflowed
+		if (n > N_MAX_MEAN_CLAMP)
+			mb = N_MEAN_CLAMP_VAL;
+
+        zmode = 0;
+
+        RequireAction(c <= numSamples, status = kALAC_ParamError; goto Exit; );
+
+        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
+        {
+            zmode = 1;
+            nz = 0;
+
+            while(c<numSamples && *inPtr == 0)
+            {
+            	/* Take care of wrap-around globals. */
+                ++inPtr;
+                ++nz;
+                ++c;
+                if ( ++rowPos >= rowSize)
+                {
+                	rowPos = 0;
+                	inPtr += rowJump;
+                }
+
+                if(nz >= 65535)
+                {
+                	zmode = 0;
+                	break;
+                }
+            }
+
+            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
+            mz = ((1<<k)-1) & wb;
+
+            value = dyn_code(mz, k, nz, &numBits);
+            dyn_jam_noDeref(out, bitPos, numBits, value);
+            bitPos += numBits;
+
+            mb = 0;
+        }
+    }
+
+    *outNumBits = (bitPos - startPos);
+	BitBufferAdvance( bitstream, *outNumBits );
+
+Exit:
+	return status;
+}
diff --git a/libaudiofile/alac/aglib.h b/libaudiofile/alac/aglib.h
new file mode 100644
index 0000000..dc4ff8f
--- /dev/null
+++ b/libaudiofile/alac/aglib.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		aglib.h
+	
+	Copyright:	(C) 2001-2011 Apple, Inc.
+*/
+
+#ifndef AGLIB_H
+#define AGLIB_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define QBSHIFT 9
+#define QB (1<<QBSHIFT)
+#define PB0 40
+#define MB0 10
+#define KB0 14
+#define MAX_RUN_DEFAULT 255
+
+#define MMULSHIFT 2
+#define MDENSHIFT (QBSHIFT - MMULSHIFT - 1)
+#define MOFF ((1<<(MDENSHIFT-2)))
+
+#define BITOFF 24
+
+/* Max. prefix of 1's. */
+#define MAX_PREFIX_16			9
+#define MAX_PREFIX_TOLONG_16	15
+#define MAX_PREFIX_32			9
+
+/* Max. bits in 16-bit data type */
+#define MAX_DATATYPE_BITS_16	16
+
+typedef struct AGParamRec
+{
+    uint32_t mb, mb0, pb, kb, wb, qb;
+    uint32_t fw, sw;
+
+    uint32_t maxrun;
+
+    // fw = 1, sw = 1;
+
+} AGParamRec, *AGParamRecPtr;
+
+struct BitBuffer;
+
+void	set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth);
+void	set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun);
+
+int32_t		dyn_comp(AGParamRecPtr params, int32_t * pc, struct BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits);
+int32_t		dyn_decomp(AGParamRecPtr params, struct BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //#ifndef AGLIB_H
diff --git a/libaudiofile/alac/dp_dec.c b/libaudiofile/alac/dp_dec.c
new file mode 100644
index 0000000..d153025
--- /dev/null
+++ b/libaudiofile/alac/dp_dec.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dp_dec.c
+
+	Contains:	Dynamic Predictor decode routines
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+
+#include "dplib.h"
+#include <string.h>
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
+// align loops to a 16 byte boundary to make the G5 happy
+#pragma function_align 16
+#define LOOP_ALIGN			asm { align 16 }
+#else
+#define LOOP_ALIGN
+#endif
+
+static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
+{
+    int32_t negishift;
+	
+    negishift = ((uint32_t)-i) >> 31;
+    return negishift | (i >> 31);
+}
+
+void unpc_block( int32_t * pc1, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
+{
+	register int16_t	a0, a1, a2, a3;
+	register int32_t	b0, b1, b2, b3;
+	int32_t					j, k, lim;
+	int32_t				sum1, sg, sgn, top, dd;
+	int32_t *			pout;
+	int32_t				del, del0;
+	uint32_t			chanshift = 32 - chanbits;
+	int32_t				denhalf = 1<<(denshift-1);
+
+	out[0] = pc1[0];
+	if ( numactive == 0 )
+	{
+		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
+		if ( (num > 1)  && (pc1 != out) )
+			memcpy( &out[1], &pc1[1], (num - 1) * sizeof(int32_t) );
+		return;
+	}
+	if ( numactive == 31 )
+	{
+		// short-circuit if numactive == 31
+		int32_t		prev;
+		
+		/*	this code is written such that the in/out buffers can be the same
+			to conserve buffer space on embedded devices like the iPod
+			
+			(original code)
+			for ( j = 1; j < num; j++ )
+				del = pc1[j] + out[j-1];
+				out[j] = (del << chanshift) >> chanshift;
+		*/
+		prev = out[0];
+		for ( j = 1; j < num; j++ )
+		{
+			del = pc1[j] + prev;
+			prev = (del << chanshift) >> chanshift;
+			out[j] = prev;
+		}
+		return;
+	}
+
+	for ( j = 1; j <= numactive; j++ )
+	{
+		del = pc1[j] + out[j-1];
+		out[j] = (del << chanshift) >> chanshift;
+	}
+
+	lim = numactive + 1;
+
+	if ( numactive == 4 )
+	{
+		// optimization for numactive == 4
+		register int16_t	a0, a1, a2, a3;
+		register int32_t	b0, b1, b2, b3;
+
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = out[j - lim];
+			pout = out + j - 1;
+
+			b0 = top - pout[0];
+			b1 = top - pout[-1];
+			b2 = top - pout[-2];
+			b3 = top - pout[-3];
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int(del);
+			del += top + sum1;
+
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+	}
+	else if ( numactive == 8 )
+	{
+		register int16_t	a4, a5, a6, a7;
+		register int32_t	b4, b5, b6, b7;
+
+		// optimization for numactive == 8
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+		a4 = coefs[4];
+		a5 = coefs[5];
+		a6 = coefs[6];
+		a7 = coefs[7];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = out[j - lim];
+			pout = out + j - 1;
+
+			b0 = top - (*pout--);
+			b1 = top - (*pout--);
+			b2 = top - (*pout--);
+			b3 = top - (*pout--);
+			b4 = top - (*pout--);
+			b5 = top - (*pout--);
+			b6 = top - (*pout--);
+			b7 = top - (*pout);
+			pout += 8;
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
+					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int(del);
+			del += top + sum1;
+
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				sgn = sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				sgn = -sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+		coefs[4] = a4;
+		coefs[5] = a5;
+		coefs[6] = a6;
+		coefs[7] = a7;
+	}
+	else
+	{
+		// general case
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			sum1 = 0;
+			pout = out + j - 1;
+			top = out[j-lim];
+
+			for ( k = 0; k < numactive; k++ )
+				sum1 += coefs[k] * (pout[-k] - top);
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int( del );
+			del += top + ((sum1 + denhalf) >> denshift);
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pout[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] -= sgn;
+					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
+					if ( del0 <= 0 )
+						break;
+				}
+			}
+			else if ( sg < 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pout[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] += sgn;
+					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
+					if ( del0 >= 0 )
+						break;
+				}
+			}
+		}
+	}
+}
diff --git a/libaudiofile/alac/dp_enc.c b/libaudiofile/alac/dp_enc.c
new file mode 100644
index 0000000..869104c
--- /dev/null
+++ b/libaudiofile/alac/dp_enc.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dp_enc.c
+
+	Contains:	Dynamic Predictor encode routines
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "dplib.h"
+#include <string.h>
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
+// align loops to a 16 byte boundary to make the G5 happy
+#pragma function_align 16
+#define LOOP_ALIGN			asm { align 16 }
+#else
+#define LOOP_ALIGN
+#endif
+
+void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs )
+{
+	int32_t		k;
+	int32_t		den = 1 << denshift;
+
+	coefs[0] = (AINIT * den) >> 4;
+	coefs[1] = (BINIT * den) >> 4;
+	coefs[2] = (CINIT * den) >> 4;
+	for ( k = 3; k < numPairs; k++ )
+		coefs[k]  = 0;
+}
+
+void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs )
+{
+	int32_t k;
+
+	for ( k = 0; k < numPairs; k++ )
+		dstCoefs[k] = srcCoefs[k];
+}
+
+static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
+{
+    int32_t negishift;
+	
+    negishift = ((uint32_t)-i) >> 31;
+    return negishift | (i >> 31);
+}
+
+void pc_block( int32_t * in, int32_t * pc1, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
+{
+	register int16_t	a0, a1, a2, a3;
+	register int32_t	b0, b1, b2, b3;
+	int32_t					j, k, lim;
+	int32_t *			pin;
+	int32_t				sum1, dd;
+	int32_t				sg, sgn;
+	int32_t				top;
+	int32_t				del, del0;
+	uint32_t			chanshift = 32 - chanbits;
+	int32_t				denhalf = 1 << (denshift - 1);
+
+	pc1[0] = in[0];
+	if ( numactive == 0 )
+	{
+		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
+		if ( (num > 1) && (in != pc1) )
+			memcpy( &pc1[1], &in[1], (num - 1) * sizeof(int32_t) );
+		return;
+	}
+	if ( numactive == 31 )
+	{
+		// short-circuit if numactive == 31
+		for( j = 1; j < num; j++ )
+		{
+			del = in[j] - in[j-1];
+			pc1[j] = (del << chanshift) >> chanshift;
+		}
+		return;
+	}
+	
+	for ( j = 1; j <= numactive; j++ )
+	{
+		del = in[j] - in[j-1];
+		pc1[j] = (del << chanshift) >> chanshift;
+	}
+
+	lim = numactive + 1;
+
+	if ( numactive == 4 )
+	{
+		// optimization for numactive == 4
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			b0 = top - pin[0];
+			b1 = top - pin[-1];
+			b2 = top - pin[-2];
+			b3 = top - pin[-3];
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;
+
+			del = in[j] - top - sum1;
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;	     
+			del0 = del;
+
+			sg = sign_of_int(del);
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+	}
+	else if ( numactive == 8 )
+	{
+		// optimization for numactive == 8
+		register int16_t	a4, a5, a6, a7;
+		register int32_t	b4, b5, b6, b7;
+
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+		a4 = coefs[4];
+		a5 = coefs[5];
+		a6 = coefs[6];
+		a7 = coefs[7];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			b0 = top - (*pin--);
+			b1 = top - (*pin--);
+			b2 = top - (*pin--);
+			b3 = top - (*pin--);
+			b4 = top - (*pin--);
+			b5 = top - (*pin--);
+			b6 = top - (*pin--);
+			b7 = top - (*pin);
+			pin += 8;
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
+					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;
+
+			del = in[j] - top - sum1;
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;	     
+			del0 = del;
+
+			sg = sign_of_int(del);
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				sgn = sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				sgn = -sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+		coefs[4] = a4;
+		coefs[5] = a5;
+		coefs[6] = a6;
+		coefs[7] = a7;
+	}
+	else
+	{
+//pc_block_general:
+		// general case
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			sum1 = 0;
+			for ( k = 0; k < numactive; k++ )
+				sum1 -= coefs[k] * (top - pin[-k]);
+		
+			del = in[j] - top - ((sum1 + denhalf) >> denshift);
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;
+			del0 = del;
+
+			sg = sign_of_int( del );
+			if ( sg > 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pin[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] -= sgn;
+					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
+					if ( del0 <= 0 )
+						break;
+				}
+			}
+			else if ( sg < 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pin[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] += sgn;
+					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
+					if ( del0 >= 0 )
+						break;
+				}
+			}
+		}
+	}
+}
diff --git a/libaudiofile/alac/dplib.h b/libaudiofile/alac/dplib.h
new file mode 100644
index 0000000..9a1ea5b
--- /dev/null
+++ b/libaudiofile/alac/dplib.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dplib.h
+	
+	Contains:	Dynamic Predictor routines
+
+	Copyright:	Copyright (C) 2001-2011 Apple, Inc.
+*/
+
+#ifndef __DPLIB_H__
+#define __DPLIB_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// defines
+
+#define DENSHIFT_MAX  15
+#define DENSHIFT_DEFAULT 9
+#define AINIT 38
+#define BINIT (-29)
+#define CINIT (-2)
+#define NUMCOEPAIRS 16
+
+// prototypes
+
+void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs );
+void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs );
+
+// NOTE: these routines read at least "numactive" samples so the i/o buffers must be at least that big
+
+void pc_block( int32_t * in, int32_t * pc, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );
+void unpc_block( int32_t * pc, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __DPLIB_H__ */
diff --git a/libaudiofile/alac/matrix_dec.c b/libaudiofile/alac/matrix_dec.c
new file mode 100644
index 0000000..b1889b9
--- /dev/null
+++ b/libaudiofile/alac/matrix_dec.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrix_dec.c
+	
+	Contains:	ALAC mixing/matrixing decode routines.
+
+	Copyright:	(c) 2004-2011 Apple, Inc.
+*/
+
+#include "matrixlib.h"
+#include "ALACAudioTypes.h"
+
+// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
+#if TARGET_RT_BIG_ENDIAN
+	#define LBYTE	2
+	#define MBYTE	1
+	#define HBYTE	0
+#else
+	#define LBYTE	0
+	#define MBYTE	1
+	#define HBYTE	2
+#endif
+
+/*
+    There is no plain middle-side option; instead there are various mixing
+    modes including middle-side, each lossless, as embodied in the mix()
+    and unmix() functions.  These functions exploit a generalized middle-side
+    transformation:
+    
+    u := [(rL + (m-r)R)/m];
+    v := L - R;
+    
+    where [ ] denotes integer floor.  The (lossless) inverse is
+    
+    L = u + v - [rV/m];
+    R = L - v;
+*/
+
+// 16-bit routines
+
+void unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int16_t *	op = out;
+	int32_t 		j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+			r = l - v[j];
+
+			op[0] = (int16_t) l;
+			op[1] = (int16_t) r;
+			op += stride;
+		} 
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			op[0] = (int16_t) u[j];
+			op[1] = (int16_t) v[j];
+			op += stride;
+		}
+	}
+}
+
+// 20-bit routines
+// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers
+
+void unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	uint8_t *	op = out;
+	int32_t 		j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+			r = l - v[j];
+
+			l <<= 4;
+			r <<= 4;
+
+			op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+			op += 3;
+
+			op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+			op += (stride - 1) * 3;
+		}
+	}
+	else 
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		val;
+
+			val = u[j] << 4;
+			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+			op += 3;
+
+			val = v[j] << 4;
+			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+
+			op += (stride - 1) * 3;
+		}
+	}
+}
+
+// 24-bit routines
+// - the 24 bits of data are right-justified in the input/output predictor buffers
+
+void unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	uint8_t *	op = out;
+	int32_t			shift = bytesShifted * 8;
+	int32_t		l, r;
+	int32_t 		j, k;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+				r = l - v[j];
+
+				l = (l << shift) | (uint32_t) shiftUV[k + 0];
+				r = (r << shift) | (uint32_t) shiftUV[k + 1];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+				r = l - v[j];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+	}
+	else 
+	{
+		/* Conventional separated stereo. */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = u[j];
+				r = v[j];
+
+				l = (l << shift) | (uint32_t) shiftUV[k + 0];
+				r = (r << shift) | (uint32_t) shiftUV[k + 1];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				int32_t		val;
+
+				val = u[j];
+				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+				op += 3;
+
+				val = v[j];
+				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+	}
+}
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers
+
+void unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	int32_t *	op = out;
+	int32_t			shift = bytesShifted * 8;
+	int32_t		l, r;
+	int32_t 		j, k;
+
+	if ( mixres != 0 )
+	{
+		//Assert( bytesShifted != 0 );
+
+		/* matrixed stereo with shift */
+		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+		{
+			int32_t		lt, rt;
+
+			lt = u[j];
+			rt = v[j];
+			
+			l = lt + rt - ((mixres * rt) >> mixbits);
+			r = l - rt;
+
+			op[0] = (l << shift) | (uint32_t) shiftUV[k + 0];
+			op[1] = (r << shift) | (uint32_t) shiftUV[k + 1];
+			op += stride;
+		} 
+	}
+	else
+	{
+		if ( bytesShifted == 0 )
+		{
+			/* interleaving w/o shift */
+			for ( j = 0; j < numSamples; j++ )
+			{
+				op[0] = u[j];
+				op[1] = v[j];
+				op += stride;
+			}
+		}
+		else
+		{
+			/* interleaving with shift */
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				op[0] = (u[j] << shift) | (uint32_t) shiftUV[k + 0];
+				op[1] = (v[j] << shift) | (uint32_t) shiftUV[k + 1];
+				op += stride;
+			}
+		}
+	}
+}
+
+// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+
+void copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
+{
+	uint8_t *	op = out;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
+{
+	uint8_t *	op = out;
+	int32_t			shiftVal = bytesShifted * 8;
+	int32_t			j;
+
+	//Assert( bytesShifted != 0 );
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		val = (val << shiftVal) | (uint32_t) shift[j];
+
+		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
+{
+	uint8_t *	op = out;
+	int32_t			j;
+
+	// 32-bit predictor values are right-aligned but 20-bit output values should be left-aligned
+	// in the 24-bit output buffer
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		op[HBYTE] = (uint8_t)((val >> 12) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  4) & 0xffu);
+		op[LBYTE] = (uint8_t)((val <<  4) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples )
+{
+	int32_t			i, j;
+
+	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
+	for ( i = 0, j = 0; i < numSamples; i++, j += stride )
+		out[j] = in[i];
+}
+
+void copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
+{
+	int32_t *		op = out;
+	uint32_t		shiftVal = bytesShifted * 8;
+	int32_t				j;
+
+	//Assert( bytesShifted != 0 );
+
+	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
+	for ( j = 0; j < numSamples; j++ )
+	{
+		op[0] = (in[j] << shiftVal) | (uint32_t) shift[j];
+		op += stride;
+	}
+}
diff --git a/libaudiofile/alac/matrix_enc.c b/libaudiofile/alac/matrix_enc.c
new file mode 100644
index 0000000..e194330
--- /dev/null
+++ b/libaudiofile/alac/matrix_enc.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrix_enc.c
+	
+	Contains:	ALAC mixing/matrixing encode routines.
+
+	Copyright:	(c) 2004-2011 Apple, Inc.
+*/
+
+#include "matrixlib.h"
+#include "ALACAudioTypes.h"
+
+// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
+#if TARGET_RT_BIG_ENDIAN
+	#define LBYTE	2
+	#define MBYTE	1
+	#define HBYTE	0
+#else
+	#define LBYTE	0
+	#define MBYTE	1
+	#define HBYTE	2
+#endif
+
+/*
+    There is no plain middle-side option; instead there are various mixing
+    modes including middle-side, each lossless, as embodied in the mix()
+    and unmix() functions.  These functions exploit a generalized middle-side
+    transformation:
+    
+    u := [(rL + (m-r)R)/m];
+    v := L - R;
+    
+    where [ ] denotes integer floor.  The (lossless) inverse is
+    
+    L = u + v - [rV/m];
+    R = L - v;
+*/
+
+// 16-bit routines
+
+void mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int16_t	*	ip = in;
+	int32_t			j;
+
+	if ( mixres != 0 )
+	{
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2;
+
+		/* matrixed stereo */
+		m2 = mod - mixres;
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = (int32_t) ip[0];
+			r = (int32_t) ip[1];
+			ip += stride;
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		}
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			u[j] = (int32_t) ip[0];
+			v[j] = (int32_t) ip[1];
+			ip += stride;
+		}
+	}
+}
+
+// 20-bit routines
+// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers
+
+void mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int32_t		l, r;
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2 = mod - mixres;
+
+		for ( j = 0; j < numSamples; j++ )
+		{
+			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			l = (l << 8) >> 12;
+			ip += 3;
+
+			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			r = (r << 8) >> 12;
+			ip += (stride - 1) * 3;
+
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		} 
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			u[j] = (l << 8) >> 12;
+			ip += 3;
+
+			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			v[j] = (r << 8) >> 12;
+			ip += (stride - 1) * 3;
+		}
+	}
+}
+
+// 24-bit routines
+// - the 24 bits of data are right-justified in the input/output predictor buffers
+
+void mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{	
+	int32_t		l, r;
+	uint8_t *	ip = in;
+	int32_t			shift = bytesShifted * 8;
+	uint32_t	mask  = (1ul << shift) - 1;
+	int32_t			j, k;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2 = mod - mixres;
+
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = (mixres * l + m2 * r) >> mixbits;
+				v[j] = l - r;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				u[j] = (mixres * l + m2 * r) >> mixbits;
+				v[j] = l - r;
+			}
+		}
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = l;
+				v[j] = r;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				u[j] = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				v[j] = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+			}
+		}
+	}
+}
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers
+
+void mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	int32_t	*	ip = in;
+	int32_t			shift = bytesShifted * 8;
+	uint32_t	mask  = (1ul << shift) - 1;
+	int32_t		l, r;
+	int32_t			j, k;
+
+	if ( mixres != 0 )
+	{
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2;
+
+		//Assert( bytesShifted != 0 );
+
+		/* matrixed stereo with shift */
+		m2 = mod - mixres;
+		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+		{
+			l = ip[0];
+			r = ip[1];
+			ip += stride;
+
+			shiftUV[k + 0] = (uint16_t)(l & mask);
+			shiftUV[k + 1] = (uint16_t)(r & mask);
+			
+			l >>= shift;
+			r >>= shift;
+
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		}
+	}
+	else
+	{
+		if ( bytesShifted == 0 )
+		{
+			/* de-interleaving w/o shift */
+			for ( j = 0; j < numSamples; j++ )
+			{
+				u[j] = ip[0];
+				v[j] = ip[1];
+				ip += stride;
+			}
+		}
+		else
+		{
+			/* de-interleaving with shift */
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = ip[0];
+				r = ip[1];
+				ip += stride;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = l;
+				v[j] = r;
+			}
+		}
+	}
+}
+
+// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+
+void copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
+{
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t			val;
+
+		// 20-bit values are left-aligned in the 24-bit input buffer but right-aligned in the 32-bit output buffer
+		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+		out[j] = (val << 8) >> 12;
+		ip += stride * 3;
+	}
+}
+
+void copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
+{
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t			val;
+
+		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+		out[j] = (val << 8) >> 8;
+		ip += stride * 3;
+	}
+}
diff --git a/libaudiofile/alac/matrixlib.h b/libaudiofile/alac/matrixlib.h
new file mode 100644
index 0000000..0a4f371
--- /dev/null
+++ b/libaudiofile/alac/matrixlib.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrixlib.h
+	
+	Contains:	ALAC mixing/matrixing routines to/from 32-bit predictor buffers.
+
+	Copyright:	Copyright (C) 2004 to 2011 Apple, Inc.
+*/
+
+#ifndef __MATRIXLIB_H
+#define __MATRIXLIB_H
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 16-bit routines
+void	mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
+void	unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );
+
+// 20-bit routines
+void	mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
+void	unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );
+
+// 24-bit routines
+// - 24-bit data sometimes compresses better by shifting off the bottom byte so these routines deal with
+//	 the specified "unused lower bytes" in the combined "shift" buffer
+void	mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+void	unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
+				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32-bit but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the combined "shift" buffer
+void	mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+void	unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
+				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+
+// 20/24/32-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+void	copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );
+void	copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );
+
+void	copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );
+void	copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );
+void	copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );
+
+void	copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples );
+void	copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __MATRIXLIB_H */
diff --git a/libaudiofile/audiofile.exports b/libaudiofile/audiofile.exports
new file mode 100644
index 0000000..f11d74a
--- /dev/null
+++ b/libaudiofile/audiofile.exports
@@ -0,0 +1,106 @@
+AUpvfree
+AUpvgetmaxitems
+AUpvgetparam
+AUpvgetval
+AUpvgetvaltype
+AUpvnew
+AUpvsetparam
+AUpvsetval
+AUpvsetvaltype
+afCloseFile
+afFreeFileSetup
+afGetAESChannelData
+afGetByteOrder
+afGetChannels
+afGetCompression
+afGetDataOffset
+afGetFileFormat
+afGetFrameCount
+afGetFrameSize
+afGetInstIDs
+afGetInstParamLong
+afGetInstParams
+afGetLoopCount
+afGetLoopEnd
+afGetLoopEndFrame
+afGetLoopIDs
+afGetLoopMode
+afGetLoopStart
+afGetLoopStartFrame
+afGetLoopTrack
+afGetMarkComment
+afGetMarkIDs
+afGetMarkName
+afGetMarkPosition
+afGetMiscIDs
+afGetMiscSize
+afGetMiscType
+afGetPCMMapping
+afGetRate
+afGetSampleFormat
+afGetTrackBytes
+afGetTrackIDs
+afGetVirtualByteOrder
+afGetVirtualChannels
+afGetVirtualFrameSize
+afGetVirtualPCMMapping
+afGetVirtualSampleFormat
+afIdentifyFD
+afIdentifyNamedFD
+afInitAESChannelData
+afInitAESChannelDataTo
+afInitByteOrder
+afInitChannels
+afInitCompression
+afInitDataOffset
+afInitFileFormat
+afInitFrameCount
+afInitInstIDs
+afInitLoopIDs
+afInitMarkComment
+afInitMarkIDs
+afInitMarkName
+afInitMiscIDs
+afInitMiscSize
+afInitMiscType
+afInitPCMMapping
+afInitRate
+afInitSampleFormat
+afInitTrackIDs
+afNewFileSetup
+afOpenFD
+afOpenFile
+afOpenNamedFD
+afOpenVirtualFile
+afQuery
+afQueryDouble
+afQueryLong
+afQueryPointer
+afReadFrames
+afReadMisc
+afSeekFrame
+afSeekMisc
+afSetAESChannelData
+afSetChannelMatrix
+afSetErrorHandler
+afSetInstParamLong
+afSetInstParams
+afSetLoopCount
+afSetLoopEnd
+afSetLoopEndFrame
+afSetLoopMode
+afSetLoopStart
+afSetLoopStartFrame
+afSetLoopTrack
+afSetMarkPosition
+afSetTrackPCMMapping
+afSetVirtualByteOrder
+afSetVirtualChannels
+afSetVirtualPCMMapping
+afSetVirtualSampleFormat
+afSyncFile
+afTellFrame
+afWriteFrames
+afWriteMisc
+af_virtual_file_destroy
+af_virtual_file_new
diff --git a/libaudiofile/audiofile.h b/libaudiofile/audiofile.h
new file mode 100644
index 0000000..087c312
--- /dev/null
+++ b/libaudiofile/audiofile.h
@@ -0,0 +1,612 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, 2010-2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	audiofile.h
+
+	This file contains the public interfaces to the Audio File Library.
+*/
+
+#ifndef AUDIOFILE_H
+#define AUDIOFILE_H
+
+#include <aupvlist.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LIBAUDIOFILE_MAJOR_VERSION 0
+#define LIBAUDIOFILE_MINOR_VERSION 3
+#define LIBAUDIOFILE_MICRO_VERSION 6
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
+#define AFAPI __attribute__((visibility("default")))
+#else
+#define AFAPI
+#endif
+
+typedef struct _AFvirtualfile AFvirtualfile;
+
+typedef struct _AFfilesetup *AFfilesetup;
+typedef struct _AFfilehandle *AFfilehandle;
+typedef void (*AFerrfunc)(long, const char *);
+
+// Define AFframecount and AFfileoffset as 64-bit signed integers.
+#if defined(__FreeBSD__) || \
+	defined(__DragonFly__) || \
+	defined(__NetBSD__) || \
+	defined(__OpenBSD__) || \
+	defined(__APPLE__) || \
+	defined(__sgi) || \
+	(defined(__linux__) && defined(__LP64__))
+// BSD and IRIX systems define off_t as a 64-bit signed integer.
+// Linux defines off_t as a 64-bit signed integer in LP64 mode.
+typedef off_t AFframecount;
+typedef off_t AFfileoffset;
+#else
+// For all other systems, use int64_t.
+typedef int64_t AFframecount;
+typedef int64_t AFfileoffset;
+#endif
+
+#define AF_NULL_FILESETUP	((struct _AFfilesetup *) 0)
+#define AF_NULL_FILEHANDLE	((struct _AFfilehandle *) 0)
+
+#define AF_ERR_BASE 3000
+
+enum
+{
+	AF_DEFAULT_TRACK = 1001
+};
+
+enum
+{
+	AF_DEFAULT_INST = 2001
+};
+
+enum
+{
+	AF_NUM_UNLIMITED = 99999
+};
+
+enum
+{
+	AF_BYTEORDER_BIGENDIAN = 501,
+	AF_BYTEORDER_LITTLEENDIAN = 502
+};
+
+enum
+{
+	AF_FILE_UNKNOWN = -1,
+	AF_FILE_RAWDATA = 0,
+	AF_FILE_AIFFC = 1,
+	AF_FILE_AIFF = 2,
+	AF_FILE_NEXTSND = 3,
+	AF_FILE_WAVE = 4,
+	AF_FILE_BICSF = 5,
+	AF_FILE_IRCAM = AF_FILE_BICSF,
+	AF_FILE_MPEG1BITSTREAM = 6,	/* not implemented */
+	AF_FILE_SOUNDDESIGNER1 = 7,	/* not implemented */
+	AF_FILE_SOUNDDESIGNER2 = 8,	/* not implemented */
+	AF_FILE_AVR = 9,
+	AF_FILE_IFF_8SVX = 10,
+	AF_FILE_SAMPLEVISION = 11,
+	AF_FILE_VOC = 12,
+	AF_FILE_NIST_SPHERE = 13,
+	AF_FILE_SOUNDFONT2 = 14,	/* not implemented */
+	AF_FILE_CAF = 15,
+	AF_FILE_FLAC = 16
+};
+
+enum
+{
+	AF_LOOP_MODE_NOLOOP = 0,
+	AF_LOOP_MODE_FORW = 1,
+	AF_LOOP_MODE_FORWBAKW = 2
+};
+
+enum
+{
+	AF_SAMPFMT_TWOSCOMP = 401, /* linear two's complement */
+	AF_SAMPFMT_UNSIGNED = 402, /* unsigned integer */
+	AF_SAMPFMT_FLOAT = 403, /* 32-bit IEEE floating-point */
+	AF_SAMPFMT_DOUBLE = 404 /* 64-bit IEEE double-precision floating-point */
+};
+
+enum
+{
+	AF_INST_LOOP_OFF = 0,			/* no looping */
+	AF_INST_LOOP_CONTINUOUS = 1,	/* loop continuously through decay */
+	AF_INST_LOOP_SUSTAIN = 3		/* loop during sustain, then continue */
+};
+
+enum
+{
+	AF_INST_MIDI_BASENOTE = 301,
+	AF_INST_NUMCENTS_DETUNE = 302,
+	AF_INST_MIDI_LONOTE = 303,
+	AF_INST_MIDI_HINOTE = 304,
+	AF_INST_MIDI_LOVELOCITY = 305,
+	AF_INST_MIDI_HIVELOCITY = 306,
+	AF_INST_NUMDBS_GAIN = 307,
+	AF_INST_SUSLOOPID = 308,		/* loop id for AIFF sustain loop */
+	AF_INST_RELLOOPID = 309,		/* loop id for AIFF release loop */
+	AF_INST_SAMP_STARTFRAME = 310,	/* start sample for this inst */
+	AF_INST_SAMP_ENDFRAME = 311,	/* end sample for this inst */
+	AF_INST_SAMP_MODE = 312,		/* looping mode for this inst */
+	AF_INST_TRACKID = 313,
+	AF_INST_NAME = 314,				/* name of this inst */
+	AF_INST_SAMP_RATE = 315,		/* sample rate of this inst's sample */
+	AF_INST_PRESETID = 316,			/* ID of preset containing this inst */
+	AF_INST_PRESET_NAME = 317		/* name of preset containing this inst */
+};
+
+enum
+{
+	AF_MISC_UNRECOGNIZED = 0,	/* unrecognized data chunk */
+	AF_MISC_COPY = 201,	/* copyright string */
+	AF_MISC_AUTH = 202,	/* author string */
+	AF_MISC_NAME = 203,	/* name string */
+	AF_MISC_ANNO = 204,	/* annotation string */
+	AF_MISC_APPL = 205,	/* application-specific data */
+	AF_MISC_MIDI = 206,	/* MIDI exclusive data */
+	AF_MISC_PCMMAP = 207,	/* PCM mapping information (future use) */
+	AF_MISC_NeXT = 208,	/* misc binary data appended to NeXT header */
+	AF_MISC_IRCAM_PEAKAMP = 209,	/* peak amplitude information */
+	AF_MISC_IRCAM_COMMENT = 210,	/* BICSF text comment */
+	AF_MISC_COMMENT = 210,	/* general text comment */
+
+	AF_MISC_ICMT = AF_MISC_COMMENT,	/* comments chunk (WAVE format) */
+	AF_MISC_ICRD = 211,  /* creation date (WAVE format) */
+	AF_MISC_ISFT = 212  /* software name (WAVE format) */
+};
+
+enum
+{
+	/* supported compression schemes */
+	AF_COMPRESSION_UNKNOWN = -1,
+	AF_COMPRESSION_NONE = 0,
+	AF_COMPRESSION_G722 = 501,
+	AF_COMPRESSION_G711_ULAW = 502,
+	AF_COMPRESSION_G711_ALAW = 503,
+
+	/* Apple proprietary AIFF-C compression schemes (not supported) */
+	AF_COMPRESSION_APPLE_ACE2 = 504,
+	AF_COMPRESSION_APPLE_ACE8 = 505,
+	AF_COMPRESSION_APPLE_MAC3 = 506,
+	AF_COMPRESSION_APPLE_MAC6 = 507,
+
+	AF_COMPRESSION_G726 = 517,
+	AF_COMPRESSION_G728 = 518,
+	AF_COMPRESSION_DVI_AUDIO = 519,
+	AF_COMPRESSION_IMA = AF_COMPRESSION_DVI_AUDIO,
+	AF_COMPRESSION_GSM = 520,
+	AF_COMPRESSION_FS1016 = 521,
+	AF_COMPRESSION_DV = 522,
+	AF_COMPRESSION_MS_ADPCM = 523,
+
+	AF_COMPRESSION_FLAC = 530,
+	AF_COMPRESSION_ALAC = 540
+};
+
+/* tokens for afQuery() -- see the man page for instructions */
+/* level 1 selectors */
+enum
+{
+	AF_QUERYTYPE_INSTPARAM = 500,
+	AF_QUERYTYPE_FILEFMT = 501,
+	AF_QUERYTYPE_COMPRESSION = 502,
+	AF_QUERYTYPE_COMPRESSIONPARAM = 503,
+	AF_QUERYTYPE_MISC = 504,
+	AF_QUERYTYPE_INST = 505,
+	AF_QUERYTYPE_MARK = 506,
+	AF_QUERYTYPE_LOOP = 507
+};
+
+/* level 2 selectors */
+enum
+{
+	AF_QUERY_NAME = 600,	/* get name (1-3 words) */
+	AF_QUERY_DESC = 601,	/* get description */
+	AF_QUERY_LABEL = 602,	/* get 4- or 5-char label */
+	AF_QUERY_TYPE = 603,	/* get type token */
+	AF_QUERY_DEFAULT = 604,	/* dflt. value for param */
+	AF_QUERY_ID_COUNT = 605,	/* get number of ids avail. */
+	AF_QUERY_IDS = 606,	/* get array of id tokens */
+	AF_QUERY_IMPLEMENTED = 613,	/* boolean */
+	AF_QUERY_TYPE_COUNT = 607,	/* get number of types av. */
+	AF_QUERY_TYPES = 608,	/* get array of types */
+	AF_QUERY_NATIVE_SAMPFMT = 609,	/* for compression */
+	AF_QUERY_NATIVE_SAMPWIDTH = 610,
+	AF_QUERY_SQUISHFAC = 611,	/* 1.0 means variable */
+	AF_QUERY_MAX_NUMBER = 612,	/* max allowed in file */
+	AF_QUERY_SUPPORTED = 613	/* insts, loops, etc., supported? */
+};
+
+/* level 2 selectors which have sub-selectors */
+enum
+{
+	AF_QUERY_TRACKS = 620,
+	AF_QUERY_CHANNELS = 621,
+	AF_QUERY_SAMPLE_SIZES = 622,
+	AF_QUERY_SAMPLE_FORMATS = 623,
+	AF_QUERY_COMPRESSION_TYPES = 624
+};
+
+/* level 3 sub-selectors */
+enum
+{
+	AF_QUERY_VALUE_COUNT = 650,	/* number of values of the above */
+	AF_QUERY_VALUES = 651	/* array of those values */
+};
+
+
+/*
+	Old Audio File Library error codes. These are still returned by the
+	AFerrorhandler calls, but are not used by the new digital media library
+	error reporting routines. See the bottom of this file for the new error
+	tokens.
+*/
+
+enum
+{
+	AF_BAD_NOT_IMPLEMENTED = 0,	/* not implemented yet */
+	AF_BAD_FILEHANDLE = 1,	/* tried to use invalid filehandle */
+	AF_BAD_OPEN = 3,	/* unix open failed */
+	AF_BAD_CLOSE = 4,	/* unix close failed */
+	AF_BAD_READ = 5,	/* unix read failed */
+	AF_BAD_WRITE = 6,	/* unix write failed */
+	AF_BAD_LSEEK = 7,	/* unix lseek failed */
+	AF_BAD_NO_FILEHANDLE = 8,	/* failed to allocate a filehandle struct */
+	AF_BAD_ACCMODE = 10,	/* unrecognized audio file access mode */
+	AF_BAD_NOWRITEACC = 11,	/* file not open for writing */
+	AF_BAD_NOREADACC = 12,	/* file not open for reading */
+	AF_BAD_FILEFMT = 13,	/* unrecognized audio file format */
+	AF_BAD_RATE = 14,	/* invalid sample rate */
+	AF_BAD_CHANNELS = 15,	/* invalid number of channels*/
+	AF_BAD_SAMPCNT = 16,	/* invalid sample count */
+	AF_BAD_WIDTH = 17,	/* invalid sample width */
+	AF_BAD_SEEKMODE = 18,	/* invalid seek mode */
+	AF_BAD_NO_LOOPDATA = 19,	/* failed to allocate loop struct */
+	AF_BAD_MALLOC = 20,	/* malloc failed somewhere */
+	AF_BAD_LOOPID = 21,
+	AF_BAD_SAMPFMT = 22,	/* bad sample format */
+	AF_BAD_FILESETUP = 23,	/* bad file setup structure*/
+	AF_BAD_TRACKID = 24,	/* no track corresponding to id */
+	AF_BAD_NUMTRACKS = 25,	/* wrong number of tracks for file format */
+	AF_BAD_NO_FILESETUP = 26,	/* failed to allocate a filesetup struct*/
+	AF_BAD_LOOPMODE = 27,	/* unrecognized loop mode value */
+	AF_BAD_INSTID = 28,	/* invalid instrument id */
+	AF_BAD_NUMLOOPS = 29,	/* bad number of loops */
+	AF_BAD_NUMMARKS = 30,	/* bad number of markers */
+	AF_BAD_MARKID = 31,	/* bad marker id */
+	AF_BAD_MARKPOS = 32,	/* invalid marker position value */
+	AF_BAD_NUMINSTS = 33,	/* invalid number of instruments */
+	AF_BAD_NOAESDATA = 34,
+	AF_BAD_MISCID = 35,
+	AF_BAD_NUMMISC = 36,
+	AF_BAD_MISCSIZE = 37,
+	AF_BAD_MISCTYPE = 38,
+	AF_BAD_MISCSEEK = 39,
+	AF_BAD_STRLEN = 40,	/* invalid string length */
+	AF_BAD_RATECONV = 45,
+	AF_BAD_SYNCFILE = 46,
+	AF_BAD_CODEC_CONFIG = 47,	/* improperly configured codec */
+	AF_BAD_CODEC_STATE = 48,	/* invalid codec state: can't recover */
+	AF_BAD_CODEC_LICENSE = 49,	/* no license available for codec */
+	AF_BAD_CODEC_TYPE = 50,	/* unsupported codec type */
+	AF_BAD_COMPRESSION = AF_BAD_CODEC_CONFIG,	/* for back compat */
+	AF_BAD_COMPTYPE = AF_BAD_CODEC_TYPE,	/* for back compat */
+
+	AF_BAD_INSTPTYPE = 51,	/* invalid instrument parameter type */
+	AF_BAD_INSTPID = 52,	/* invalid instrument parameter id */
+	AF_BAD_BYTEORDER = 53,
+	AF_BAD_FILEFMT_PARAM = 54,	/* unrecognized file format parameter */
+	AF_BAD_COMP_PARAM = 55,	/* unrecognized compression parameter */
+	AF_BAD_DATAOFFSET = 56,	/* bad data offset */
+	AF_BAD_FRAMECNT = 57,	/* bad frame count */
+	AF_BAD_QUERYTYPE = 58,	/* bad query type */
+	AF_BAD_QUERY = 59,	/* bad argument to afQuery() */
+	AF_WARNING_CODEC_RATE = 60,	/* using 8k instead of codec rate 8012 */
+	AF_WARNING_RATECVT = 61,	/* warning about rate conversion used */
+
+	AF_BAD_HEADER = 62,	/* failed to parse header */
+	AF_BAD_FRAME = 63,	/* bad frame number */
+	AF_BAD_LOOPCOUNT = 64,	/* bad loop count */
+	AF_BAD_DMEDIA_CALL = 65,	/* error in dmedia subsystem call */
+
+	/* AIFF/AIFF-C specific errors when parsing file header */
+	AF_BAD_AIFF_HEADER = 108,	/* failed to parse chunk header */
+	AF_BAD_AIFF_FORM = 109,	/* failed to parse FORM chunk */
+	AF_BAD_AIFF_SSND = 110,	/* failed to parse SSND chunk */
+	AF_BAD_AIFF_CHUNKID = 111,	/* unrecognized AIFF/AIFF-C chunk id */
+	AF_BAD_AIFF_COMM = 112,	/* failed to parse COMM chunk */
+	AF_BAD_AIFF_INST = 113,	/* failed to parse INST chunk */
+	AF_BAD_AIFF_MARK = 114,	/* failed to parse MARK chunk */
+	AF_BAD_AIFF_SKIP = 115,	/* failed to skip unsupported chunk */
+	AF_BAD_AIFF_LOOPMODE = 116	/* unrecognized loop mode (forw, etc)*/
+};
+
+/* new error codes which may be retrieved via dmGetError() */
+/* The old error tokens continue to be retrievable via the AFerrorhandler */
+/* AF_ERR_BASE is #defined in dmedia/dmedia.h */
+
+enum
+{
+	AF_ERR_NOT_IMPLEMENTED = 0+AF_ERR_BASE,	/* not implemented yet */
+	AF_ERR_BAD_FILEHANDLE = 1+AF_ERR_BASE,	/* invalid filehandle */
+	AF_ERR_BAD_READ = 5+AF_ERR_BASE,	/* unix read failed */
+	AF_ERR_BAD_WRITE = 6+AF_ERR_BASE,	/* unix write failed */
+	AF_ERR_BAD_LSEEK = 7+AF_ERR_BASE,	/* unix lseek failed */
+	AF_ERR_BAD_ACCMODE = 10+AF_ERR_BASE,	/* unrecognized audio file access mode */
+	AF_ERR_NO_WRITEACC = 11+AF_ERR_BASE,	/* file not open for writing */
+	AF_ERR_NO_READACC = 12+AF_ERR_BASE,	/* file not open for reading */
+	AF_ERR_BAD_FILEFMT = 13+AF_ERR_BASE,	/* unrecognized audio file format */
+	AF_ERR_BAD_RATE = 14+AF_ERR_BASE,	/* invalid sample rate */
+	AF_ERR_BAD_CHANNELS = 15+AF_ERR_BASE,	/* invalid # channels*/
+	AF_ERR_BAD_SAMPCNT = 16+AF_ERR_BASE,	/* invalid sample count */
+	AF_ERR_BAD_WIDTH = 17+AF_ERR_BASE,	/* invalid sample width */
+	AF_ERR_BAD_SEEKMODE = 18+AF_ERR_BASE,	/* invalid seek mode */
+	AF_ERR_BAD_LOOPID = 21+AF_ERR_BASE,	/* invalid loop id */
+	AF_ERR_BAD_SAMPFMT = 22+AF_ERR_BASE,	/* bad sample format */
+	AF_ERR_BAD_FILESETUP = 23+AF_ERR_BASE,	/* bad file setup structure*/
+	AF_ERR_BAD_TRACKID = 24+AF_ERR_BASE,	/* no track corresponding to id */
+	AF_ERR_BAD_NUMTRACKS = 25+AF_ERR_BASE,	/* wrong number of tracks for file format */
+	AF_ERR_BAD_LOOPMODE = 27+AF_ERR_BASE,	/* unrecognized loop mode symbol */
+	AF_ERR_BAD_INSTID = 28+AF_ERR_BASE,	/* invalid instrument id */
+	AF_ERR_BAD_NUMLOOPS = 29+AF_ERR_BASE,	/* bad number of loops */
+	AF_ERR_BAD_NUMMARKS = 30+AF_ERR_BASE,	/* bad number of markers */
+	AF_ERR_BAD_MARKID = 31+AF_ERR_BASE,	/* bad marker id */
+	AF_ERR_BAD_MARKPOS = 32+AF_ERR_BASE,	/* invalid marker position value */
+	AF_ERR_BAD_NUMINSTS = 33+AF_ERR_BASE,	/* invalid number of instruments */
+	AF_ERR_BAD_NOAESDATA = 34+AF_ERR_BASE,
+	AF_ERR_BAD_MISCID = 35+AF_ERR_BASE,
+	AF_ERR_BAD_NUMMISC = 36+AF_ERR_BASE,
+	AF_ERR_BAD_MISCSIZE = 37+AF_ERR_BASE,
+	AF_ERR_BAD_MISCTYPE = 38+AF_ERR_BASE,
+	AF_ERR_BAD_MISCSEEK = 39+AF_ERR_BASE,
+	AF_ERR_BAD_STRLEN = 40+AF_ERR_BASE,	/* invalid string length */
+	AF_ERR_BAD_RATECONV = 45+AF_ERR_BASE,
+	AF_ERR_BAD_SYNCFILE = 46+AF_ERR_BASE,
+	AF_ERR_BAD_CODEC_CONFIG = 47+AF_ERR_BASE,	/* improperly configured codec */
+	AF_ERR_BAD_CODEC_TYPE = 50+AF_ERR_BASE,	/* unsupported codec type */
+	AF_ERR_BAD_INSTPTYPE = 51+AF_ERR_BASE,	/* invalid instrument parameter type */
+	AF_ERR_BAD_INSTPID = 52+AF_ERR_BASE,	/* invalid instrument parameter id */
+
+	AF_ERR_BAD_BYTEORDER = 53+AF_ERR_BASE,
+	AF_ERR_BAD_FILEFMT_PARAM = 54+AF_ERR_BASE,	/* unrecognized file format parameter */
+	AF_ERR_BAD_COMP_PARAM = 55+AF_ERR_BASE,	/* unrecognized compression parameter */
+	AF_ERR_BAD_DATAOFFSET = 56+AF_ERR_BASE,	/* bad data offset */
+	AF_ERR_BAD_FRAMECNT = 57+AF_ERR_BASE,	/* bad frame count */
+
+	AF_ERR_BAD_QUERYTYPE = 58+AF_ERR_BASE,	/* bad query type */
+	AF_ERR_BAD_QUERY = 59+AF_ERR_BASE,	/* bad argument to afQuery() */
+	AF_ERR_BAD_HEADER = 62+AF_ERR_BASE,	/* failed to parse header */
+	AF_ERR_BAD_FRAME = 63+AF_ERR_BASE,	/* bad frame number */
+	AF_ERR_BAD_LOOPCOUNT = 64+AF_ERR_BASE,	/* bad loop count */
+
+	/* AIFF/AIFF-C specific errors when parsing file header */
+
+	AF_ERR_BAD_AIFF_HEADER = 66+AF_ERR_BASE,	/* failed to parse chunk header */
+	AF_ERR_BAD_AIFF_FORM = 67+AF_ERR_BASE,	/* failed to parse FORM chunk */
+	AF_ERR_BAD_AIFF_SSND = 68+AF_ERR_BASE,	/* failed to parse SSND chunk */
+	AF_ERR_BAD_AIFF_CHUNKID = 69+AF_ERR_BASE,	/* unrecognized AIFF/AIFF-C chunk id */
+	AF_ERR_BAD_AIFF_COMM = 70+AF_ERR_BASE,	/* failed to parse COMM chunk */
+	AF_ERR_BAD_AIFF_INST = 71+AF_ERR_BASE,	/* failed to parse INST chunk */
+	AF_ERR_BAD_AIFF_MARK = 72+AF_ERR_BASE,	/* failed to parse MARK chunk */
+	AF_ERR_BAD_AIFF_SKIP = 73+AF_ERR_BASE,	/* failed to skip unsupported chunk */
+	AF_ERR_BAD_AIFF_LOOPMODE = 74+AF_ERR_BASE	/* unrecognized loop mode (forw, etc) */
+};
+
+
+/* global routines */
+AFAPI AFerrfunc afSetErrorHandler (AFerrfunc efunc);
+
+/* query routines */
+AFAPI AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);
+AFAPI long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);
+AFAPI double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4);
+AFAPI void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4);
+
+/* basic operations on file handles and file setups */
+AFAPI AFfilesetup afNewFileSetup (void);
+AFAPI void afFreeFileSetup (AFfilesetup);
+AFAPI int afIdentifyFD (int);
+AFAPI int afIdentifyNamedFD (int, const char *filename, int *implemented);
+
+AFAPI AFfilehandle afOpenFile (const char *filename, const char *mode,
+	AFfilesetup setup);
+AFAPI AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
+	AFfilesetup setup);
+AFAPI AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup);
+AFAPI AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
+	const char *filename);
+
+AFAPI void afSaveFilePosition (AFfilehandle file);
+AFAPI void afRestoreFilePosition (AFfilehandle file);
+AFAPI int afSyncFile (AFfilehandle file);
+AFAPI int afCloseFile (AFfilehandle file);
+
+AFAPI void afInitFileFormat (AFfilesetup, int format);
+AFAPI int afGetFileFormat (AFfilehandle, int *version);
+
+/* track */
+AFAPI void afInitTrackIDs (AFfilesetup, const int *trackids, int trackCount);
+AFAPI int afGetTrackIDs (AFfilehandle, int *trackids);
+
+/* track data: reading, writng, seeking, sizing frames */
+AFAPI int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount);
+AFAPI int afWriteFrames (AFfilehandle, int track, const void *buffer, int frameCount);
+AFAPI AFframecount afSeekFrame (AFfilehandle, int track, AFframecount frameoffset);
+AFAPI AFframecount afTellFrame (AFfilehandle, int track);
+AFAPI AFfileoffset afGetTrackBytes (AFfilehandle, int track);
+AFAPI float afGetFrameSize (AFfilehandle, int track, int expand3to4);
+AFAPI float afGetVirtualFrameSize (AFfilehandle, int track, int expand3to4);
+
+/* track data: AES data */
+/* afInitAESChannelData is obsolete -- use afInitAESChannelDataTo() */
+AFAPI void afInitAESChannelData (AFfilesetup, int track); /* obsolete */
+AFAPI void afInitAESChannelDataTo (AFfilesetup, int track, int willBeData);
+AFAPI int afGetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
+AFAPI void afSetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
+
+/* track data: byte order */
+AFAPI void afInitByteOrder (AFfilesetup, int track, int byteOrder);
+AFAPI int afGetByteOrder (AFfilehandle, int track);
+AFAPI int afSetVirtualByteOrder (AFfilehandle, int track, int byteOrder);
+AFAPI int afGetVirtualByteOrder (AFfilehandle, int track);
+
+/* track data: number of channels */
+AFAPI void afInitChannels (AFfilesetup, int track, int nchannels);
+AFAPI int afGetChannels (AFfilehandle, int track);
+AFAPI int afSetVirtualChannels (AFfilehandle, int track, int channelCount);
+AFAPI int afGetVirtualChannels (AFfilehandle, int track);
+AFAPI void afSetChannelMatrix (AFfilehandle, int track, double *matrix);
+
+/* track data: sample format and sample width */
+AFAPI void afInitSampleFormat (AFfilesetup, int track, int sampleFormat,
+	int sampleWidth);
+AFAPI void afGetSampleFormat (AFfilehandle file, int track, int *sampleFormat,
+	int *sampleWidth);
+AFAPI int afSetVirtualSampleFormat (AFfilehandle, int track,
+	int sampleFormat, int sampleWidth);
+AFAPI void afGetVirtualSampleFormat (AFfilehandle, int track,
+	int *sampleFormat, int *sampleWidth);
+
+/* track data: sampling rate */
+AFAPI void afInitRate (AFfilesetup, int track, double rate);
+AFAPI double afGetRate (AFfilehandle, int track);
+
+#if 0
+int afSetVirtualRate (AFfilehandle, int track, double rate);
+double afGetVirtualRate (AFfilehandle, int track);
+#endif
+
+/* track data: compression */
+AFAPI void afInitCompression (AFfilesetup, int track, int compression);
+#if 0
+void afInitCompressionParams (AFfilesetup, int track, int compression
+	AUpvlist params, int parameterCount);
+#endif
+
+AFAPI int afGetCompression (AFfilehandle, int track);
+#if 0
+void afGetCompressionParams (AFfilehandle, int track, int *compression,
+	AUpvlist params, int parameterCount);
+
+int afSetVirtualCompression (AFfilesetup, int track, int compression);
+void afSetVirtualCompressionParams (AFfilehandle, int track, int compression,
+	AUpvlist params, int parameterCount);
+
+int afGetVirtualCompression (AFfilesetup, int track, int compression);
+void afGetVirtualCompressionParams (AFfilehandle, int track, int *compression,
+	AUpvlist params, int parameterCount);
+#endif
+
+/* track data: pcm mapping */
+AFAPI void afInitPCMMapping (AFfilesetup filesetup, int track,
+	double slope, double intercept, double minClip, double maxClip);
+AFAPI void afGetPCMMapping (AFfilehandle file, int track,
+	double *slope, double *intercept, double *minClip, double *maxClip);
+/* NOTE: afSetTrackPCMMapping() is special--it does not set the virtual  */
+/* format; it changes what the AF thinks the track format is! Be careful. */
+AFAPI int afSetTrackPCMMapping (AFfilehandle file, int track,
+	double slope, double intercept, double minClip, double maxClip);
+/* NOTE: afSetVirtualPCMMapping() is different from afSetTrackPCMMapping(): */
+/* see comment for afSetTrackPCMMapping(). */
+AFAPI int afSetVirtualPCMMapping (AFfilehandle file, int track,
+	double slope, double intercept, double minClip, double maxClip);
+AFAPI void afGetVirtualPCMMapping (AFfilehandle file, int track,
+	double *slope, double *intercept, double *minClip, double *maxClip);
+
+/* track data: data offset within the file */
+/* initialize for raw reading only */
+AFAPI void afInitDataOffset(AFfilesetup, int track, AFfileoffset offset);
+AFAPI AFfileoffset afGetDataOffset (AFfilehandle, int track);
+
+/* track data: count of frames in file */
+AFAPI void afInitFrameCount (AFfilesetup, int track, AFframecount frameCount);
+AFAPI AFframecount afGetFrameCount (AFfilehandle file, int track);
+
+/* loop operations */
+AFAPI void afInitLoopIDs (AFfilesetup, int instid, const int *ids, int nids);
+AFAPI int afGetLoopIDs (AFfilehandle, int instid, int loopids[]);
+AFAPI void afSetLoopMode (AFfilehandle, int instid, int loop, int mode);
+AFAPI int afGetLoopMode (AFfilehandle, int instid, int loopid);
+AFAPI int afSetLoopCount (AFfilehandle, int instid, int loop, int count);
+AFAPI int afGetLoopCount (AFfilehandle, int instid, int loopid);
+AFAPI void afSetLoopStart (AFfilehandle, int instid, int loopid, int markerid);
+AFAPI int afGetLoopStart (AFfilehandle, int instid, int loopid);
+AFAPI void afSetLoopEnd (AFfilehandle, int instid, int loopid, int markerid);
+AFAPI int afGetLoopEnd (AFfilehandle, int instid, int loopid);
+
+AFAPI int afSetLoopStartFrame (AFfilehandle, int instid, int loop,
+	AFframecount startFrame);
+AFAPI AFframecount afGetLoopStartFrame (AFfilehandle, int instid, int loop);
+AFAPI int afSetLoopEndFrame (AFfilehandle, int instid, int loop,
+	AFframecount startFrame);
+AFAPI AFframecount afGetLoopEndFrame (AFfilehandle, int instid, int loop);
+
+AFAPI void afSetLoopTrack (AFfilehandle, int instid, int loopid, int trackid);
+AFAPI int afGetLoopTrack (AFfilehandle, int instid, int loopid);
+
+/* marker operations */
+AFAPI void afInitMarkIDs (AFfilesetup, int trackid, const int *ids, int nids);
+AFAPI int afGetMarkIDs (AFfilehandle file, int trackid, int markids[]);
+AFAPI void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
+	AFframecount markpos);
+AFAPI AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid);
+AFAPI void afInitMarkName (AFfilesetup, int trackid, int marker, const char *name);
+AFAPI void afInitMarkComment (AFfilesetup, int trackid, int marker,
+	const char *comment);
+AFAPI char *afGetMarkName (AFfilehandle file, int trackid, int markid);
+AFAPI char *afGetMarkComment (AFfilehandle file, int trackid, int markid);
+
+/* instrument operations */
+AFAPI void afInitInstIDs (AFfilesetup, const int *ids, int nids);
+AFAPI int afGetInstIDs (AFfilehandle file, int *instids);
+AFAPI void afGetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
+	int nparams);
+AFAPI void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
+	int nparams);
+AFAPI long afGetInstParamLong (AFfilehandle file, int instid, int param);
+AFAPI void afSetInstParamLong (AFfilehandle file, int instid, int param, long value);
+
+/* miscellaneous data operations */
+AFAPI void afInitMiscIDs (AFfilesetup, const int *ids, int nids);
+AFAPI int afGetMiscIDs (AFfilehandle, int *ids);
+AFAPI void afInitMiscType (AFfilesetup, int miscellaneousid, int type);
+AFAPI int afGetMiscType (AFfilehandle, int miscellaneousid);
+AFAPI void afInitMiscSize (AFfilesetup, int miscellaneousid, int size);
+AFAPI int afGetMiscSize (AFfilehandle, int miscellaneousid);
+AFAPI int afWriteMisc (AFfilehandle, int miscellaneousid, const void *buf, int bytes);
+AFAPI int afReadMisc (AFfilehandle, int miscellaneousid, void *buf, int bytes);
+AFAPI int afSeekMisc (AFfilehandle, int miscellaneousid, int offset);
+
+#undef AFAPI
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUDIOFILE_H */
diff --git a/libaudiofile/aupv.c b/libaudiofile/aupv.c
new file mode 100644
index 0000000..64e798b
--- /dev/null
+++ b/libaudiofile/aupv.c
@@ -0,0 +1,252 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	aupv.c
+
+	This file contains an implementation of SGI's Audio Library parameter
+	value list functions.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "aupvinternal.h"
+#include "aupvlist.h"
+
+AUpvlist AUpvnew (int maxitems)
+{
+	AUpvlist	aupvlist;
+	int		i;
+
+	if (maxitems <= 0)
+		return AU_NULL_PVLIST;
+
+	aupvlist = (AUpvlist) malloc(sizeof (struct _AUpvlist));
+	assert(aupvlist);
+	if (aupvlist == NULL)
+		return AU_NULL_PVLIST;
+
+	aupvlist->items = calloc(maxitems, sizeof (struct _AUpvitem));
+
+	assert(aupvlist->items);
+	if (aupvlist->items == NULL)
+	{
+		free(aupvlist);
+		return AU_NULL_PVLIST;
+	}
+
+	/* Initialize the items in the list. */
+	for (i=0; i<maxitems; i++)
+	{
+		aupvlist->items[i].valid = _AU_VALID_PVITEM;
+		aupvlist->items[i].type = AU_PVTYPE_LONG;
+		aupvlist->items[i].parameter = 0;
+		memset(&aupvlist->items[i].value, 0, sizeof (aupvlist->items[i].value));
+	}
+
+	aupvlist->valid = _AU_VALID_PVLIST;
+	aupvlist->count = maxitems;
+
+	return aupvlist;
+}
+
+int AUpvgetmaxitems (AUpvlist list)
+{
+	assert(list);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+
+	return list->count;
+}
+
+int AUpvfree (AUpvlist list)
+{
+	assert(list);
+	assert(list->items);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+
+	if ((list->items != _AU_NULL_PVITEM) &&
+		(list->items[0].valid == _AU_VALID_PVITEM))
+	{
+		free(list->items);
+	}
+
+	free(list);
+
+	return _AU_SUCCESS;
+}
+
+int AUpvsetparam (AUpvlist list, int item, int param)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	list->items[item].parameter = param;
+	return _AU_SUCCESS;
+}
+
+int AUpvsetvaltype (AUpvlist list, int item, int type)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	list->items[item].type = type;
+	return _AU_SUCCESS;
+}
+
+int AUpvsetval (AUpvlist list, int item, void *val)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	switch (list->items[item].type)
+	{
+		case AU_PVTYPE_LONG:
+			list->items[item].value.l = *((long *) val);
+			break;
+		case AU_PVTYPE_DOUBLE:
+			list->items[item].value.d = *((double *) val);
+			break;
+		case AU_PVTYPE_PTR:
+			list->items[item].value.v = *((void **) val);
+			break;
+		default:
+			assert(0);
+			return AU_BAD_PVLIST;
+	}
+
+	return _AU_SUCCESS;
+}
+
+int AUpvgetparam (AUpvlist list, int item, int *param)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	*param = list->items[item].parameter;
+	return _AU_SUCCESS;
+}
+
+int AUpvgetvaltype (AUpvlist list, int item, int *type)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	*type = list->items[item].type;
+	return _AU_SUCCESS;
+}
+
+int AUpvgetval (AUpvlist list, int item, void *val)
+{
+	assert(list);
+	assert(list->items);
+	assert(item >= 0);
+	assert(item < list->count);
+
+	if (list == AU_NULL_PVLIST)
+		return AU_BAD_PVLIST;
+	if (list->valid != _AU_VALID_PVLIST)
+		return AU_BAD_PVLIST;
+	if ((item < 0) || (item > list->count - 1))
+		return AU_BAD_PVITEM;
+	if (list->items[item].valid != _AU_VALID_PVITEM)
+		return AU_BAD_PVLIST;
+
+	switch (list->items[item].type)
+	{
+		case AU_PVTYPE_LONG:
+			*((long *) val) = list->items[item].value.l;
+			break;
+		case AU_PVTYPE_DOUBLE:
+			*((double *) val) = list->items[item].value.d;
+			break;
+		case AU_PVTYPE_PTR:
+			*((void **) val) = list->items[item].value.v;
+			break;
+	}
+
+	return _AU_SUCCESS;
+}
diff --git a/libaudiofile/aupvinternal.h b/libaudiofile/aupvinternal.h
new file mode 100644
index 0000000..4465055
--- /dev/null
+++ b/libaudiofile/aupvinternal.h
@@ -0,0 +1,75 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	aupvinternal.h
+
+	This file contains the private data structures for the parameter
+	value list data types.
+*/
+
+#ifndef AUPVINTERNAL_H
+#define AUPVINTERNAL_H
+
+struct _AUpvitem
+{
+	int	valid;
+	int	type;
+	int	parameter;
+
+	union
+	{
+		long	l;
+		double	d;
+		void	*v;
+	}
+	value;
+};
+
+struct _AUpvlist
+{
+	int			valid;
+	size_t			count;
+	struct _AUpvitem	*items;
+};
+
+enum
+{
+	_AU_VALID_PVLIST = 30932,
+	_AU_VALID_PVITEM = 30933
+};
+
+enum
+{
+	AU_BAD_PVLIST = -5,
+	AU_BAD_PVITEM = -6,
+	AU_BAD_PVTYPE = -7,
+	AU_BAD_ALLOC = -8
+};
+
+enum
+{
+	_AU_FAIL = -1,
+	_AU_SUCCESS = 0
+};
+
+#define _AU_NULL_PVITEM ((struct _AUpvitem *) NULL)
+
+#endif
diff --git a/libaudiofile/aupvlist.h b/libaudiofile/aupvlist.h
new file mode 100644
index 0000000..c20f248
--- /dev/null
+++ b/libaudiofile/aupvlist.h
@@ -0,0 +1,68 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	aupvlist.h
+
+	This file contains the interface to the parameter value list data
+	structures and routines.
+*/
+
+#ifndef AUPVLIST_H
+#define AUPVLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
+#define AFAPI __attribute__((visibility("default")))
+#else
+#define AFAPI
+#endif
+
+enum
+{
+	AU_PVTYPE_LONG = 1,
+	AU_PVTYPE_DOUBLE = 2,
+	AU_PVTYPE_PTR = 3
+};
+
+typedef struct _AUpvlist *AUpvlist;
+
+#define AU_NULL_PVLIST ((struct _AUpvlist *) 0)
+
+AFAPI AUpvlist AUpvnew (int maxItems);
+AFAPI int AUpvgetmaxitems (AUpvlist);
+AFAPI int AUpvfree (AUpvlist);
+AFAPI int AUpvsetparam (AUpvlist, int item, int param);
+AFAPI int AUpvsetvaltype (AUpvlist, int item, int type);
+AFAPI int AUpvsetval (AUpvlist, int item, void *val);
+AFAPI int AUpvgetparam (AUpvlist, int item, int *param);
+AFAPI int AUpvgetvaltype (AUpvlist, int item, int *type);
+AFAPI int AUpvgetval (AUpvlist, int item, void *val);
+
+#undef AFAPI
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUPVLIST_H */
diff --git a/libaudiofile/byteorder.h b/libaudiofile/byteorder.h
new file mode 100644
index 0000000..e8239dd
--- /dev/null
+++ b/libaudiofile/byteorder.h
@@ -0,0 +1,117 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-1999, 2010-2011, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef BYTEORDER_H
+#define BYTEORDER_H
+
+#include "config.h"
+
+#include <stdint.h>
+
+#if WORDS_BIGENDIAN
+	#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_BIGENDIAN)
+#else
+	#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_LITTLEENDIAN)
+#endif
+
+inline uint16_t _af_byteswap_int16 (uint16_t x)
+{
+	return (x >> 8) | (x << 8);
+}
+
+inline uint32_t _af_byteswap_int32 (uint32_t x)
+{
+	return ((x & 0x000000ffU) << 24) |
+		((x & 0x0000ff00U) << 8) |
+		((x & 0x00ff0000U) >> 8) |
+		((x & 0xff000000U) >> 24);
+}
+
+inline uint64_t _af_byteswap_int64 (uint64_t x)
+{
+	return ((x & 0x00000000000000ffULL) << 56) |
+		((x & 0x000000000000ff00ULL) << 40) |
+		((x & 0x0000000000ff0000ULL) << 24) |
+		((x & 0x00000000ff000000ULL) << 8) |
+		((x & 0x000000ff00000000ULL) >> 8) |
+		((x & 0x0000ff0000000000ULL) >> 24) |
+		((x & 0x00ff000000000000ULL) >> 40) |
+		((x & 0xff00000000000000ULL) >> 56);
+}
+
+inline float _af_byteswap_float32 (float x)
+{
+	union
+	{
+		uint32_t i;
+		float f;
+	} u;
+	u.f = x;
+	u.i = _af_byteswap_int32(u.i);
+	return u.f;
+}
+
+inline double _af_byteswap_float64 (double x)
+{
+	union
+	{
+		uint64_t i;
+		double f;
+	} u;
+	u.f = x;
+	u.i = _af_byteswap_int64(u.i);
+	return u.f;
+}
+
+inline uint64_t byteswap(uint64_t value) { return _af_byteswap_int64(value); }
+inline int64_t byteswap(int64_t value) { return _af_byteswap_int64(value); }
+inline uint32_t byteswap(uint32_t value) { return _af_byteswap_int32(value); }
+inline int32_t byteswap(int32_t value) { return _af_byteswap_int32(value); }
+inline uint16_t byteswap(uint16_t value) { return _af_byteswap_int16(value); }
+inline int16_t byteswap(int16_t value) { return _af_byteswap_int16(value); }
+
+inline double byteswap(double value) { return _af_byteswap_float64(value); }
+inline float byteswap(float value) { return _af_byteswap_float32(value); }
+
+template <typename T>
+T bigToHost(T value)
+{
+	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
+}
+
+template <typename T>
+T littleToHost(T value)
+{
+	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
+}
+
+template <typename T>
+T hostToBig(T value)
+{
+	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
+}
+
+template <typename T>
+T hostToLittle(T value)
+{
+	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
+}
+
+#endif
diff --git a/libaudiofile/compression.cpp b/libaudiofile/compression.cpp
new file mode 100644
index 0000000..e996923
--- /dev/null
+++ b/libaudiofile/compression.cpp
@@ -0,0 +1,92 @@
+/*
+	Audio File Library
+	Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	compression.cpp
+
+	This file contains routines for configuring compressed audio.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "audiofile.h"
+#include "aupvlist.h"
+#include "units.h"
+#include "util.h"
+
+const CompressionUnit *_af_compression_unit_from_id (int compressionid)
+{
+	for (int i=0; i<_AF_NUM_COMPRESSION; i++)
+		if (_af_compression[i].compressionID == compressionid)
+			return &_af_compression[i];
+
+	_af_error(AF_BAD_COMPTYPE, "compression type %d not available", compressionid);
+	return NULL;
+}
+
+int afGetCompression (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->f.compressionType;
+}
+
+void afInitCompression (AFfilesetup setup, int trackid, int compression)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (!_af_compression_unit_from_id(compression))
+		return;
+
+	track->compressionSet = true;
+	track->f.compressionType = compression;
+}
+
+#if 0
+int afGetCompressionParams (AFfilehandle file, int trackid,
+	int *compression, AUpvlist pvlist, int numitems)
+{
+	assert(file);
+	assert(trackid == AF_DEFAULT_TRACK);
+}
+
+void afInitCompressionParams (AFfilesetup setup, int trackid,
+	int compression, AUpvlist pvlist, int numitems)
+{
+	assert(setup);
+	assert(trackid == AF_DEFAULT_TRACK);
+}
+#endif
diff --git a/libaudiofile/compression.h b/libaudiofile/compression.h
new file mode 100644
index 0000000..d4b9792
--- /dev/null
+++ b/libaudiofile/compression.h
@@ -0,0 +1,33 @@
+/*
+	Audio File Library
+	Copyright (C) 1999, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	compression.h
+*/
+
+#ifndef COMPRESSION_H
+#define COMPRESSION_H
+
+struct CompressionUnit;
+
+const CompressionUnit *_af_compression_unit_from_id (int compressionid);
+
+#endif
diff --git a/libaudiofile/data.cpp b/libaudiofile/data.cpp
new file mode 100644
index 0000000..21b16b1
--- /dev/null
+++ b/libaudiofile/data.cpp
@@ -0,0 +1,236 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	data.cpp
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "File.h"
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "modules/Module.h"
+#include "modules/ModuleState.h"
+#include "util.h"
+
+int afWriteFrames (AFfilehandle file, int trackid, const void *samples,
+	int nvframes2write)
+{
+	SharedPtr<Module> firstmod;
+	SharedPtr<Chunk> userc;
+	int bytes_per_vframe;
+	AFframecount vframe;
+
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (!file->checkCanWrite())
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
+		return -1;
+
+	if (!track->ms->fileModuleHandlesSeeking() &&
+		file->m_seekok &&
+		file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
+			track->fpos_next_frame)
+	{
+		_af_error(AF_BAD_LSEEK, "unable to position write pointer at next frame");
+		return -1;
+	}
+
+	bytes_per_vframe = _af_format_frame_size(&track->v, true);
+
+	firstmod = track->ms->modules().front();
+	userc = track->ms->chunks().front();
+
+	track->filemodhappy = true;
+
+	vframe = 0;
+#ifdef UNLIMITED_CHUNK_NVFRAMES
+	/*
+		OPTIMIZATION: see the comment at the very end of
+		arrangemodules() in modules.c for an explanation of this:
+	*/
+	if (!trk->ms->mustUseAtomicNVFrames())
+	{
+		userc->buffer = (char *) samples;
+		userc->frameCount = nvframes2write;
+
+		firstmod->runPush();
+
+		/* Count this chunk if there was no i/o error. */
+		if (trk->filemodhappy)
+			vframe += userc->frameCount;
+	}
+	else
+#else
+	/* Optimization must be off. */
+	assert(track->ms->mustUseAtomicNVFrames());
+#endif
+	{
+		while (vframe < nvframes2write)
+		{
+			userc->buffer = (char *) samples + bytes_per_vframe * vframe;
+			if (vframe <= nvframes2write - _AF_ATOMIC_NVFRAMES)
+				userc->frameCount = _AF_ATOMIC_NVFRAMES;
+			else
+				userc->frameCount = nvframes2write - vframe;
+
+			firstmod->runPush();
+
+			if (!track->filemodhappy)
+				break;
+
+			vframe += userc->frameCount;
+		}
+	}
+
+	track->nextvframe += vframe;
+	track->totalvframes += vframe;
+
+	return vframe;
+}
+
+int afReadFrames (AFfilehandle file, int trackid, void *samples,
+	int nvframeswanted)
+{
+	SharedPtr<Module> firstmod;
+	SharedPtr<Chunk> userc;
+	AFframecount	nvframesleft, nvframes2read;
+	int		bytes_per_vframe;
+	AFframecount	vframe;
+
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (!file->checkCanRead())
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
+		return -1;
+
+	if (!track->ms->fileModuleHandlesSeeking() &&
+		file->m_seekok &&
+		file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
+			track->fpos_next_frame)
+	{
+		_af_error(AF_BAD_LSEEK, "unable to position read pointer at next frame");
+		return -1;
+	}
+
+	if (track->totalvframes == -1)
+		nvframes2read = nvframeswanted;
+	else
+	{
+		nvframesleft = track->totalvframes - track->nextvframe;
+		nvframes2read = (nvframeswanted > nvframesleft) ?
+			nvframesleft : nvframeswanted;
+	}
+	bytes_per_vframe = _af_format_frame_size(&track->v, true);
+
+	firstmod = track->ms->modules().back();
+	userc = track->ms->chunks().back();
+
+	track->filemodhappy = true;
+
+	vframe = 0;
+
+	if (!track->ms->mustUseAtomicNVFrames())
+	{
+		assert(track->frames2ignore == 0);
+		userc->buffer = samples;
+		userc->frameCount = nvframes2read;
+
+		firstmod->runPull();
+		if (track->filemodhappy)
+			vframe += userc->frameCount;
+	}
+	else
+	{
+		bool	eof = false;
+
+		if (track->frames2ignore != 0)
+		{
+			userc->frameCount = track->frames2ignore;
+			userc->allocate(track->frames2ignore * bytes_per_vframe);
+			if (!userc->buffer)
+				return 0;
+
+			firstmod->runPull();
+
+			/* Have we hit EOF? */
+			if (static_cast<ssize_t>(userc->frameCount) < track->frames2ignore)
+				eof = true;
+
+			track->frames2ignore = 0;
+
+			userc->deallocate();
+		}
+
+		/*
+			Now start reading useful frames, until EOF or
+			premature EOF.
+		*/
+
+		while (track->filemodhappy && !eof && vframe < nvframes2read)
+		{
+			AFframecount	nvframes2pull;
+			userc->buffer = (char *) samples + bytes_per_vframe * vframe;
+
+			if (vframe <= nvframes2read - _AF_ATOMIC_NVFRAMES)
+				nvframes2pull = _AF_ATOMIC_NVFRAMES;
+			else
+				nvframes2pull = nvframes2read - vframe;
+
+			userc->frameCount = nvframes2pull;
+
+			firstmod->runPull();
+
+			if (track->filemodhappy)
+			{
+				vframe += userc->frameCount;
+				if (static_cast<ssize_t>(userc->frameCount) < nvframes2pull)
+					eof = true;
+			}
+		}
+	}
+
+	track->nextvframe += vframe;
+
+	return vframe;
+}
diff --git a/libaudiofile/debug.cpp b/libaudiofile/debug.cpp
new file mode 100644
index 0000000..1bea40f
--- /dev/null
+++ b/libaudiofile/debug.cpp
@@ -0,0 +1,272 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	debug.cpp
+
+	This file contains debugging routines for the Audio File
+	Library.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "aupvlist.h"
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "aupvinternal.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "debug.h"
+#include "units.h"
+#include "util.h"
+
+void _af_print_pvlist (AUpvlist list)
+{
+	assert(list);
+
+	printf("list.valid: %d\n", list->valid);
+	printf("list.count: %zu\n", list->count);
+
+	for (unsigned i=0; i<list->count; i++)
+	{
+		printf("item %u valid %d, should be %d\n",
+			i, list->items[i].valid, _AU_VALID_PVITEM);
+
+		switch (list->items[i].type)
+		{
+			case AU_PVTYPE_LONG:
+				printf("item #%u, parameter %d, long: %ld\n",
+					i, list->items[i].parameter,
+					list->items[i].value.l);
+				break;
+			case AU_PVTYPE_DOUBLE:
+				printf("item #%u, parameter %d, double: %f\n",
+					i, list->items[i].parameter,
+					list->items[i].value.d);
+				break;
+			case AU_PVTYPE_PTR:
+				printf("item #%u, parameter %d, pointer: %p\n",
+					i, list->items[i].parameter,
+					list->items[i].value.v);
+				break;
+
+			default:
+				printf("item #%u, invalid type %d\n", i,
+					list->items[i].type);
+				assert(false);
+				break;
+		}
+	}
+}
+
+void _af_print_audioformat (AudioFormat *fmt)
+{
+	/* sampleRate, channelCount */
+	printf("{ %7.2f Hz %d ch ", fmt->sampleRate, fmt->channelCount);
+
+	/* sampleFormat, sampleWidth */
+	switch (fmt->sampleFormat)
+	{
+		case AF_SAMPFMT_TWOSCOMP:
+			printf("%db 2 ", fmt->sampleWidth);
+			break;
+		case AF_SAMPFMT_UNSIGNED:
+			printf("%db u ", fmt->sampleWidth);
+			break;
+		case AF_SAMPFMT_FLOAT:
+			printf("flt ");
+			break;
+		case AF_SAMPFMT_DOUBLE:
+			printf("dbl ");
+			break;
+		default:
+			printf("%dsampfmt? ", fmt->sampleFormat);
+	}
+
+	/* pcm */
+	printf("(%.30g+-%.30g [%.30g,%.30g]) ",
+		fmt->pcm.intercept, fmt->pcm.slope,
+		fmt->pcm.minClip, fmt->pcm.maxClip);
+
+	/* byteOrder */
+	switch (fmt->byteOrder)
+	{
+		case AF_BYTEORDER_BIGENDIAN:
+			printf("big ");
+			break;
+		case AF_BYTEORDER_LITTLEENDIAN:
+			printf("little ");
+			break;
+		default:
+			printf("%dbyteorder? ", fmt->byteOrder);
+			break;
+	}
+
+	/* compression */
+	{
+		const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
+		if (!unit)
+			printf("%dcompression?", fmt->compressionType);
+		else if (fmt->compressionType == AF_COMPRESSION_NONE)
+			printf("pcm");
+		else
+			printf("%s", unit->label);
+	}
+
+	printf(" }");
+}
+
+void _af_print_tracks (AFfilehandle filehandle)
+{
+	for (int i=0; i<filehandle->m_trackCount; i++)
+	{
+		Track *track = &filehandle->m_tracks[i];
+		printf("track %d\n", i);
+		printf(" id %d\n", track->id);
+		printf(" sample format\n");
+		_af_print_audioformat(&track->f);
+		printf(" virtual format\n");
+		_af_print_audioformat(&track->v);
+		printf(" total file frames: %jd\n",
+			(intmax_t) track->totalfframes);
+		printf(" total virtual frames: %jd\n",
+			(intmax_t) track->totalvframes);
+		printf(" next file frame: %jd\n",
+			(intmax_t) track->nextfframe);
+		printf(" next virtual frame: %jd\n",
+			(intmax_t) track->nextvframe);
+		printf(" frames to ignore: %jd\n",
+			(intmax_t) track->frames2ignore);
+
+		printf(" data_size: %jd\n",
+			(intmax_t) track->data_size);
+		printf(" fpos_first_frame: %jd\n",
+			(intmax_t) track->fpos_first_frame);
+		printf(" fpos_next_frame: %jd\n",
+			(intmax_t) track->fpos_next_frame);
+		printf(" fpos_after_data: %jd\n",
+			(intmax_t) track->fpos_after_data);
+
+		printf(" channel matrix:");
+		_af_print_channel_matrix(track->channelMatrix,
+			track->f.channelCount, track->v.channelCount);
+		printf("\n");
+
+		printf(" marker count: %d\n", track->markerCount);
+	}
+}
+
+void _af_print_filehandle (AFfilehandle filehandle)
+{
+	printf("file handle: 0x%p\n", filehandle);
+
+	if (filehandle->m_valid == _AF_VALID_FILEHANDLE)
+		printf("valid\n");
+	else
+		printf("invalid!\n");
+
+	printf(" access: ");
+	if (filehandle->m_access == _AF_READ_ACCESS)
+		putchar('r');
+	else
+		putchar('w');
+
+	printf(" fileFormat: %d\n", filehandle->m_fileFormat);
+
+	printf(" instrument count: %d\n", filehandle->m_instrumentCount);
+	printf(" instruments: 0x%p\n", filehandle->m_instruments);
+
+	printf(" miscellaneous count: %d\n", filehandle->m_miscellaneousCount);
+	printf(" miscellaneous: 0x%p\n", filehandle->m_miscellaneous);
+
+	printf(" trackCount: %d\n", filehandle->m_trackCount);
+	printf(" tracks: 0x%p\n", filehandle->m_tracks);
+	_af_print_tracks(filehandle);
+}
+
+void _af_print_channel_matrix (double *matrix, int fchans, int vchans)
+{
+	int v, f;
+
+	if (!matrix)
+	{
+		printf("NULL");
+		return;
+	}
+
+	printf("{");
+	for (v=0; v < vchans; v++)
+	{
+		if (v) printf(" ");
+		printf("{");
+		for (f=0; f < fchans; f++)
+		{
+			if (f) printf(" ");
+			printf("%5.2f", *(matrix + v*fchans + f));
+		}
+		printf("}");
+	}
+	printf("}");
+}
+
+void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
+	char *formatstring, int numberwidth,
+	double slope, double intercept, double minclip, double maxclip)
+{
+	char linebuf[81];
+	int wavewidth = 78 - numberwidth*nchannels - 6;
+	int c;
+
+	memset(linebuf, ' ', 80);
+	linebuf[0] = '|';
+	linebuf[wavewidth-1] = '|';
+	linebuf[wavewidth] = 0;
+
+	printf("%05jd ", (intmax_t) frameno);
+
+	for (c=0; c < nchannels; c++)
+	{
+		double pcm = frame[c];
+		printf(formatstring, pcm);
+	}
+	for (c=0; c < nchannels; c++)
+	{
+		double pcm = frame[c], volts;
+		if (maxclip > minclip)
+		{
+			if (pcm < minclip) pcm = minclip;
+			if (pcm > maxclip) pcm = maxclip;
+		}
+		volts = (pcm - intercept) / slope;
+		linebuf[(int)((volts/2 + 0.5)*(wavewidth-3)) + 1] = '0' + c;
+	}
+	printf("%s\n", linebuf);
+}
diff --git a/libaudiofile/debug.h b/libaudiofile/debug.h
new file mode 100644
index 0000000..abb878f
--- /dev/null
+++ b/libaudiofile/debug.h
@@ -0,0 +1,45 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	debug.h
+
+	This header file declares debugging functions for the Audio
+	File Library.
+*/
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdint.h>
+#include "audiofile.h"
+#include "afinternal.h"
+
+void _af_print_filehandle (AFfilehandle filehandle);
+void _af_print_tracks (AFfilehandle filehandle);
+void _af_print_channel_matrix (double *matrix, int fchans, int vchans);
+void _af_print_pvlist (AUpvlist list);
+
+void _af_print_audioformat (AudioFormat *format);
+void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
+	char *formatstring, int numberwidth,
+	double slope, double intercept, double minclip, double maxclip);
+
+#endif
diff --git a/libaudiofile/error.c b/libaudiofile/error.c
new file mode 100644
index 0000000..da1e543
--- /dev/null
+++ b/libaudiofile/error.c
@@ -0,0 +1,69 @@
+/*
+	Audio File Library
+	Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	error.c
+
+	This file contains the routines used in the Audio File Library's
+	error handling.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include "audiofile.h"
+
+static void defaultErrorFunction (long error, const char *str);
+
+static AFerrfunc errorFunction = defaultErrorFunction;
+
+AFerrfunc afSetErrorHandler (AFerrfunc efunc)
+{
+	AFerrfunc	old;
+
+	old = errorFunction;
+	errorFunction = efunc;
+
+	return old;
+}
+
+static void defaultErrorFunction (long error, const char *str)
+{
+	fprintf(stderr, "Audio File Library: ");
+	fprintf(stderr, "%s", str);
+	fprintf(stderr, " [error %ld]\n", error);
+}
+
+void _af_error (int errorCode, const char *fmt, ...)
+{
+	char	buf[1024];
+	va_list	ap;
+
+	va_start(ap, fmt);
+
+	vsnprintf(buf, 1024, fmt, ap);
+
+	va_end(ap);
+
+	if (errorFunction != NULL)
+		errorFunction(errorCode, buf);
+}
diff --git a/libaudiofile/error.h b/libaudiofile/error.h
new file mode 100644
index 0000000..250dc95
--- /dev/null
+++ b/libaudiofile/error.h
@@ -0,0 +1,39 @@
+/*
+	Audio File Library
+	Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__GNUC__) && !defined(__clang__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+void _af_error (int errorCode, const char *fmt, ...)
+	__attribute__((format(printf, 2, 3)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libaudiofile/extended.c b/libaudiofile/extended.c
new file mode 100644
index 0000000..f1901ca
--- /dev/null
+++ b/libaudiofile/extended.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 1989-1991 Apple Computer, Inc.
+ *
+ * All rights reserved.
+ *
+ * Warranty Information
+ *  Even though Apple has reviewed this software, Apple makes no warranty
+ *  or representation, either express or implied, with respect to this
+ *  software, its quality, accuracy, merchantability, or fitness for a
+ *  particular purpose.  As a result, this software is provided "as is,"
+ *  and you, its user, are assuming the entire risk as to its quality
+ *  and accuracy.
+ *
+ * This code may be used and freely distributed as long as it includes
+ * this copyright notice and the above warranty information.
+ *
+ * Machine-independent I/O routines for IEEE floating-point numbers.
+ *
+ * NaN's and infinities are converted to HUGE_VAL or HUGE, which
+ * happens to be infinity on IEEE machines.  Unfortunately, it is
+ * impossible to preserve NaN's in a machine-independent way.
+ * Infinities are, however, preserved on IEEE machines.
+ *
+ * These routines have been tested on the following machines:
+ *	Apple Macintosh, MPW 3.1 C compiler
+ *	Apple Macintosh, THINK C compiler
+ *	Silicon Graphics IRIS, MIPS compiler
+ *	Cray X/MP and Y/MP
+ *	Digital Equipment VAX
+ *	Sequent Balance (Multiprocesor 386)
+ *	NeXT
+ *
+ *
+ * Implemented by Malcolm Slaney and Ken Turkowski.
+ *
+ * Malcolm Slaney contributions during 1988-1990 include big- and little-
+ * endian file I/O, conversion to and from Motorola's extended 80-bit
+ * floating-point format, and conversions to and from IEEE single-
+ * precision floating-point format.
+ *
+ * In 1991, Ken Turkowski implemented the conversions to and from
+ * IEEE double-precision format, added more precision to the extended
+ * conversions, and accommodated conversions involving +/- infinity,
+ * NaN's, and denormalized numbers.
+ */
+
+/****************************************************************
+ * Extended precision IEEE floating-point conversion routines.
+ * Extended is an 80-bit number as defined by Motorola,
+ * with a sign bit, 15 bits of exponent (offset 16383?),
+ * and a 64-bit mantissa, with no hidden bit.
+ ****************************************************************/
+
+#include "extended.h"
+
+#include <math.h>
+
+#ifndef HUGE_VAL
+#define HUGE_VAL HUGE
+#endif
+
+#define FloatToUnsigned(f) ((unsigned long) (((long) (f - 2147483648.0)) + 2147483647L) + 1)
+
+void _af_convert_to_ieee_extended (double num, unsigned char *bytes)
+{
+	int				sign;
+	int				expon;
+	double			fMant, fsMant;
+	unsigned long	hiMant, loMant;
+
+	if (num < 0) {
+		sign = 0x8000;
+		num *= -1;
+	} else {
+		sign = 0;
+	}
+
+	if (num == 0) {
+		expon = 0; hiMant = 0; loMant = 0;
+	}
+	else {
+		fMant = frexp(num, &expon);
+		if ((expon > 16384) || !(fMant < 1)) {	  /* Infinity or NaN */
+			expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
+		}
+		else {	  /* Finite */
+			expon += 16382;
+			if (expon < 0) {	/* denormalized */
+				fMant = ldexp(fMant, expon);
+				expon = 0;
+			}
+			expon |= sign;
+			fMant = ldexp(fMant, 32);
+			fsMant = floor(fMant);
+			hiMant = FloatToUnsigned(fsMant);
+			fMant = ldexp(fMant - fsMant, 32);
+			fsMant = floor(fMant);
+			loMant = FloatToUnsigned(fsMant);
+		}
+	}
+
+	bytes[0] = expon >> 8;
+	bytes[1] = expon;
+	bytes[2] = hiMant >> 24;
+	bytes[3] = hiMant >> 16;
+	bytes[4] = hiMant >> 8;
+	bytes[5] = hiMant;
+	bytes[6] = loMant >> 24;
+	bytes[7] = loMant >> 16;
+	bytes[8] = loMant >> 8;
+	bytes[9] = loMant;
+}
+
+#define UnsignedToFloat(u) (((double) ((long) (u - 2147483647L - 1))) + 2147483648.0)
+
+double _af_convert_from_ieee_extended (const unsigned char *bytes)
+{
+	double			f;
+	int				expon;
+	unsigned long	hiMant, loMant;
+
+	expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
+	hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
+		| ((unsigned long) (bytes[3] & 0xFF) << 16)
+		| ((unsigned long) (bytes[4] & 0xFF) << 8)
+		| ((unsigned long) (bytes[5] & 0xFF));
+	loMant = ((unsigned long) (bytes[6] & 0xFF) << 24)
+		| ((unsigned long) (bytes[7] & 0xFF) << 16)
+		| ((unsigned long) (bytes[8] & 0xFF) << 8)
+		| ((unsigned long) (bytes[9] & 0xFF));
+
+	if (expon == 0 && hiMant == 0 && loMant == 0) {
+		f = 0;
+	}
+	else {
+		if (expon == 0x7FFF) {	  /* Infinity or NaN */
+			f = HUGE_VAL;
+		}
+		else {
+			expon -= 16383;
+			f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
+			f += ldexp(UnsignedToFloat(loMant), expon-=32);
+		}
+	}
+
+	if (bytes[0] & 0x80)
+		return -f;
+	else
+		return f;
+}
diff --git a/libaudiofile/extended.h b/libaudiofile/extended.h
new file mode 100644
index 0000000..e0647dd
--- /dev/null
+++ b/libaudiofile/extended.h
@@ -0,0 +1,42 @@
+/*
+	Audio File Library
+	Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	extended.h
+
+	This file defines interfaces to Apple's extended floating-point
+	conversion routines.
+*/
+
+#ifndef EXTENDED_H
+#define EXTENDED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _af_convert_to_ieee_extended (double num, unsigned char *bytes);
+double _af_convert_from_ieee_extended (const unsigned char *bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libaudiofile/format.cpp b/libaudiofile/format.cpp
new file mode 100644
index 0000000..01ba521
--- /dev/null
+++ b/libaudiofile/format.cpp
@@ -0,0 +1,385 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	audiofile.c
+
+	This file implements many of the main interface routines of the
+	Audio File Library.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "modules/Module.h"
+#include "modules/ModuleState.h"
+#include "units.h"
+#include "util.h"
+
+AFfileoffset afGetDataOffset (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->fpos_first_frame;
+}
+
+AFfileoffset afGetTrackBytes (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->data_size;
+}
+
+/*
+	afGetFrameSize returns the size (in bytes) of a sample frame from
+	the specified track of an audio file.
+
+	stretch3to4 == true: size which user sees
+	stretch3to4 == false: size used in file
+*/
+float afGetFrameSize (AFfilehandle file, int trackid, int stretch3to4)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return _af_format_frame_size(&track->f, stretch3to4);
+}
+
+float afGetVirtualFrameSize (AFfilehandle file, int trackid, int stretch3to4)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return _af_format_frame_size(&track->v, stretch3to4);
+}
+
+AFframecount afSeekFrame (AFfilehandle file, int trackid, AFframecount frame)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (!file->checkCanRead())
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
+		return -1;
+
+	if (frame < 0)
+		return track->nextvframe;
+
+	/* Optimize the case of seeking to the current position. */
+	if (frame == track->nextvframe)
+		return track->nextvframe;
+
+	/* Limit request to the number of frames in the file. */
+	if (track->totalvframes != -1)
+		if (frame > track->totalvframes)
+			frame = track->totalvframes - 1;
+
+	/*
+		Now that the modules are not dirty and frame
+		represents a valid virtual frame, we call
+		_AFsetupmodules again after setting track->nextvframe.
+
+		_AFsetupmodules will look at track->nextvframe and
+		compute track->nextfframe in clever and mysterious
+		ways.
+	*/
+	track->nextvframe = frame;
+
+	if (track->ms->setup(file, track) == AF_FAIL)
+		return -1;
+
+	return track->nextvframe;
+}
+
+AFfileoffset afTellFrame (AFfilehandle file, int trackid)
+{
+	return afSeekFrame(file, trackid, -1);
+}
+
+int afSetVirtualByteOrder (AFfilehandle file, int trackid, int byteorder)
+{
+	if (!_af_filehandle_ok(file))
+		return AF_FAIL;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return AF_FAIL;
+
+	if (byteorder != AF_BYTEORDER_BIGENDIAN &&
+		byteorder != AF_BYTEORDER_LITTLEENDIAN)
+	{
+		_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
+		return AF_FAIL;
+	}
+
+	track->v.byteOrder = byteorder;
+	track->ms->setDirty();
+
+	return AF_SUCCEED;
+}
+
+int afGetByteOrder (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->f.byteOrder;
+}
+
+int afGetVirtualByteOrder (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->v.byteOrder;
+}
+
+AFframecount afGetFrameCount (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
+		return -1;
+
+	return track->totalvframes;
+}
+
+double afGetRate (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->f.sampleRate;
+}
+
+int afGetChannels (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->f.channelCount;
+}
+
+void afGetSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (sampleFormat)
+		*sampleFormat = track->f.sampleFormat;
+
+	if (sampleWidth)
+		*sampleWidth = track->f.sampleWidth;
+}
+
+void afGetVirtualSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (sampleFormat)
+		*sampleFormat = track->v.sampleFormat;
+
+	if (sampleWidth)
+		*sampleWidth = track->v.sampleWidth;
+}
+
+int afSetVirtualSampleFormat (AFfilehandle file, int trackid,
+	int sampleFormat, int sampleWidth)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (_af_set_sample_format(&track->v, sampleFormat, sampleWidth) == AF_FAIL)
+		return -1;
+
+	track->ms->setDirty();
+
+	return 0;
+}
+
+/* XXXmpruett fix the version */
+int afGetFileFormat (AFfilehandle file, int *version)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	if (version != NULL)
+		*version = file->getVersion();
+
+	return file->m_fileFormat;
+}
+
+int afSetVirtualChannels (AFfilehandle file, int trackid, int channelCount)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	track->v.channelCount = channelCount;
+	track->ms->setDirty();
+
+	if (track->channelMatrix)
+		free(track->channelMatrix);
+	track->channelMatrix = NULL;
+
+	return 0;
+}
+
+double afGetVirtualRate (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->v.sampleRate;
+}
+
+int afSetVirtualRate (AFfilehandle file, int trackid, double rate)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	if (rate < 0)
+	{
+		_af_error(AF_BAD_RATE, "invalid sampling rate %.30g", rate);
+		return -1;
+	}
+
+	track->v.sampleRate = rate;
+	track->ms->setDirty();
+
+	return 0;
+}
+
+void afSetChannelMatrix (AFfilehandle file, int trackid, double* matrix)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (track->channelMatrix != NULL)
+		free(track->channelMatrix);
+	track->channelMatrix = NULL;
+
+	if (matrix != NULL)
+	{
+		int	i, size;
+
+		size = track->v.channelCount * track->f.channelCount;
+
+		track->channelMatrix = (double *) malloc(size * sizeof (double));
+
+		for (i = 0; i < size; i++)
+			track->channelMatrix[i] = matrix[i];
+	}
+}
+
+int afGetVirtualChannels (AFfilehandle file, int trackid)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	return track->v.channelCount;
+}
diff --git a/libaudiofile/g711.c b/libaudiofile/g711.c
new file mode 100644
index 0000000..8fb2323
--- /dev/null
+++ b/libaudiofile/g711.c
@@ -0,0 +1,227 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#define SUPERCEDED
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
+#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
+#define	NSEGS		(8)		/* Number of A-law segments. */
+#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
+#define	SEG_MASK	(0x70)		/* Segment field mask. */
+
+/* see libst.h */
+#ifdef	SUPERCEDED
+
+static const short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+			    0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
+
+static int search(int val, const short *table, int size)
+{
+	int		i;
+
+	for (i = 0; i < size; i++) {
+		if (val <= *table++)
+			return (i);
+	}
+	return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ *		Linear Input Code	Compressed Code
+ *	------------------------	---------------
+ *	0000000wxyza			000wxyz
+ *	0000001wxyza			001wxyz
+ *	000001wxyzab			010wxyz
+ *	00001wxyzabc			011wxyz
+ *	0001wxyzabcd			100wxyz
+ *	001wxyzabcde			101wxyz
+ *	01wxyzabcdef			110wxyz
+ *	1wxyzabcdefg			111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+_af_linear2alaw(pcm_val)
+	int		pcm_val;	/* 2's complement (16-bit range) */
+{
+	int		mask;
+	int		seg;
+	unsigned char	aval;
+
+	if (pcm_val >= 0) {
+		mask = 0xD5;		/* sign (7th) bit = 1 */
+	} else {
+		mask = 0x55;		/* sign bit = 0 */
+		pcm_val = -pcm_val - 8;
+	}
+
+	/* Convert the scaled magnitude to segment number. */
+	seg = search(pcm_val, seg_end, 8);
+
+	/* Combine the sign, segment, and quantization bits. */
+
+	if (seg >= 8)		/* out of range, return maximum value. */
+		return (0x7F ^ mask);
+	else {
+		aval = seg << SEG_SHIFT;
+		if (seg < 2)
+			aval |= (pcm_val >> 4) & QUANT_MASK;
+		else
+			aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+		return (aval ^ mask);
+	}
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+int
+_af_alaw2linear(a_val)
+	unsigned char	a_val;
+{
+	int		t;
+	int		seg;
+
+	a_val ^= 0x55;
+
+	t = (a_val & QUANT_MASK) << 4;
+	seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+	switch (seg) {
+	case 0:
+		t += 8;
+		break;
+	case 1:
+		t += 0x108;
+		break;
+	default:
+		t += 0x108;
+		t <<= seg - 1;
+	}
+	return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define	BIAS		(0x84)		/* Bias for linear code. */
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ *	Biased Linear Input Code	Compressed Code
+ *	------------------------	---------------
+ *	00000001wxyza			000wxyz
+ *	0000001wxyzab			001wxyz
+ *	000001wxyzabc			010wxyz
+ *	00001wxyzabcd			011wxyz
+ *	0001wxyzabcde			100wxyz
+ *	001wxyzabcdef			101wxyz
+ *	01wxyzabcdefg			110wxyz
+ *	1wxyzabcdefgh			111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz.  * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* 2's complement (16-bit range) */
+unsigned char _af_linear2ulaw (int pcm_val)
+{
+	int		mask;
+	int		seg;
+	unsigned char	uval;
+
+	/* Get the sign and the magnitude of the value. */
+	if (pcm_val < 0) {
+		pcm_val = BIAS - pcm_val;
+		mask = 0x7F;
+	} else {
+		pcm_val += BIAS;
+		mask = 0xFF;
+	}
+
+	/* Convert the scaled magnitude to segment number. */
+	seg = search(pcm_val, seg_end, 8);
+
+	/*
+	 * Combine the sign, segment, quantization bits;
+	 * and complement the code word.
+	 */
+	if (seg >= 8)		/* out of range, return maximum value. */
+		return (0x7F ^ mask);
+	else {
+		uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+		return (uval ^ mask);
+	}
+
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int _af_ulaw2linear (unsigned char u_val)
+{
+	int		t;
+
+	/* Complement to obtain normal u-law value. */
+	u_val = ~u_val;
+
+	/*
+	 * Extract and bias the quantization bits. Then
+	 * shift up by the segment number and subtract out the bias.
+	 */
+	t = ((u_val & QUANT_MASK) << 3) + BIAS;
+	t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+#endif
diff --git a/libaudiofile/g711.h b/libaudiofile/g711.h
new file mode 100644
index 0000000..71fa23e
--- /dev/null
+++ b/libaudiofile/g711.h
@@ -0,0 +1,119 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * g711.h
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+
+#ifndef G711_H
+#define G711_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ *		Linear Input Code	Compressed Code
+ *	------------------------	---------------
+ *	0000000wxyza			000wxyz
+ *	0000001wxyza			001wxyz
+ *	000001wxyzab			010wxyz
+ *	00001wxyzabc			011wxyz
+ *	0001wxyzabcd			100wxyz
+ *	001wxyzabcde			101wxyz
+ *	01wxyzabcdef			110wxyz
+ *	1wxyzabcdefg			111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* pcm_val is 2's complement (16-bit range) */
+unsigned char _af_linear2alaw (int pcm_val);
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+
+int _af_alaw2linear (unsigned char a_val);
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ *	Biased Linear Input Code	Compressed Code
+ *	------------------------	---------------
+ *	00000001wxyza			000wxyz
+ *	0000001wxyzab			001wxyz
+ *	000001wxyzabc			010wxyz
+ *	00001wxyzabcd			011wxyz
+ *	0001wxyzabcde			100wxyz
+ *	001wxyzabcdef			101wxyz
+ *	01wxyzabcdefg			110wxyz
+ *	1wxyzabcdefgh			111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz.  * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* pcm_val is 2's complement (16-bit range) */
+unsigned char _af_linear2ulaw (int pcm_val);
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+
+int _af_ulaw2linear (unsigned char u_val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* G711_H */
diff --git a/libaudiofile/modules/ALAC.cpp b/libaudiofile/modules/ALAC.cpp
new file mode 100644
index 0000000..7593c11
--- /dev/null
+++ b/libaudiofile/modules/ALAC.cpp
@@ -0,0 +1,383 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "ALAC.h"
+
+#include "Buffer.h"
+#include "Compiler.h"
+#include "File.h"
+#include "FileModule.h"
+#include "PacketTable.h"
+#include "SimpleModule.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "units.h"
+#include "util.h"
+
+#include "../alac/ALACBitUtilities.h"
+#include "../alac/ALACDecoder.h"
+#include "../alac/ALACEncoder.h"
+
+#include <assert.h>
+#include <string.h>
+
+enum
+{
+	kALACFormatFlag_16BitSourceData = 1,
+	kALACFormatFlag_20BitSourceData = 2,
+	kALACFormatFlag_24BitSourceData = 3,
+	kALACFormatFlag_32BitSourceData = 4
+};
+
+class ALAC : public FileModule
+{
+public:
+	static ALAC *createDecompress(Track *, File *, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+	static ALAC *createCompress(Track *, File *, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual ~ALAC();
+
+	virtual const char *name() const OVERRIDE
+	{
+		return mode() == Compress ?  "alac_compress" : "alac_decompress";
+	}
+	virtual void describe() OVERRIDE;
+	virtual void runPull() OVERRIDE;
+	virtual void reset1() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+	virtual int bufferSize() const OVERRIDE;
+
+private:
+	AFframecount m_framesToIgnore;
+	AFfileoffset m_savedPositionNextFrame;
+	AFframecount m_savedNextFrame;
+
+	SharedPtr<Buffer> m_codecData;
+	ALACDecoder *m_decoder;
+	ALACEncoder *m_encoder;
+	int m_currentPacket;
+
+	ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData);
+	void initDecoder();
+	void initEncoder();
+
+	AudioFormatDescription outputFormat() const;
+};
+
+ALAC::ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData) :
+	FileModule(mode, track, fh, canSeek),
+	m_savedPositionNextFrame(-1),
+	m_savedNextFrame(-1),
+	m_codecData(codecData),
+	m_decoder(NULL),
+	m_encoder(NULL),
+	m_currentPacket(0)
+{
+	if (mode == Decompress)
+		initDecoder();
+	else
+		initEncoder();
+}
+
+ALAC::~ALAC()
+{
+	delete m_decoder;
+	delete m_encoder;
+}
+
+void ALAC::initDecoder()
+{
+	m_decoder = new ALACDecoder();
+	m_decoder->Init(m_codecData->data(), m_codecData->size());
+}
+
+void ALAC::initEncoder()
+{
+	m_encoder = new ALACEncoder();
+	m_encoder->SetFrameSize(m_track->f.framesPerPacket);
+	m_encoder->InitializeEncoder(outputFormat());
+
+	uint32_t cookieSize = m_encoder->GetMagicCookieSize(m_track->f.channelCount);
+	assert(cookieSize == m_codecData->size());
+	m_encoder->GetMagicCookie(m_codecData->data(), &cookieSize);
+
+	void *v = NULL;
+	_af_pv_getptr(m_track->f.compressionParams, _AF_CODEC_DATA, &v);
+	::memcpy(v, m_codecData->data(), cookieSize);
+}
+
+AudioFormatDescription ALAC::outputFormat() const
+{
+	AudioFormatDescription outputFormat;
+	outputFormat.mSampleRate = m_track->f.sampleRate;
+	outputFormat.mFormatID = kALACFormatAppleLossless;
+	switch (m_track->f.sampleWidth)
+	{
+		case 16:
+			outputFormat.mFormatFlags = kALACFormatFlag_16BitSourceData; break;
+		case 20:
+			outputFormat.mFormatFlags = kALACFormatFlag_20BitSourceData; break;
+		case 24:
+			outputFormat.mFormatFlags = kALACFormatFlag_24BitSourceData; break;
+		case 32:
+			outputFormat.mFormatFlags = kALACFormatFlag_32BitSourceData; break;
+		default:
+			outputFormat.mFormatFlags = 0; break;
+	}
+	outputFormat.mFramesPerPacket = m_track->f.framesPerPacket;
+	outputFormat.mChannelsPerFrame = m_track->f.channelCount;
+	outputFormat.mBytesPerPacket = 0;
+	outputFormat.mBytesPerFrame = 0;
+	outputFormat.mBitsPerChannel = 0;
+	outputFormat.mReserved = 0;
+	return outputFormat;
+}
+
+void ALAC::describe()
+{
+	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
+	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
+}
+
+ALAC *ALAC::createDecompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	AUpvlist pv = (AUpvlist) track->f.compressionParams;
+	long codecDataSize;
+	if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
+		return NULL;
+	}
+
+	SharedPtr<Buffer> codecData = new Buffer(codecDataSize);
+
+	void *data;
+	if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
+		return NULL;
+	}
+
+	memcpy(codecData->data(), data, codecDataSize);
+
+	*chunkFrames = track->f.framesPerPacket;
+
+	return new ALAC(Decompress, track, fh, canSeek, codecData.get());
+}
+
+ALAC *ALAC::createCompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	AUpvlist pv = (AUpvlist) track->f.compressionParams;
+	long codecDataSize;
+	if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
+		return NULL;
+	}
+
+	SharedPtr<Buffer> codecData = new Buffer(codecDataSize);
+
+	void *data;
+	if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
+		return NULL;
+	}
+
+	memcpy(codecData->data(), data, codecDataSize);
+
+	*chunkFrames = track->f.framesPerPacket;
+
+	return new ALAC(Compress, track, fh, canSeek, codecData.get());
+}
+
+void ALAC::runPull()
+{
+	SharedPtr<PacketTable> packetTable = m_track->m_packetTable;
+	if (m_currentPacket >= static_cast<int>(packetTable->numPackets()))
+	{
+		m_outChunk->frameCount = 0;
+		return;
+	}
+	assert(m_currentPacket < static_cast<int>(packetTable->numPackets()));
+
+	ssize_t bytesPerPacket = packetTable->bytesPerPacket(m_currentPacket);
+	assert(bytesPerPacket <= bufferSize());
+
+	if (read(m_inChunk->buffer, bytesPerPacket) < bytesPerPacket)
+	{
+		reportReadError(0, m_track->f.framesPerPacket);
+		return;
+	}
+
+	BitBuffer bitBuffer;
+	BitBufferInit(&bitBuffer, static_cast<uint8_t *>(m_inChunk->buffer),
+		bytesPerPacket);
+
+	uint32_t numFrames;
+	m_decoder->Decode(&bitBuffer, static_cast<uint8_t *>(m_outChunk->buffer),
+		m_track->f.framesPerPacket, m_track->f.channelCount, &numFrames);
+	m_outChunk->frameCount = numFrames;
+
+	m_currentPacket++;
+}
+
+void ALAC::reset1()
+{
+	AFframecount nextFrame = m_track->nextfframe;
+	m_currentPacket = nextFrame / m_track->f.framesPerPacket;
+	m_track->nextfframe = m_currentPacket * m_track->f.framesPerPacket;
+	m_framesToIgnore = nextFrame - m_track->nextfframe;
+}
+
+void ALAC::reset2()
+{
+	m_track->fpos_next_frame = m_track->fpos_first_frame +
+		m_track->m_packetTable->startOfPacket(m_currentPacket);
+	m_track->frames2ignore += m_framesToIgnore;
+}
+
+int ALAC::bufferSize() const
+{
+	return m_track->f.framesPerPacket * m_track->f.channelCount *
+		((10 + m_track->f.sampleWidth) / 8) + 1;
+}
+
+void ALAC::runPush()
+{
+	AudioFormatDescription inputFormat;
+	inputFormat.mSampleRate = m_track->f.sampleRate;
+	inputFormat.mFormatID = kALACFormatLinearPCM;
+	inputFormat.mFormatFlags = kALACFormatFlagsNativeEndian;
+	inputFormat.mBytesPerPacket = _af_format_frame_size_uncompressed(&m_track->f, false);
+	inputFormat.mFramesPerPacket = 1;
+	inputFormat.mBytesPerFrame = _af_format_frame_size_uncompressed(&m_track->f, false);
+	inputFormat.mChannelsPerFrame = m_track->f.channelCount;
+	inputFormat.mBitsPerChannel = m_track->f.sampleWidth;
+	inputFormat.mReserved = 0;
+
+	int32_t numBytes = m_inChunk->frameCount * inputFormat.mBytesPerFrame;
+	int32_t result = m_encoder->Encode(inputFormat, outputFormat(),
+		static_cast<uint8_t *>(m_inChunk->buffer),
+		static_cast<uint8_t *>(m_outChunk->buffer),
+		&numBytes);
+	if (result)
+	{
+		_af_error(AF_BAD_CODEC_STATE, "error encoding ALAC audio data");
+		m_track->filemodhappy = false;
+		return;
+	}
+
+	assert(numBytes <= bufferSize());
+
+	ssize_t bytesWritten = write(m_outChunk->buffer, numBytes);
+	if (bytesWritten != numBytes)
+	{
+		reportWriteError(0, m_track->f.framesPerPacket);
+		return;
+	}
+
+	PacketTable *packetTable = m_track->m_packetTable.get();
+
+	packetTable->append(numBytes);
+
+	packetTable->setNumValidFrames(packetTable->numValidFrames() +
+		m_inChunk->frameCount);
+}
+
+void ALAC::sync1()
+{
+	m_savedPositionNextFrame = m_track->fpos_next_frame;
+	m_savedNextFrame = m_track->nextfframe;
+}
+
+void ALAC::sync2()
+{
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+
+	m_track->fpos_after_data = tell();
+
+	m_track->fpos_next_frame = m_savedPositionNextFrame;
+	m_track->nextfframe = m_savedNextFrame;
+}
+
+bool _af_alac_format_ok (AudioFormat *f)
+{
+	if (f->channelCount > kALACMaxChannels)
+	{
+		_af_error(AF_BAD_CHANNELS,
+			"ALAC compression supports a maximum of 8 channels");
+		return false;
+	}
+
+	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"ALAC compression requires signed integer audio data");
+		return false;
+	}
+
+	if (f->sampleWidth != 16 &&
+		f->sampleWidth != 20 &&
+		f->sampleWidth != 24 &&
+		f->sampleWidth != 32)
+	{
+		_af_error(AF_BAD_WIDTH,
+			"ALAC compression requires 16, 20, 24, or 32 bits per sample");
+		return false;
+	}
+
+	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"ALAC compression requires native-endian format");
+		f->byteOrder = _AF_BYTEORDER_NATIVE;
+	}
+
+	return true;
+}
+
+FileModule *_af_alac_init_decompress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return ALAC::createDecompress(track, fh, canSeek, headerless, chunkFrames);
+}
+
+FileModule *_af_alac_init_compress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return ALAC::createCompress(track, fh, canSeek, headerless, chunkFrames);
+}
diff --git a/libaudiofile/modules/ALAC.h b/libaudiofile/modules/ALAC.h
new file mode 100644
index 0000000..8d5882a
--- /dev/null
+++ b/libaudiofile/modules/ALAC.h
@@ -0,0 +1,41 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef ALAC_h
+#define ALAC_h
+
+#include "Module.h"
+#include "afinternal.h"
+#include "audiofile.h"
+
+class File;
+class FileModule;
+struct AudioFormat;
+struct Track;
+
+bool _af_alac_format_ok (AudioFormat *f);
+
+FileModule *_af_alac_init_decompress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+FileModule *_af_alac_init_compress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+#endif
diff --git a/libaudiofile/modules/BlockCodec.cpp b/libaudiofile/modules/BlockCodec.cpp
new file mode 100644
index 0000000..4731be1
--- /dev/null
+++ b/libaudiofile/modules/BlockCodec.cpp
@@ -0,0 +1,127 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "BlockCodec.h"
+
+#include "Track.h"
+
+#include <assert.h>
+
+BlockCodec::BlockCodec(Mode mode, Track *track, File *fh, bool canSeek) :
+	FileModule(mode, track, fh, canSeek),
+	m_bytesPerPacket(-1),
+	m_framesPerPacket(-1),
+	m_framesToIgnore(-1),
+	m_savedPositionNextFrame(-1),
+	m_savedNextFrame(-1)
+{
+	m_framesPerPacket = track->f.framesPerPacket;
+	m_bytesPerPacket = track->f.bytesPerPacket;
+}
+
+void BlockCodec::runPull()
+{
+	AFframecount framesToRead = m_outChunk->frameCount;
+	AFframecount framesRead = 0;
+
+	assert(framesToRead % m_framesPerPacket == 0);
+	int blockCount = framesToRead / m_framesPerPacket;
+
+	// Read the compressed data.
+	ssize_t bytesRead = read(m_inChunk->buffer, m_bytesPerPacket * blockCount);
+	int blocksRead = bytesRead >= 0 ? bytesRead / m_bytesPerPacket : 0;
+
+	// Decompress into m_outChunk.
+	for (int i=0; i<blocksRead; i++)
+	{
+		if (decodeBlock(static_cast<const uint8_t *>(m_inChunk->buffer) + i * m_bytesPerPacket,
+			static_cast<int16_t *>(m_outChunk->buffer) + i * m_framesPerPacket * m_track->f.channelCount)==0)
+			break;
+
+		framesRead += m_framesPerPacket;
+	}
+
+	m_track->nextfframe += framesRead;
+
+	assert(tell() == m_track->fpos_next_frame);
+
+	if (framesRead < framesToRead)
+		reportReadError(framesRead, framesToRead);
+
+	m_outChunk->frameCount = framesRead;
+}
+
+void BlockCodec::reset1()
+{
+	AFframecount nextTrackFrame = m_track->nextfframe;
+	m_track->nextfframe = (nextTrackFrame / m_framesPerPacket) *
+		m_framesPerPacket;
+
+	m_framesToIgnore = nextTrackFrame - m_track->nextfframe;
+}
+
+void BlockCodec::reset2()
+{
+	m_track->fpos_next_frame = m_track->fpos_first_frame +
+		m_bytesPerPacket * (m_track->nextfframe / m_framesPerPacket);
+	m_track->frames2ignore += m_framesToIgnore;
+
+	assert(m_track->nextfframe % m_framesPerPacket == 0);
+}
+
+void BlockCodec::runPush()
+{
+	AFframecount framesToWrite = m_inChunk->frameCount;
+	int channelCount = m_inChunk->f.channelCount;
+
+	int blockCount = (framesToWrite + m_framesPerPacket - 1) / m_framesPerPacket;
+	for (int i=0; i<blockCount; i++)
+	{
+		encodeBlock(static_cast<const int16_t *>(m_inChunk->buffer) + i * m_framesPerPacket * channelCount,
+			static_cast<uint8_t *>(m_outChunk->buffer) + i * m_bytesPerPacket);
+	}
+
+	ssize_t bytesWritten = write(m_outChunk->buffer, m_bytesPerPacket * blockCount);
+	ssize_t blocksWritten = bytesWritten >= 0 ? bytesWritten / m_bytesPerPacket : 0;
+	AFframecount framesWritten = std::min((AFframecount) blocksWritten * m_framesPerPacket, framesToWrite);
+
+	m_track->nextfframe += framesWritten;
+	m_track->totalfframes = m_track->nextfframe;
+
+	assert(tell() == m_track->fpos_next_frame);
+
+	if (framesWritten < framesToWrite)
+		reportWriteError(framesWritten, framesToWrite);
+}
+
+void BlockCodec::sync1()
+{
+	m_savedPositionNextFrame = m_track->fpos_next_frame;
+	m_savedNextFrame = m_track->nextfframe;
+}
+
+void BlockCodec::sync2()
+{
+	assert(tell() == m_track->fpos_next_frame);
+	m_track->fpos_after_data = tell();
+	m_track->fpos_next_frame = m_savedPositionNextFrame;
+	m_track->nextfframe = m_savedNextFrame;
+}
diff --git a/libaudiofile/modules/BlockCodec.h b/libaudiofile/modules/BlockCodec.h
new file mode 100644
index 0000000..eb839d7
--- /dev/null
+++ b/libaudiofile/modules/BlockCodec.h
@@ -0,0 +1,51 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+// BlockCodec is a base class for codecs with fixed-size packets.
+
+#ifndef BlockCodec_h
+#define BlockCodec_h
+
+#include "Compiler.h"
+#include "FileModule.h"
+
+class BlockCodec : public FileModule
+{
+public:
+	virtual void runPull() OVERRIDE;
+	virtual void reset1() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+
+protected:
+	int m_bytesPerPacket, m_framesPerPacket;
+	AFframecount m_framesToIgnore;
+	AFfileoffset m_savedPositionNextFrame;
+	AFframecount m_savedNextFrame;
+
+	BlockCodec(Mode, Track *, File *, bool canSeek);
+
+	virtual int decodeBlock(const uint8_t *encoded, int16_t *decoded) = 0;
+	virtual int encodeBlock(const int16_t *decoded, uint8_t *encoded) = 0;
+};
+
+#endif
diff --git a/libaudiofile/modules/FLAC.cpp b/libaudiofile/modules/FLAC.cpp
new file mode 100644
index 0000000..aaf9e5b
--- /dev/null
+++ b/libaudiofile/modules/FLAC.cpp
@@ -0,0 +1,511 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "FLAC.h"
+
+#include "Compiler.h"
+#include "FileModule.h"
+#include "Features.h"
+#include "Track.h"
+#include "byteorder.h"
+
+#if ENABLE(FLAC)
+
+#include <FLAC/stream_decoder.h>
+#include <FLAC/stream_encoder.h>
+#include <assert.h>
+#include <string.h>
+#include <algorithm>
+#include <vector>
+
+class FLACDecoder : public FileModule
+{
+public:
+	static FLACDecoder *create(Track *track, File *file, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual ~FLACDecoder();
+
+	virtual const char *name() const OVERRIDE { return "flac_decompress"; }
+
+	virtual void describe() OVERRIDE;
+	virtual void runPull() OVERRIDE;
+	virtual void reset1() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+
+	virtual bool handlesSeeking() const OVERRIDE { return true; }
+
+private:
+	FLACDecoder(Track *track, File *file, bool canSeek);
+
+	FLAC__StreamDecoder *m_decoder;
+	std::vector<int32_t *> m_buffer;
+	int m_bufferedFrames, m_bufferedOffset;
+
+	void convertAndInterleave(int offset, int frameCount);
+
+	static FLAC__StreamDecoderReadStatus readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		ssize_t result = flac->read(buffer, *bytes);
+		if (result > 0)
+		{
+			*bytes = result;
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		}
+
+		*bytes = 0;
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+	}
+
+	static FLAC__StreamDecoderSeekStatus seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		if (flac->seek(absoluteByteOffset) < 0)
+			return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+	}
+
+	static FLAC__StreamDecoderTellStatus tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		off_t result = flac->tell();
+		if (result < 0)
+			return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+		*absoluteByteOffset = static_cast<FLAC__uint64>(result);
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+
+	static FLAC__StreamDecoderLengthStatus lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		off_t result = flac->length();
+		if (result < 0)
+			return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+		*length = result;
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+
+	static FLAC__bool eofCallback(const FLAC__StreamDecoder *, void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		return flac->tell() == flac->length();
+	}
+
+	static FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData)
+	{
+		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
+		flac->didDecodeFrame(frame, buffer);
+		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	}
+
+	static void metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData)
+	{
+	}
+
+	static void errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "FLAC decoding error %d", status);
+	}
+
+	void didDecodeFrame(const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+	{
+		m_bufferedFrames = frame->header.blocksize;
+		m_bufferedOffset = 0;
+		for (unsigned c=0; c<frame->header.channels; c++)
+			memcpy(m_buffer[c], buffer[c], frame->header.blocksize * sizeof (int32_t));
+
+		m_track->nextfframe += frame->header.blocksize;
+	}
+};
+
+FLACDecoder *FLACDecoder::create(Track *track, File *file, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return new FLACDecoder(track, file, canSeek);
+}
+
+FLACDecoder::FLACDecoder(Track *track, File *file, bool canSeek) :
+	FileModule(Decompress, track, file, canSeek),
+	m_decoder(NULL),
+	m_bufferedFrames(0),
+	m_bufferedOffset(0)
+{
+	m_decoder = FLAC__stream_decoder_new();
+
+	if (FLAC__stream_decoder_init_stream(m_decoder,
+		readCallback,
+		seekCallback,
+		tellCallback,
+		lengthCallback,
+		eofCallback,
+		writeCallback,
+		metadataCallback,
+		errorCallback,
+		this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC decoder");
+		return;
+	}
+
+	m_buffer.resize(m_track->f.channelCount);
+	for (int c=0; c<m_track->f.channelCount; c++)
+		m_buffer[c] = new int32_t[FLAC__MAX_BLOCK_SIZE];
+}
+
+FLACDecoder::~FLACDecoder()
+{
+	if (m_decoder)
+	{
+		FLAC__stream_decoder_delete(m_decoder);
+		m_decoder = NULL;
+	}
+
+	for (size_t i=0; i<m_buffer.size(); i++)
+		delete [] m_buffer[i];
+}
+
+void FLACDecoder::describe()
+{
+	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
+	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
+}
+
+void FLACDecoder::convertAndInterleave(int offset, int frameCount)
+{
+	int channelCount = m_outChunk->f.channelCount;
+
+	if (m_track->f.sampleWidth == 16)
+	{
+		int16_t *out = static_cast<int16_t *>(m_outChunk->buffer);
+		for (int i=0; i<frameCount; i++)
+		{
+			for (int c=0; c<channelCount; c++)
+			{
+				int outIndex = (offset+i) * channelCount + c;
+				out[outIndex] = m_buffer[c][m_bufferedOffset + i];
+			}
+		}
+	}
+	else if (m_track->f.sampleWidth == 24)
+	{
+		uint8_t *out = static_cast<uint8_t *>(m_outChunk->buffer);
+		for (int i=0; i<frameCount; i++)
+		{
+			for (int c=0; c<channelCount; c++)
+			{
+				int32_t in = m_buffer[c][m_bufferedOffset + i];
+				uint8_t c0, c1, c2;
+
+#ifdef WORDS_BIGENDIAN
+				c0 = (in >> 16) & 0xff;
+				c1 = (in >> 8) & 0xff;
+				c2 = in & 0xff;
+#else
+				c2 = (in >> 16) & 0xff;
+				c1 = (in >> 8) & 0xff;
+				c0 = in & 0xff;
+#endif
+
+				int outIndex = (offset+i) * channelCount + c;
+				out[3*outIndex] = c0;
+				out[3*outIndex+1] = c1;
+				out[3*outIndex+2] = c2;
+			}
+		}
+	}
+
+	m_bufferedOffset += frameCount;
+}
+
+void FLACDecoder::runPull()
+{
+	int framesToRead = m_outChunk->frameCount;
+	int offset = 0;
+	while (framesToRead > 0)
+	{
+		int bufferedFramesToRead = std::min<int>(framesToRead,
+			m_bufferedFrames - m_bufferedOffset);
+		convertAndInterleave(offset, bufferedFramesToRead);
+		offset += bufferedFramesToRead;
+		framesToRead -= bufferedFramesToRead;
+
+		if (framesToRead > 0)
+		{
+			if (!FLAC__stream_decoder_process_single(m_decoder))
+				break;
+			if (FLAC__stream_decoder_get_state(m_decoder) >= FLAC__STREAM_DECODER_END_OF_STREAM)
+				break;
+		}
+	}
+}
+
+void FLACDecoder::reset1()
+{
+}
+
+void FLACDecoder::reset2()
+{
+	if (!FLAC__stream_decoder_seek_absolute(m_decoder, m_track->nextfframe))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not seek to frame %jd",
+			static_cast<intmax_t>(m_track->nextfframe));
+	}
+}
+
+class FLACEncoder : public FileModule
+{
+public:
+	static FLACEncoder *create(Track *track, File *file, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual ~FLACEncoder();
+
+	virtual const char *name() const OVERRIDE { return "flac_compress"; }
+
+	virtual void describe() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+
+	virtual bool handlesSeeking() const OVERRIDE { return true; }
+
+private:
+	FLAC__StreamEncoder *m_encoder;
+	FLAC__int32 *m_buffer;
+
+	FLACEncoder(Track *track, File *file, bool canSeek);
+
+	void convert16To32();
+	void convert24To32();
+
+	static FLAC__StreamEncoderSeekStatus seekCallback(const FLAC__StreamEncoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
+	{
+		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
+		off_t result = flac->seek(absoluteByteOffset);
+		if (result < 0)
+			return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+	}
+
+	static FLAC__StreamEncoderTellStatus tellCallback(const FLAC__StreamEncoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
+	{
+		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
+		off_t offset = flac->tell();
+		if (offset < 0)
+			return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+		*absoluteByteOffset = static_cast<FLAC__uint64>(offset);
+		return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+	}
+
+	static FLAC__StreamEncoderWriteStatus writeCallback(const FLAC__StreamEncoder *, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned currentFrame, void *clientData)
+	{
+		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
+		ssize_t result = flac->write(buffer, bytes);
+		if (result == static_cast<ssize_t>(bytes))
+			return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+	}
+};
+
+FLACEncoder::FLACEncoder(Track *track, File *file, bool canSeek) :
+	FileModule(Compress, track, file, canSeek),
+	m_encoder(NULL),
+	m_buffer(NULL)
+{
+	m_encoder = FLAC__stream_encoder_new();
+	if (!m_encoder)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not create encoder");
+		return;
+	}
+
+	if (!FLAC__stream_encoder_set_channels(m_encoder, m_track->f.channelCount))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not set channel count");
+		return;
+	}
+
+	if (!FLAC__stream_encoder_set_sample_rate(m_encoder, m_track->f.sampleRate))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not set sample rate");
+		return;
+	}
+
+	if (!FLAC__stream_encoder_set_bits_per_sample(m_encoder, m_track->f.sampleWidth))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not set sample width");
+		return;
+	}
+
+	if (FLAC__stream_encoder_init_stream(m_encoder,
+		writeCallback,
+		seekCallback,
+		tellCallback,
+		NULL,
+		this) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC encoder");
+		return;
+	}
+
+	m_buffer = new int32_t[FLAC__MAX_BLOCK_SIZE * m_track->f.channelCount];
+}
+
+FLACEncoder::~FLACEncoder()
+{
+	if (m_encoder)
+	{
+		FLAC__stream_encoder_delete(m_encoder);
+		m_encoder = NULL;
+	}
+
+	delete [] m_buffer;
+}
+
+FLACEncoder *FLACEncoder::create(Track *track, File *file, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return new FLACEncoder(track, file, canSeek);
+}
+
+void FLACEncoder::describe()
+{
+	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	m_outChunk->f.compressionType = AF_COMPRESSION_FLAC;
+}
+
+void FLACEncoder::runPush()
+{
+	if (m_track->f.sampleWidth == 16)
+		convert16To32();
+	else if (m_track->f.sampleWidth == 24)
+		convert24To32();
+
+	if (!FLAC__stream_encoder_process_interleaved(m_encoder, m_buffer,
+		m_inChunk->frameCount))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not encode data into FLAC stream");
+	}
+
+	m_track->nextfframe += m_inChunk->frameCount;
+	m_track->totalfframes = m_track->nextfframe;
+}
+
+void FLACEncoder::sync1()
+{
+}
+
+void FLACEncoder::sync2()
+{
+	if (!FLAC__stream_encoder_finish(m_encoder))
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "could not finish encoding");
+	}
+}
+
+void FLACEncoder::convert16To32()
+{
+	int channelCount = m_track->f.channelCount;
+	const int16_t *src = static_cast<const int16_t *>(m_inChunk->buffer);
+	for (unsigned i=0; i<m_inChunk->frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+			m_buffer[channelCount * i + c] = src[channelCount * i + c];
+}
+
+void FLACEncoder::convert24To32()
+{
+	int channelCount = m_track->f.channelCount;
+	const uint8_t *src = static_cast<const uint8_t *>(m_inChunk->buffer);
+	for (unsigned i=0; i<m_inChunk->frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+		{
+			int srcIndex = channelCount * i + c; 
+			int32_t t =
+#ifdef WORDS_BIGENDIAN
+				(src[3*srcIndex] << 24) |
+				(src[3*srcIndex+1] << 16) |
+				src[3*srcIndex+2] << 8;
+#else
+				(src[3*srcIndex+2] << 24) |
+				(src[3*srcIndex+1] << 16) |
+				src[3*srcIndex] << 8;
+#endif
+			m_buffer[channelCount * i + c] = t >> 8;
+		}
+}
+
+bool _af_flac_format_ok(AudioFormat *f)
+{
+	if (f->channelCount > static_cast<int>(FLAC__MAX_CHANNELS))
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"FLAC compression supports a maximum of 8 channels");
+		return false;
+	}
+
+	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP ||
+		(f->sampleWidth != 16 && f->sampleWidth != 24))
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"FLAC compression requires 16- or 24-bit signed integer format");
+		return false;
+	}
+
+	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"FLAC compression requires native byte order");
+		return false;
+	}
+
+	return true;
+}
+
+#else
+
+bool _af_flac_format_ok(AudioFormat *)
+{
+	return false;
+}
+
+#endif
+
+FileModule *_af_flac_init_compress(Track *track, File *file, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+#if ENABLE(FLAC)
+	return FLACEncoder::create(track, file, canSeek, headerless, chunkFrames);
+#else
+	return NULL;
+#endif
+}
+
+FileModule *_af_flac_init_decompress(Track *track, File *file, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+#if ENABLE(FLAC)
+	return FLACDecoder::create(track, file, canSeek, headerless, chunkFrames);
+#else
+	return NULL;
+#endif
+}
diff --git a/libaudiofile/modules/FLAC.h b/libaudiofile/modules/FLAC.h
new file mode 100644
index 0000000..0da9d03
--- /dev/null
+++ b/libaudiofile/modules/FLAC.h
@@ -0,0 +1,40 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef FLAC_h
+#define FLAC_h
+
+#include "afinternal.h"
+#include "audiofile.h"
+
+class FileModule;
+class File;
+struct AudioFormat;
+struct Track;
+
+bool _af_flac_format_ok (AudioFormat *f);
+
+FileModule *_af_flac_init_decompress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+FileModule *_af_flac_init_compress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+#endif
diff --git a/libaudiofile/modules/FileModule.cpp b/libaudiofile/modules/FileModule.cpp
new file mode 100644
index 0000000..239e4d2
--- /dev/null
+++ b/libaudiofile/modules/FileModule.cpp
@@ -0,0 +1,125 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "FileModule.h"
+
+#include "File.h"
+#include "Track.h"
+
+#include <errno.h>
+#include <string.h>
+
+FileModule::FileModule(Mode mode, Track *track, File *fh, bool canSeek) :
+	m_mode(mode),
+	m_track(track),
+	m_fh(fh),
+	m_canSeek(canSeek)
+{
+	track->fpos_next_frame = track->fpos_first_frame;
+	track->frames2ignore = 0;
+}
+
+ssize_t FileModule::read(void *data, size_t nbytes)
+{
+	ssize_t bytesRead = m_fh->read(data, nbytes);
+	if (bytesRead > 0)
+	{
+		m_track->fpos_next_frame += bytesRead;
+	}
+	return bytesRead;
+}
+
+ssize_t FileModule::write(const void *data, size_t nbytes)
+{
+	ssize_t bytesWritten = m_fh->write(data, nbytes);
+	if (bytesWritten > 0)
+	{
+		m_track->fpos_next_frame += bytesWritten;
+		m_track->data_size += bytesWritten;
+	}
+	return bytesWritten;
+}
+
+off_t FileModule::seek(off_t offset)
+{
+	return m_fh->seek(offset, File::SeekFromBeginning);
+}
+
+off_t FileModule::tell()
+{
+	return m_fh->tell();
+}
+
+off_t FileModule::length()
+{
+	return m_fh->length();
+}
+
+void FileModule::reportReadError(AFframecount framesRead,
+	AFframecount framesToRead)
+{
+	// Report error if we haven't already.
+	if (!m_track->filemodhappy)
+		return;
+
+	_af_error(AF_BAD_READ,
+		"file missing data -- read %jd frames, should be %jd",
+		static_cast<intmax_t>(m_track->nextfframe),
+		static_cast<intmax_t>(m_track->totalfframes));
+	m_track->filemodhappy = false;
+}
+
+void FileModule::reportWriteError(AFframecount framesWritten,
+	AFframecount framesToWrite)
+{
+	// Report error if we haven't already.
+	if (!m_track->filemodhappy)
+		return;
+
+	if (framesWritten < 0)
+	{
+		// Signal I/O error.
+		_af_error(AF_BAD_WRITE,
+			"unable to write data (%s) -- wrote %jd out of %jd frames",
+			strerror(errno),
+			static_cast<intmax_t>(m_track->nextfframe),
+			static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
+	}
+	else
+	{
+		// Signal disk full error.
+		_af_error(AF_BAD_WRITE,
+			"unable to write data (disk full) -- "
+			"wrote %jd out of %jd frames",
+			static_cast<intmax_t>(m_track->nextfframe + framesWritten),
+			static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
+	}
+
+	m_track->filemodhappy = false;
+}
+
+int FileModule::bufferSize() const
+{
+	if (mode() == Compress)
+		return outChunk()->frameCount * inChunk()->f.bytesPerFrame(true);
+	else
+		return inChunk()->frameCount * outChunk()->f.bytesPerFrame(true);
+}
diff --git a/libaudiofile/modules/FileModule.h b/libaudiofile/modules/FileModule.h
new file mode 100644
index 0000000..0b61cf3
--- /dev/null
+++ b/libaudiofile/modules/FileModule.h
@@ -0,0 +1,60 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef FILE_MODULE_H
+#define FILE_MODULE_H
+
+#include "Module.h"
+
+class FileModule : public Module
+{
+public:
+	virtual bool handlesSeeking() const { return false; }
+
+	virtual int bufferSize() const;
+
+protected:
+	enum Mode { Compress, Decompress };
+	FileModule(Mode, Track *, File *fh, bool canSeek);
+
+	Mode mode() const { return m_mode; }
+	bool canSeek() const { return m_canSeek; }
+
+	ssize_t read(void *data, size_t nbytes);
+	ssize_t write(const void *data, size_t nbytes);
+	off_t seek(off_t offset);
+	off_t tell();
+	off_t length();
+
+private:
+	Mode m_mode;
+
+protected:
+	Track *m_track;
+
+	void reportReadError(AFframecount framesRead, AFframecount framesRequested);
+	void reportWriteError(AFframecount framesWritten, AFframecount framesRequested);
+
+private:
+	File *m_fh;
+	bool m_canSeek;
+};
+
+#endif // FILE_MODULE_H
diff --git a/libaudiofile/modules/G711.cpp b/libaudiofile/modules/G711.cpp
new file mode 100644
index 0000000..cb93af9
--- /dev/null
+++ b/libaudiofile/modules/G711.cpp
@@ -0,0 +1,247 @@
+/*
+	Audio File Library
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "G711.h"
+
+#include <assert.h>
+
+#include "Compiler.h"
+#include "FileModule.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "units.h"
+#include "util.h"
+
+#include "../g711.h"
+
+static void ulaw2linear_buf (const uint8_t *ulaw, int16_t *linear, int nsamples)
+{
+	for (int i=0; i < nsamples; i++)
+		linear[i] = _af_ulaw2linear(ulaw[i]);
+}
+
+static void linear2ulaw_buf (const int16_t *linear, uint8_t *ulaw, int nsamples)
+{
+	for (int i=0; i < nsamples; i++)
+		ulaw[i] = _af_linear2ulaw(linear[i]);
+}
+
+static void alaw2linear_buf (const uint8_t *alaw, int16_t *linear, int nsamples)
+{
+	for (int i=0; i < nsamples; i++)
+		linear[i] = _af_alaw2linear(alaw[i]);
+}
+
+static void linear2alaw_buf (const int16_t *linear, uint8_t *alaw, int nsamples)
+{
+	for (int i=0; i < nsamples; i++)
+		alaw[i] = _af_linear2alaw(linear[i]);
+}
+
+bool _af_g711_format_ok (AudioFormat *f)
+{
+	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+		       "G.711 compression requires 16-bit signed integer format");
+		return false;
+	}
+
+	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"G.711 compression requires native byte order");
+		return false;
+	}
+
+	return true;
+}
+
+class G711 : public FileModule
+{
+public:
+	static G711 *createCompress(Track *trk, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkframes);
+	static G711 *createDecompress(Track *trk, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkframes);
+
+	virtual const char *name() const OVERRIDE
+	{
+		return mode() == Compress ? "g711compress" : "g711decompress";
+	}
+	virtual void describe() OVERRIDE;
+	virtual void runPull() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+
+private:
+	G711(Mode mode, Track *track, File *fh, bool canSeek);
+
+	AFfileoffset m_savedPositionNextFrame;
+	AFframecount m_savedNextFrame;
+};
+
+G711::G711(Mode mode, Track *track, File *fh, bool canSeek) :
+	FileModule(mode, track, fh, canSeek),
+	m_savedPositionNextFrame(-1),
+	m_savedNextFrame(-1)
+{
+	if (mode == Decompress)
+		track->f.compressionParams = AU_NULL_PVLIST;
+}
+
+G711 *G711::createCompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkframes)
+{
+	return new G711(Compress, track, fh, canSeek);
+}
+
+void G711::runPush()
+{
+	AFframecount framesToWrite = m_inChunk->frameCount;
+	AFframecount samplesToWrite = m_inChunk->frameCount * m_inChunk->f.channelCount;
+	int framesize = m_inChunk->f.channelCount;
+
+	assert(m_track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
+		m_track->f.compressionType == AF_COMPRESSION_G711_ALAW);
+
+	/* Compress frames into i->outc. */
+
+	if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+		linear2ulaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
+			static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);
+	else
+		linear2alaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
+			static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);
+
+	/* Write the compressed data. */
+
+	ssize_t bytesWritten = write(m_outChunk->buffer, framesize * framesToWrite);
+	AFframecount framesWritten = bytesWritten >= 0 ? bytesWritten / framesize : 0;
+
+	if (framesWritten != framesToWrite)
+		reportWriteError(framesWritten, framesToWrite);
+
+	m_track->nextfframe += framesWritten;
+	m_track->totalfframes = m_track->nextfframe;
+
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+}
+
+void G711::sync1()
+{
+	m_savedPositionNextFrame = m_track->fpos_next_frame;
+	m_savedNextFrame = m_track->nextfframe;
+}
+
+void G711::sync2()
+{
+	/* sanity check. */
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+
+	/* We can afford to do an lseek just in case because sync2 is rare. */
+	m_track->fpos_after_data = tell();
+
+	m_track->fpos_next_frame = m_savedPositionNextFrame;
+	m_track->nextfframe = m_savedNextFrame;
+}
+
+void G711::describe()
+{
+	if (mode() == Compress)
+	{
+		m_outChunk->f.compressionType = m_track->f.compressionType;
+	}
+	else
+	{
+		m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+		m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
+	}
+}
+
+G711 *G711::createDecompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkframes)
+{
+	return new G711(Decompress, track, fh, canSeek);
+}
+
+void G711::runPull()
+{
+	AFframecount framesToRead = m_outChunk->frameCount;
+	AFframecount samplesToRead = m_outChunk->frameCount * m_outChunk->f.channelCount;
+	int framesize = m_outChunk->f.channelCount;
+
+	/* Read the compressed frames. */
+
+	ssize_t bytesRead = read(m_inChunk->buffer, framesize * framesToRead);
+	AFframecount framesRead = bytesRead >= 0 ? bytesRead / framesize : 0;
+
+	/* Decompress into i->outc. */
+
+	if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+		ulaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
+			static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);
+	else
+		alaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
+			static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);
+
+	m_track->nextfframe += framesRead;
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+
+	/*
+		If we got EOF from read, then we return the actual amount read.
+
+		Complain only if there should have been more frames in the file.
+	*/
+
+	if (m_track->totalfframes != -1 && framesRead != framesToRead)
+		reportReadError(framesRead, framesToRead);
+
+	m_outChunk->frameCount = framesRead;
+}
+
+void G711::reset2()
+{
+	int framesize = m_inChunk->f.channelCount;
+
+	m_track->fpos_next_frame = m_track->fpos_first_frame +
+		framesize * m_track->nextfframe;
+
+	m_track->frames2ignore = 0;
+}
+
+FileModule *_AFg711initcompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return G711::createCompress(track, fh, canSeek, headerless, chunkFrames);
+}
+
+FileModule *_AFg711initdecompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return G711::createDecompress(track, fh, canSeek, headerless, chunkFrames);
+}
diff --git a/libaudiofile/modules/G711.h b/libaudiofile/modules/G711.h
new file mode 100644
index 0000000..e1ba3d5
--- /dev/null
+++ b/libaudiofile/modules/G711.h
@@ -0,0 +1,45 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	g711.h
+*/
+
+#ifndef MODULES_G711_H
+#define MODULES_G711_H
+
+#include "afinternal.h"
+#include "audiofile.h"
+
+class File;
+class FileModule;
+struct AudioFormat;
+struct Track;
+
+bool _af_g711_format_ok (AudioFormat *f);
+
+FileModule *_AFg711initcompress (Track *, File *, bool canSeek,
+	bool headerless, AFframecount *chunkframes);
+
+FileModule *_AFg711initdecompress (Track *, File *, bool canSeek,
+	bool headerless, AFframecount *chunkframes);
+
+#endif /* MODULES_G711_H */
diff --git a/libaudiofile/modules/IMA.cpp b/libaudiofile/modules/IMA.cpp
new file mode 100644
index 0000000..7476d44
--- /dev/null
+++ b/libaudiofile/modules/IMA.cpp
@@ -0,0 +1,418 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	This module implements IMA ADPCM compression.
+*/
+
+#include "config.h"
+#include "IMA.h"
+
+#include <assert.h>
+
+#include <audiofile.h>
+
+#include "BlockCodec.h"
+#include "Compiler.h"
+#include "File.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "util.h"
+#include "../pcm.h"
+
+struct adpcmState
+{
+	int previousValue;	// previous output value
+	int index;			// index into step table
+
+	adpcmState()
+	{
+		previousValue = 0;
+		index = 0;
+	}
+};
+
+class IMA : public BlockCodec
+{
+public:
+	static IMA *createDecompress(Track *track, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+	static IMA *createCompress(Track *track, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual ~IMA();
+
+	virtual const char *name() const OVERRIDE
+	{
+		return mode() == Compress ?
+			"ima_adpcm_compress" : "ima_adpcm_decompress";
+	}
+	virtual void describe() OVERRIDE;
+
+private:
+	int m_imaType;
+	adpcmState *m_adpcmState;
+
+	IMA(Mode, Track *, File *fh, bool canSeek);
+
+	int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE;
+	int decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded);
+	int decodeBlockQT(const uint8_t *encoded, int16_t *decoded);
+
+	int encodeBlock(const int16_t *input, uint8_t *output) OVERRIDE;
+	int encodeBlockWAVE(const int16_t *input, uint8_t *output);
+	int encodeBlockQT(const int16_t *input, uint8_t *output);
+};
+
+IMA::IMA(Mode mode, Track *track, File *fh, bool canSeek) :
+	BlockCodec(mode, track, fh, canSeek),
+	m_imaType(0)
+{
+	AUpvlist pv = (AUpvlist) track->f.compressionParams;
+
+	m_framesPerPacket = track->f.framesPerPacket;
+	m_bytesPerPacket = track->f.bytesPerPacket;
+
+	long l;
+	if (_af_pv_getlong(pv, _AF_IMA_ADPCM_TYPE, &l))
+		m_imaType = l;
+
+	m_adpcmState = new adpcmState[track->f.channelCount];
+}
+
+IMA::~IMA()
+{
+	delete [] m_adpcmState;
+}
+
+int IMA::decodeBlock(const uint8_t *encoded, int16_t *decoded)
+{
+	if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE)
+		return decodeBlockWAVE(encoded, decoded);
+	else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT)
+		return decodeBlockQT(encoded, decoded);
+	return 0;
+}
+
+static const int8_t indexTable[16] =
+{
+	-1, -1, -1, -1, 2, 4, 6, 8,
+	-1, -1, -1, -1, 2, 4, 6, 8,
+};
+
+static const int16_t stepTable[89] =
+{
+	7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+	19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+	50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+	130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+	337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+	876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+	2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+	5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+	15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+static inline int clamp(int x, int low, int high)
+{
+	if (x < low) return low;
+	if (x > high) return high;
+	return x;
+}
+
+static inline int16_t decodeSample(adpcmState &state, uint8_t code)
+{
+	int step = stepTable[state.index];
+
+	int diff = step >> 3;
+	if (code & 4) diff += step;
+	if (code & 2) diff += step>>1;
+	if (code & 1) diff += step>>2;
+
+	int predictor = state.previousValue;
+	if (code & 8)
+		predictor -= diff;
+	else
+		predictor += diff;
+
+	state.previousValue = clamp(predictor, MIN_INT16, MAX_INT16);
+	state.index = clamp(state.index + indexTable[code], 0, 88);
+	return state.previousValue;
+}
+
+int IMA::decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded)
+{
+	int channelCount = m_track->f.channelCount;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		m_adpcmState[c].previousValue = (encoded[1]<<8) | encoded[0];
+		if (encoded[1] & 0x80)
+			m_adpcmState[c].previousValue -= 0x10000;
+
+		m_adpcmState[c].index = encoded[2];
+
+		*decoded++ = m_adpcmState[c].previousValue;
+
+		encoded += 4;
+	}
+
+	for (int n=0; n<m_framesPerPacket - 1; n += 8)
+	{
+		for (int c=0; c<channelCount; c++)
+		{
+			int16_t *output = decoded + c;
+			for (int s=0; s<4; s++)
+			{
+				*output = decodeSample(m_adpcmState[c], *encoded & 0xf);
+				output += channelCount;
+				*output = decodeSample(m_adpcmState[c], *encoded >> 4);
+				output += channelCount;
+				encoded++;
+			}
+		}
+
+		decoded += channelCount * 8;
+	}
+
+	return m_framesPerPacket * channelCount * sizeof (int16_t);
+}
+
+
+int IMA::decodeBlockQT(const uint8_t *encoded, int16_t *decoded)
+{
+	int channelCount = m_track->f.channelCount;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		adpcmState state;
+		int predictor = (encoded[0] << 8) | (encoded[1] & 0x80);
+		if (predictor & 0x8000)
+			predictor -= 0x10000;
+
+		state.previousValue = clamp(predictor, MIN_INT16, MAX_INT16);
+		state.index = encoded[1] & 0x7f;
+		encoded += 2;
+
+		for (int n=0; n<m_framesPerPacket; n+=2)
+		{
+			uint8_t e = *encoded;
+			decoded[n*channelCount + c] = decodeSample(state, e & 0xf);
+			decoded[(n+1)*channelCount + c] = decodeSample(state, e >> 4);
+			encoded++;
+		}
+	}
+
+	return m_framesPerPacket * channelCount * sizeof (int16_t);
+}
+
+int IMA::encodeBlock(const int16_t *input, uint8_t *output)
+{
+	if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE)
+		return encodeBlockWAVE(input, output);
+	else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT)
+		return encodeBlockQT(input, output);
+	return 0;
+}
+
+static inline uint8_t encodeSample(adpcmState &state, int16_t sample)
+{
+	int step = stepTable[state.index];
+	int diff = sample - state.previousValue;
+	int vpdiff = step >> 3;
+	uint8_t code = 0;
+	if (diff < 0)
+	{
+		code = 8;
+		diff = -diff;
+	}
+	if (diff >= step)
+	{
+		code |= 4;
+		diff -= step;
+		vpdiff += step;
+	}
+	step >>= 1;
+	if (diff >= step)
+	{
+		code |= 2;
+		diff -= step;
+		vpdiff += step;
+	}
+	step >>= 1;
+	if (diff >= step)
+	{
+		code |= 1;
+		vpdiff += step;
+	}
+
+	if (code & 8)
+		vpdiff = -vpdiff;
+	state.previousValue = clamp(state.previousValue + vpdiff,
+		MIN_INT16, MAX_INT16);
+
+	state.index = clamp(state.index + indexTable[code], 0, 88);
+	return code & 0xf;
+}
+
+int IMA::encodeBlockWAVE(const int16_t *input, uint8_t *output)
+{
+	int channelCount = m_track->f.channelCount;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		output[0] = m_adpcmState[c].previousValue & 0xff;
+		output[1] = m_adpcmState[c].previousValue >> 8;
+		output[2] = m_adpcmState[c].index;
+		output[3] = 0;
+
+		output += 4;
+	}
+
+	for (int n=0; n<m_framesPerPacket - 1; n += 8)
+	{
+		for (int c=0; c<channelCount; c++)
+		{
+			const int16_t *currentInput = input + c;
+			for (int s=0; s<4; s++)
+			{
+				uint8_t encodedValue = encodeSample(m_adpcmState[c], *currentInput);
+				currentInput += channelCount;
+				encodedValue |= encodeSample(m_adpcmState[c], *currentInput) << 4;
+				currentInput += channelCount;
+				*output++ = encodedValue;
+			}
+		}
+
+		input += channelCount * 8;
+	}
+
+	return m_bytesPerPacket;
+}
+
+int IMA::encodeBlockQT(const int16_t *input, uint8_t *output)
+{
+	int channelCount = m_track->f.channelCount;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		adpcmState state = m_adpcmState[c];
+
+		state.previousValue &= ~0x7f;
+
+		output[0] = (state.previousValue >> 8) & 0xff;
+		output[1] = (state.previousValue & 0x80) | (state.index & 0x7f);
+		output += 2;
+
+		for (int n=0; n<m_framesPerPacket; n+=2)
+		{
+			uint8_t encoded = encodeSample(state, input[n*channelCount + c]);
+			encoded |= encodeSample(state, input[(n+1)*channelCount + c]) << 4;
+			*output++ = encoded;
+		}
+
+		m_adpcmState[c] = state;
+	}
+
+	return m_bytesPerPacket;
+}
+
+bool _af_ima_adpcm_format_ok (AudioFormat *f)
+{
+	if (f->channelCount != 1 && f->channelCount != 2)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"IMA ADPCM compression requires 1 or 2 channels");
+		return false;
+	}
+
+	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"IMA ADPCM compression requires 16-bit signed integer format");
+		return false;
+	}
+
+	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"IMA ADPCM compression requires native byte order");
+		return false;
+	}
+
+	return true;
+}
+
+void IMA::describe()
+{
+	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
+	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
+}
+
+IMA *IMA::createDecompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	IMA *ima = new IMA(Decompress, track, fh, canSeek);
+
+	if (!ima->m_imaType)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "IMA type not set");
+		delete ima;
+		return NULL;
+	}
+
+	*chunkFrames = ima->m_framesPerPacket;
+	return ima;
+}
+
+IMA *IMA::createCompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	IMA *ima = new IMA(Compress, track, fh, canSeek);
+
+	if (!ima->m_imaType)
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "IMA type not set");
+		delete ima;
+		return NULL;
+	}
+
+	*chunkFrames = ima->m_framesPerPacket;
+	return ima;
+}
+
+FileModule *_af_ima_adpcm_init_decompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return IMA::createDecompress(track, fh, canSeek, headerless, chunkFrames);
+}
+
+FileModule *_af_ima_adpcm_init_compress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return IMA::createCompress(track, fh, canSeek, headerless, chunkFrames);
+}
diff --git a/libaudiofile/modules/IMA.h b/libaudiofile/modules/IMA.h
new file mode 100644
index 0000000..e14467b
--- /dev/null
+++ b/libaudiofile/modules/IMA.h
@@ -0,0 +1,47 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	IMA.h
+
+	This module declares the interface for the IMA ADPCM
+	compression module.
+*/
+
+#ifndef IMA_H
+#define IMA_H
+
+#include "afinternal.h"
+#include "audiofile.h"
+
+class File;
+class FileModule;
+struct AudioFormat;
+struct Track;
+
+bool _af_ima_adpcm_format_ok(AudioFormat *);
+
+FileModule *_af_ima_adpcm_init_compress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+FileModule *_af_ima_adpcm_init_decompress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+#endif
diff --git a/libaudiofile/modules/MSADPCM.cpp b/libaudiofile/modules/MSADPCM.cpp
new file mode 100644
index 0000000..ef9c38c
--- /dev/null
+++ b/libaudiofile/modules/MSADPCM.cpp
@@ -0,0 +1,491 @@
+/*
+	Audio File Library
+	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	This module implements Microsoft ADPCM compression.
+*/
+
+#include "config.h"
+#include "MSADPCM.h"
+
+#include <assert.h>
+#include <cstdlib>
+#include <limits>
+#include <string.h>
+
+#include "BlockCodec.h"
+#include "Compiler.h"
+#include "File.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+#include "../pcm.h"
+
+struct ms_adpcm_state
+{
+	uint8_t predictorIndex;
+	int delta;
+	int16_t sample1, sample2;
+
+	ms_adpcm_state()
+	{
+		predictorIndex = 0;
+		delta = 16;
+		sample1 = 0;
+		sample2 = 0;
+	}
+};
+
+class MSADPCM : public BlockCodec
+{
+public:
+	static MSADPCM *createDecompress(Track *, File *, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+	static MSADPCM *createCompress(Track *, File *, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual ~MSADPCM();
+
+	bool initializeCoefficients();
+
+	virtual const char *name() const OVERRIDE
+	{
+		return mode() == Compress ? "ms_adpcm_compress" : "ms_adpcm_decompress";
+	}
+	virtual void describe() OVERRIDE;
+
+private:
+	// m_coefficients is an array of m_numCoefficients ADPCM coefficient pairs.
+	int m_numCoefficients;
+	int16_t m_coefficients[256][2];
+
+	ms_adpcm_state *m_state;
+
+	MSADPCM(Mode mode, Track *track, File *fh, bool canSeek);
+
+	int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE;
+	int encodeBlock(const int16_t *decoded, uint8_t *encoded) OVERRIDE;
+	void choosePredictorForBlock(const int16_t *decoded);
+};
+
+static inline int clamp(int x, int low, int high)
+{
+	if (x < low) return low;
+	if (x > high) return high;
+	return x;
+}
+
+static const int16_t adaptationTable[] =
+{
+	230, 230, 230, 230, 307, 409, 512, 614,
+	768, 614, 512, 409, 307, 230, 230, 230
+};
+
+int firstBitSet(int x)
+{
+        int position=0;
+        while (x!=0)
+        {
+                x>>=1;
+                ++position;
+        }
+        return position;
+}
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+int multiplyCheckOverflow(int a, int b, int *result)
+{
+#if (defined __GNUC__ && __GNUC__ >= 5) || ( __clang__ && __has_builtin(__builtin_mul_overflow))
+	return __builtin_mul_overflow(a, b, result);
+#else
+	if (firstBitSet(a)+firstBitSet(b)>31) // int is signed, so we can't use 32 bits
+		return true;
+	*result = a * b;
+	return false;
+#endif
+}
+
+
+// Compute a linear PCM value from the given differential coded value.
+static int16_t decodeSample(ms_adpcm_state &state,
+	uint8_t code, const int16_t *coefficient, bool *ok=NULL)
+{
+	int linearSample = (state.sample1 * coefficient[0] +
+		state.sample2 * coefficient[1]) >> 8;
+	int delta;
+
+	linearSample += ((code & 0x08) ? (code - 0x10) : code) * state.delta;
+
+	linearSample = clamp(linearSample, MIN_INT16, MAX_INT16);
+
+	if (multiplyCheckOverflow(state.delta, adaptationTable[code], &delta))
+	{
+                if (ok) *ok=false;
+		_af_error(AF_BAD_COMPRESSION, "Error decoding sample");
+		return 0;
+	}
+	delta >>= 8;
+	if (delta < 16)
+		delta = 16;
+
+	state.delta = delta;
+	state.sample2 = state.sample1;
+	state.sample1 = linearSample;
+	if (ok) *ok=true;
+
+	return static_cast<int16_t>(linearSample);
+}
+
+// Compute a differential coded value from the given linear PCM sample.
+static uint8_t encodeSample(ms_adpcm_state &state, int16_t sample,
+	const int16_t *coefficient)
+{
+	int predictor = (state.sample1 * coefficient[0] +
+		state.sample2 * coefficient[1]) >> 8;
+	int code = sample - predictor;
+	int bias = state.delta / 2;
+	if (code < 0)
+		bias = -bias;
+	code = (code + bias) / state.delta;
+	code = clamp(code, -8, 7) & 0xf;
+
+	predictor += ((code & 0x8) ? (code - 0x10) : code) * state.delta;
+
+	state.sample2 = state.sample1;
+	state.sample1 = clamp(predictor, MIN_INT16, MAX_INT16);
+	state.delta = (adaptationTable[code] * state.delta) >> 8;
+	if (state.delta < 16)
+		state.delta = 16;
+	return code;
+}
+
+// Decode one block of MS ADPCM data.
+int MSADPCM::decodeBlock(const uint8_t *encoded, int16_t *decoded)
+{
+	ms_adpcm_state decoderState[2];
+	ms_adpcm_state *state[2];
+
+	int channelCount = m_track->f.channelCount;
+
+	// Calculate the number of bytes needed for decoded data.
+	int outputLength = m_framesPerPacket * sizeof (int16_t) * channelCount;
+
+	state[0] = &decoderState[0];
+	if (channelCount == 2)
+		state[1] = &decoderState[1];
+	else
+		state[1] = &decoderState[0];
+
+	// Initialize block predictor.
+	for (int i=0; i<channelCount; i++)
+	{
+		state[i]->predictorIndex = *encoded++;
+		assert(state[i]->predictorIndex < m_numCoefficients);
+	}
+
+	// Initialize delta.
+	for (int i=0; i<channelCount; i++)
+	{
+		state[i]->delta = (encoded[1]<<8) | encoded[0];
+		encoded += sizeof (uint16_t);
+	}
+
+	// Initialize first two samples.
+	for (int i=0; i<channelCount; i++)
+	{
+		state[i]->sample1 = (encoded[1]<<8) | encoded[0];
+		encoded += sizeof (uint16_t);
+	}
+
+	for (int i=0; i<channelCount; i++)
+	{
+		state[i]->sample2 = (encoded[1]<<8) | encoded[0];
+		encoded += sizeof (uint16_t);
+	}
+
+	const int16_t *coefficient[2] =
+	{
+		m_coefficients[state[0]->predictorIndex],
+		m_coefficients[state[1]->predictorIndex]
+	};
+
+	for (int i=0; i<channelCount; i++)
+		*decoded++ = state[i]->sample2;
+
+	for (int i=0; i<channelCount; i++)
+		*decoded++ = state[i]->sample1;
+
+	/*
+		The first two samples have already been 'decoded' in
+		the block header.
+	*/
+	int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;
+
+	while (samplesRemaining > 0)
+	{
+		uint8_t code;
+		int16_t newSample;
+		bool ok;
+
+		code = *encoded >> 4;
+		newSample = decodeSample(*state[0], code, coefficient[0], &ok);
+		if (!ok) return 0;
+		*decoded++ = newSample;
+
+		code = *encoded & 0x0f;
+		newSample = decodeSample(*state[1], code, coefficient[1], &ok);
+		if (!ok) return 0;
+		*decoded++ = newSample;
+
+		encoded++;
+		samplesRemaining -= 2;
+	}
+
+	return outputLength;
+}
+
+int MSADPCM::encodeBlock(const int16_t *decoded, uint8_t *encoded)
+{
+	choosePredictorForBlock(decoded);
+
+	int channelCount = m_track->f.channelCount;
+
+	// Encode predictor.
+	for (int c=0; c<channelCount; c++)
+		*encoded++ = m_state[c].predictorIndex;
+
+	// Encode delta.
+	for (int c=0; c<channelCount; c++)
+	{
+		*encoded++ = m_state[c].delta & 0xff;
+		*encoded++ = m_state[c].delta >> 8;
+	}
+
+	// Enccode first two samples.
+	for (int c=0; c<channelCount; c++)
+		m_state[c].sample2 = *decoded++;
+
+	for (int c=0; c<channelCount; c++)
+		m_state[c].sample1 = *decoded++;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		*encoded++ = m_state[c].sample1 & 0xff;
+		*encoded++ = m_state[c].sample1 >> 8;
+	}
+
+	for (int c=0; c<channelCount; c++)
+	{
+		*encoded++ = m_state[c].sample2 & 0xff;
+		*encoded++ = m_state[c].sample2 >> 8;
+	}
+
+	ms_adpcm_state *state[2] = { &m_state[0], &m_state[channelCount - 1] };
+	const int16_t *coefficient[2] =
+	{
+		m_coefficients[state[0]->predictorIndex],
+		m_coefficients[state[1]->predictorIndex]
+	};
+
+	int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;
+	while (samplesRemaining > 0)
+	{
+		uint8_t code1 = encodeSample(*state[0], *decoded++, coefficient[0]);
+		uint8_t code2 = encodeSample(*state[1], *decoded++, coefficient[1]);
+
+		*encoded++ = (code1 << 4) | code2;
+		samplesRemaining -= 2;
+	}
+
+	return m_bytesPerPacket;
+}
+
+void MSADPCM::choosePredictorForBlock(const int16_t *decoded)
+{
+	const int kPredictorSampleLength = 3;
+
+	int channelCount = m_track->f.channelCount;
+
+	for (int c=0; c<channelCount; c++)
+	{
+		int bestPredictorIndex = 0;
+		int bestPredictorError = std::numeric_limits<int>::max();
+		for (int k=0; k<m_numCoefficients; k++)
+		{
+			int a0 = m_coefficients[k][0];
+			int a1 = m_coefficients[k][1];
+
+			int currentPredictorError = 0;
+			for (int i=2; i<2+kPredictorSampleLength; i++)
+			{
+				int error = std::abs(decoded[i*channelCount + c] -
+					((a0 * decoded[(i-1)*channelCount + c] +
+					a1 * decoded[(i-2)*channelCount + c]) >> 8));
+				currentPredictorError += error;
+			}
+
+			currentPredictorError /= 4 * kPredictorSampleLength;
+
+			if (currentPredictorError < bestPredictorError)
+			{
+				bestPredictorError = currentPredictorError;
+				bestPredictorIndex = k;
+			}
+
+			if (!currentPredictorError)
+				break;
+		}
+
+		if (bestPredictorError < 16)
+			bestPredictorError = 16;
+
+		m_state[c].predictorIndex = bestPredictorIndex;
+		m_state[c].delta = bestPredictorError;
+	}
+}
+
+void MSADPCM::describe()
+{
+	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
+	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
+	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
+}
+
+MSADPCM::MSADPCM(Mode mode, Track *track, File *fh, bool canSeek) :
+	BlockCodec(mode, track, fh, canSeek),
+	m_numCoefficients(0),
+	m_state(NULL)
+{
+	m_state = new ms_adpcm_state[m_track->f.channelCount];
+}
+
+MSADPCM::~MSADPCM()
+{
+	delete [] m_state;
+}
+
+bool MSADPCM::initializeCoefficients()
+{
+	AUpvlist pv = m_track->f.compressionParams;
+
+	long l;
+	if (_af_pv_getlong(pv, _AF_MS_ADPCM_NUM_COEFFICIENTS, &l))
+	{
+		m_numCoefficients = l;
+	}
+	else
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "number of coefficients not set");
+		return false;
+	}
+
+	void *v;
+	if (_af_pv_getptr(pv, _AF_MS_ADPCM_COEFFICIENTS, &v))
+	{
+		memcpy(m_coefficients, v, m_numCoefficients * 2 * sizeof (int16_t));
+	}
+	else
+	{
+		_af_error(AF_BAD_CODEC_CONFIG, "coefficient array not set");
+		return false;
+	}
+
+	return true;
+}
+
+MSADPCM *MSADPCM::createDecompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	MSADPCM *msadpcm = new MSADPCM(Decompress, track, fh, canSeek);
+
+	if (!msadpcm->initializeCoefficients())
+	{
+		delete msadpcm;
+		return NULL;
+	}
+
+	*chunkFrames = msadpcm->m_framesPerPacket;
+
+	return msadpcm;
+}
+
+MSADPCM *MSADPCM::createCompress(Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	assert(fh->tell() == track->fpos_first_frame);
+
+	MSADPCM *msadpcm = new MSADPCM(Compress, track, fh, canSeek);
+
+	if (!msadpcm->initializeCoefficients())
+	{
+		delete msadpcm;
+		return NULL;
+	}
+
+	*chunkFrames = msadpcm->m_framesPerPacket;
+
+	return msadpcm;
+}
+
+bool _af_ms_adpcm_format_ok (AudioFormat *f)
+{
+	if (f->channelCount != 1 && f->channelCount != 2)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"MS ADPCM compression requires 1 or 2 channels");
+		return false;
+	}
+
+	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"MS ADPCM compression requires 16-bit signed integer format");
+		return false;
+	}
+
+	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		_af_error(AF_BAD_COMPRESSION,
+			"MS ADPCM compression requires native byte order");
+		return false;
+	}
+
+	return true;
+}
+
+FileModule *_af_ms_adpcm_init_decompress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return MSADPCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
+}
+
+FileModule *_af_ms_adpcm_init_compress (Track *track, File *fh,
+	bool canSeek, bool headerless, AFframecount *chunkFrames)
+{
+	return MSADPCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
+}
diff --git a/libaudiofile/modules/MSADPCM.h b/libaudiofile/modules/MSADPCM.h
new file mode 100644
index 0000000..e23bb71
--- /dev/null
+++ b/libaudiofile/modules/MSADPCM.h
@@ -0,0 +1,48 @@
+/*
+	Audio File Library
+	Copyright (C) 2001, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	msadpcm.h
+
+	This module declares the interface for the Microsoft ADPCM
+	compression module.
+*/
+
+#ifndef MSADPCM_H
+#define MSADPCM_H
+
+#include "afinternal.h"
+#include "audiofile.h"
+
+class File;
+class FileModule;
+struct AudioFormat;
+struct Track;
+
+bool _af_ms_adpcm_format_ok (AudioFormat *f);
+
+FileModule *_af_ms_adpcm_init_decompress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+FileModule *_af_ms_adpcm_init_compress(Track *, File *,
+	bool canSeek, bool headerless, AFframecount *chunkframes);
+
+#endif
diff --git a/libaudiofile/modules/Makefile.am b/libaudiofile/modules/Makefile.am
new file mode 100644
index 0000000..168bbc3
--- /dev/null
+++ b/libaudiofile/modules/Makefile.am
@@ -0,0 +1,46 @@
+noinst_LTLIBRARIES = libmodules.la
+
+AM_CPPFLAGS = -I$(srcdir)/..
+
+libmodules_la_SOURCES = \
+	ALAC.cpp \
+	ALAC.h \
+	BlockCodec.cpp \
+	BlockCodec.h \
+	FLAC.cpp \
+	FLAC.h \
+	FileModule.cpp \
+	FileModule.h \
+	G711.cpp \
+	G711.h \
+	IMA.cpp \
+	IMA.h \
+	Module.cpp \
+	Module.h \
+	ModuleState.cpp \
+	ModuleState.h \
+	MSADPCM.cpp \
+	MSADPCM.h \
+	PCM.cpp \
+	PCM.h \
+	RebufferModule.cpp \
+	RebufferModule.h \
+	SimpleModule.cpp \
+	SimpleModule.h
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = \
+	-DNDEBUG \
+	-Wall \
+	-Wno-multichar \
+	$(WERROR_CFLAGS) \
+	$(COVERAGE_CFLAGS) \
+	$(FLAC_CFLAGS) \
+	-fvisibility=hidden
+AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden
+
+CLEANFILES = *.gcda *.gcno
diff --git a/libaudiofile/modules/Module.cpp b/libaudiofile/modules/Module.cpp
new file mode 100644
index 0000000..165f093
--- /dev/null
+++ b/libaudiofile/modules/Module.cpp
@@ -0,0 +1,78 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "Module.h"
+
+#include "File.h"
+#include "SimpleModule.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "units.h"
+#include "../pcm.h"
+
+Module::Module() :
+	m_sink(NULL)
+{
+}
+
+Module::~Module()
+{
+}
+
+void Module::setSink(Module *module) { m_sink = module; }
+void Module::setSource(Module *module) { m_source = module; }
+
+const char *Module::name() const { return ""; }
+
+void Module::describe()
+{
+}
+
+void Module::maxPull()
+{
+	m_inChunk->frameCount = m_outChunk->frameCount;
+}
+
+void Module::maxPush()
+{
+	m_outChunk->frameCount = m_inChunk->frameCount;
+}
+
+void Module::runPull()
+{
+}
+
+void Module::runPush()
+{
+}
+
+void Module::pull(size_t frames)
+{
+	m_inChunk->frameCount = frames;
+	m_source->runPull();
+}
+
+void Module::push(size_t frames)
+{
+	m_outChunk->frameCount = frames;
+	m_sink->runPush();
+}
diff --git a/libaudiofile/modules/Module.h b/libaudiofile/modules/Module.h
new file mode 100644
index 0000000..c906fc5
--- /dev/null
+++ b/libaudiofile/modules/Module.h
@@ -0,0 +1,130 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#include "AudioFormat.h"
+#include "Shared.h"
+#include "afinternal.h"
+
+#include <vector>
+
+enum FormatCode
+{
+	kUndefined = -1,
+	kInt8,
+	kInt16,
+	kInt24,
+	kInt32,
+	kFloat,
+	kDouble,
+};
+
+class Chunk : public Shared<Chunk>
+{
+public:
+	void *buffer;
+	size_t frameCount;
+	AudioFormat f;
+	bool ownsMemory;
+
+	Chunk() : buffer(NULL), frameCount(0), ownsMemory(false) { }
+	~Chunk()
+	{
+		deallocate();
+	}
+	void allocate(size_t capacity)
+	{
+		deallocate();
+		ownsMemory = true;
+		buffer = ::operator new(capacity);
+	}
+	void deallocate()
+	{
+		if (ownsMemory)
+			::operator delete(buffer);
+		ownsMemory = false;
+		buffer = NULL;
+	}
+};
+
+class Module : public Shared<Module>
+{
+public:
+	Module();
+	virtual ~Module();
+
+	void setSink(Module *);
+	void setSource(Module *);
+	Chunk *inChunk() const { return m_inChunk.get(); }
+	void setInChunk(Chunk *chunk) { m_inChunk = chunk; }
+	Chunk *outChunk() const { return m_outChunk.get(); }
+	void setOutChunk(Chunk *chunk) { m_outChunk = chunk; }
+
+	virtual const char *name() const;
+	/*
+		Set format of m_outChunk based on how this module transforms m_inChunk.
+	*/
+	virtual void describe();
+	/*
+		Set frame count of m_inChunk to the maximum number of frames needed to
+		produce frame count of m_outChunk.
+	*/
+	virtual void maxPull();
+	/*
+		Set frame count of m_outChunk to the maximum number of frames needed to
+		produce frame count of m_inChunk.
+	*/
+	virtual void maxPush();
+	virtual void runPull();
+	virtual void reset1() { }
+	virtual void reset2() { }
+	virtual void runPush();
+	virtual void sync1() { }
+	virtual void sync2() { }
+
+protected:
+	SharedPtr<Chunk> m_inChunk, m_outChunk;
+	union
+	{
+		Module *m_sink;
+		Module *m_source;
+	};
+
+	void pull(size_t frames);
+	void push(size_t frames);
+};
+
+/*
+	_AF_ATOMIC_NVFRAMES is NOT the maximum number of frames a module
+	can be requested to produce.
+
+	This IS the maximum number of virtual (user) frames that will
+	be produced or processed per run of the modules.
+
+	Modules can be requested more frames than this because of rate
+	conversion and rebuffering.
+*/
+
+#define _AF_ATOMIC_NVFRAMES 1024
+
+#endif // MODULE_H
diff --git a/libaudiofile/modules/ModuleState.cpp b/libaudiofile/modules/ModuleState.cpp
new file mode 100644
index 0000000..0c29d7a
--- /dev/null
+++ b/libaudiofile/modules/ModuleState.cpp
@@ -0,0 +1,504 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "ModuleState.h"
+
+#include "File.h"
+#include "FileHandle.h"
+#include "FileModule.h"
+#include "RebufferModule.h"
+#include "SimpleModule.h"
+#include "Track.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "units.h"
+#include "util.h"
+#include "../pcm.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <stdio.h>
+
+ModuleState::ModuleState() :
+	m_isDirty(true)
+{
+}
+
+ModuleState::~ModuleState()
+{
+}
+
+status ModuleState::initFileModule(AFfilehandle file, Track *track)
+{
+	const CompressionUnit *unit = _af_compression_unit_from_id(track->f.compressionType);
+	if (!unit)
+		return AF_FAIL;
+
+	// Validate compression format and parameters.
+	if (!unit->fmtok(&track->f))
+		return AF_FAIL;
+
+	if (file->m_seekok &&
+		file->m_fh->seek(track->fpos_first_frame, File::SeekFromBeginning) !=
+			track->fpos_first_frame)
+	{
+		_af_error(AF_BAD_LSEEK, "unable to position file handle at beginning of sound data");
+		return AF_FAIL;
+	}
+
+	AFframecount chunkFrames;
+	if (file->m_access == _AF_READ_ACCESS)
+		m_fileModule = unit->initdecompress(track, file->m_fh, file->m_seekok,
+			file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);
+	else
+		m_fileModule = unit->initcompress(track, file->m_fh, file->m_seekok,
+			file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);
+
+	if (unit->needsRebuffer)
+	{
+		assert(unit->nativeSampleFormat == AF_SAMPFMT_TWOSCOMP);
+
+		RebufferModule::Direction direction =
+			file->m_access == _AF_WRITE_ACCESS ?
+				RebufferModule::VariableToFixed : RebufferModule::FixedToVariable;
+
+		m_fileRebufferModule = new RebufferModule(direction,
+			track->f.bytesPerFrame(false), chunkFrames,
+			unit->multiple_of);
+	}
+
+	track->filemodhappy = true;
+
+	return AF_SUCCEED;
+}
+
+status ModuleState::init(AFfilehandle file, Track *track)
+{
+	if (initFileModule(file, track) == AF_FAIL)
+		return AF_FAIL;
+
+	return AF_SUCCEED;
+}
+
+bool ModuleState::fileModuleHandlesSeeking() const
+{
+	return m_fileModule->handlesSeeking();
+}
+
+status ModuleState::setup(AFfilehandle file, Track *track)
+{
+	AFframecount fframepos = llrint(track->nextvframe * track->f.sampleRate / track->v.sampleRate);
+	bool isReading = file->m_access == _AF_READ_ACCESS;
+
+	if (!track->v.isUncompressed())
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED,
+			"library does not support compression in virtual format yet");
+		return AF_FAIL;
+	}
+
+	if (arrange(file, track) == AF_FAIL)
+		return AF_FAIL;
+
+	track->filemodhappy = true;
+	int maxbufsize = 0;
+	if (isReading)
+	{
+		m_chunks.back()->frameCount = _AF_ATOMIC_NVFRAMES;
+		for (int i=m_modules.size() - 1; i >= 0; i--)
+		{
+			SharedPtr<Chunk> inChunk = m_chunks[i];
+			SharedPtr<Chunk> outChunk = m_chunks[i+1];
+			int bufsize = outChunk->frameCount * outChunk->f.bytesPerFrame(true);
+			if (bufsize > maxbufsize)
+				maxbufsize = bufsize;
+			if (i != 0)
+				m_modules[i]->setSource(m_modules[i-1].get());
+			m_modules[i]->maxPull();
+		}
+
+		if (!track->filemodhappy)
+			return AF_FAIL;
+		int bufsize = m_fileModule->bufferSize();
+		if (bufsize > maxbufsize)
+			maxbufsize = bufsize;
+	}
+	else
+	{
+		m_chunks.front()->frameCount = _AF_ATOMIC_NVFRAMES;
+		for (size_t i=0; i<m_modules.size(); i++)
+		{
+			SharedPtr<Chunk> inChunk = m_chunks[i];
+			SharedPtr<Chunk> outChunk = m_chunks[i+1];
+			int bufsize = inChunk->frameCount * inChunk->f.bytesPerFrame(true);
+			if (bufsize > maxbufsize)
+				maxbufsize = bufsize;
+			if (i != m_modules.size() - 1)
+				m_modules[i]->setSink(m_modules[i+1].get());
+			m_modules[i]->maxPush();
+		}
+
+		if (!track->filemodhappy)
+			return AF_FAIL;
+
+		int bufsize = m_fileModule->bufferSize();
+		if (bufsize > maxbufsize)
+			maxbufsize = bufsize;
+	}
+
+	for (size_t i=0; i<m_chunks.size(); i++)
+	{
+		if ((isReading && i==m_chunks.size() - 1) || (!isReading && i==0))
+			continue;
+		m_chunks[i]->allocate(maxbufsize);
+	}
+
+	if (isReading)
+	{
+		if (track->totalfframes == -1)
+			track->totalvframes = -1;
+		else
+			track->totalvframes = llrint(track->totalfframes *
+				(track->v.sampleRate / track->f.sampleRate));
+
+		track->nextfframe = fframepos;
+		track->nextvframe = llrint(fframepos * track->v.sampleRate / track->f.sampleRate);
+
+		m_isDirty = false;
+
+		if (reset(file, track) == AF_FAIL)
+			return AF_FAIL;
+	}
+	else
+	{
+		track->nextvframe = track->totalvframes =
+			(AFframecount) (fframepos * track->v.sampleRate / track->f.sampleRate);
+		m_isDirty = false;
+	}
+
+	return AF_SUCCEED;
+}
+
+const std::vector<SharedPtr<Module> > &ModuleState::modules() const
+{
+	return m_modules;
+}
+
+const std::vector<SharedPtr<Chunk> > &ModuleState::chunks() const
+{
+	return m_chunks;
+}
+
+status ModuleState::reset(AFfilehandle file, Track *track)
+{
+	track->filemodhappy = true;
+	for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
+			i != m_modules.rend(); ++i)
+		(*i)->reset1();
+	track->frames2ignore = 0;
+	if (!track->filemodhappy)
+		return AF_FAIL;
+	for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
+			i != m_modules.end(); ++i)
+		(*i)->reset2();
+	if (!track->filemodhappy)
+		return AF_FAIL;
+	return AF_SUCCEED;
+}
+
+status ModuleState::sync(AFfilehandle file, Track *track)
+{
+	track->filemodhappy = true;
+	for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
+			i != m_modules.rend(); ++i)
+		(*i)->sync1();
+	if (!track->filemodhappy)
+		return AF_FAIL;
+	for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
+			i != m_modules.end(); ++i)
+		(*i)->sync2();
+	return AF_SUCCEED;
+}
+
+static const PCMInfo * const intmappings[6] =
+{
+	&_af_default_signed_integer_pcm_mappings[1],
+	&_af_default_signed_integer_pcm_mappings[2],
+	&_af_default_signed_integer_pcm_mappings[3],
+	&_af_default_signed_integer_pcm_mappings[4],
+	NULL,
+	NULL
+};
+
+static FormatCode getFormatCode(const AudioFormat &format)
+{
+	if (format.sampleFormat == AF_SAMPFMT_FLOAT)
+		return kFloat;
+	if (format.sampleFormat == AF_SAMPFMT_DOUBLE)
+		return kDouble;
+	if (format.isInteger())
+	{
+		switch (format.bytesPerSample(false))
+		{
+			case 1: return kInt8;
+			case 2: return kInt16;
+			case 3: return kInt24;
+			case 4: return kInt32;
+		}
+	}
+
+	/* NOTREACHED */
+	assert(false);
+	return kUndefined;
+}
+
+static bool isInteger(FormatCode code) { return code >= kInt8 && code <= kInt32; }
+static bool isFloat(FormatCode code) { return code >= kFloat && code <= kDouble; }
+
+static bool isTrivialIntMapping(const AudioFormat &format, FormatCode code)
+{
+	return intmappings[code] != NULL &&
+		format.pcm.slope == intmappings[code]->slope &&
+		format.pcm.intercept == intmappings[code]->intercept;
+}
+
+static bool isTrivialIntClip(const AudioFormat &format, FormatCode code)
+{
+	return intmappings[code] != NULL &&
+		format.pcm.minClip == intmappings[code]->minClip &&
+		format.pcm.maxClip == intmappings[code]->maxClip;
+}
+
+status ModuleState::arrange(AFfilehandle file, Track *track)
+{
+	bool isReading = file->m_access == _AF_READ_ACCESS;
+	AudioFormat in, out;
+	if (isReading)
+	{
+		in = track->f;
+		out = track->v;
+	}
+	else
+	{
+		in = track->v;
+		out = track->f;
+	}
+
+	FormatCode infc = getFormatCode(in);
+	FormatCode outfc = getFormatCode(out);
+	if (infc == kUndefined || outfc == kUndefined)
+		return AF_FAIL;
+
+	m_chunks.clear();
+	m_chunks.push_back(new Chunk());
+	m_chunks.back()->f = in;
+
+	m_modules.clear();
+
+	if (isReading)
+	{
+		addModule(m_fileModule.get());
+		addModule(m_fileRebufferModule.get());
+	}
+
+	// Convert to native byte order.
+	if (in.byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		size_t bytesPerSample = in.bytesPerSample(!isReading);
+		if (bytesPerSample > 1 && in.compressionType == AF_COMPRESSION_NONE)
+			addModule(new SwapModule());
+		else
+			in.byteOrder = _AF_BYTEORDER_NATIVE;
+	}
+
+	// Handle 24-bit integer input format.
+	if (in.isInteger() && in.bytesPerSample(false) == 3)
+	{
+		if (isReading || in.compressionType != AF_COMPRESSION_NONE)
+			addModule(new Expand3To4Module(in.isSigned()));
+	}
+
+	// Make data signed.
+	if (in.isUnsigned())
+		addModule(new ConvertSign(infc, false));
+
+	in.pcm = m_chunks.back()->f.pcm;
+
+	// Reverse the unsigned shift for output.
+	if (out.isUnsigned())
+	{
+		const double shift = intmappings[outfc]->minClip;
+		out.pcm.intercept += shift;
+		out.pcm.minClip += shift;
+		out.pcm.maxClip += shift;
+	}
+
+	// Clip input samples if necessary.
+	if (in.pcm.minClip < in.pcm.maxClip && !isTrivialIntClip(in, infc))
+		addModule(new Clip(infc, in.pcm));
+
+	bool alreadyClippedOutput = false;
+	bool alreadyTransformedOutput = false;
+	// Perform range transformation if input and output PCM mappings differ.
+	bool transforming = (in.pcm.slope != out.pcm.slope ||
+		in.pcm.intercept != out.pcm.intercept) &&
+		!(isTrivialIntMapping(in, infc) &&
+		isTrivialIntMapping(out, outfc));
+
+	// Range transformation requires input to be floating-point.
+	if (isInteger(infc) && transforming)
+	{
+		if (infc == kInt32 || outfc == kDouble || outfc == kInt32)
+		{
+			addConvertIntToFloat(infc, kDouble);
+			infc = kDouble;
+		}
+		else
+		{
+			addConvertIntToFloat(infc, kFloat);
+			infc = kFloat;
+		}
+	}
+
+	if (transforming && infc == kDouble && isFloat(outfc))
+		addModule(new Transform(infc, in.pcm, out.pcm));
+
+	// Add format conversion if needed.
+	if (isInteger(infc) && isInteger(outfc))
+		addConvertIntToInt(infc, outfc);
+	else if (isInteger(infc) && isFloat(outfc))
+		addConvertIntToFloat(infc, outfc);
+	else if (isFloat(infc) && isInteger(outfc))
+	{
+		addConvertFloatToInt(infc, outfc, in.pcm, out.pcm);
+		alreadyClippedOutput = true;
+		alreadyTransformedOutput = true;
+	}
+	else if (isFloat(infc) && isFloat(outfc))
+		addConvertFloatToFloat(infc, outfc);
+
+	if (transforming && !alreadyTransformedOutput && infc != kDouble)
+		addModule(new Transform(outfc, in.pcm, out.pcm));
+
+	if (in.channelCount != out.channelCount)
+		addModule(new ApplyChannelMatrix(outfc, isReading,
+			in.channelCount, out.channelCount,
+			in.pcm.minClip, in.pcm.maxClip,
+			track->channelMatrix));
+
+	// Perform clipping if necessary.
+	if (!alreadyClippedOutput)
+	{
+		if (out.pcm.minClip < out.pcm.maxClip && !isTrivialIntClip(out, outfc))
+			addModule(new Clip(outfc, out.pcm));
+	}
+
+	// Make data unsigned if necessary.
+	if (out.isUnsigned())
+		addModule(new ConvertSign(outfc, true));
+
+	// Handle 24-bit integer output format.
+	if (out.isInteger() && out.bytesPerSample(false) == 3)
+	{
+		if (!isReading || out.compressionType != AF_COMPRESSION_NONE)
+			addModule(new Compress4To3Module(out.isSigned()));
+	}
+
+	if (out.byteOrder != _AF_BYTEORDER_NATIVE)
+	{
+		size_t bytesPerSample = out.bytesPerSample(isReading);
+		if (bytesPerSample > 1 && out.compressionType == AF_COMPRESSION_NONE)
+			addModule(new SwapModule());
+		else
+			out.byteOrder = _AF_BYTEORDER_NATIVE;
+	}
+
+	if (!isReading)
+	{
+		addModule(m_fileRebufferModule.get());
+		addModule(m_fileModule.get());
+	}
+
+	return AF_SUCCEED;
+}
+
+void ModuleState::addModule(Module *module)
+{
+	if (!module)
+		return;
+
+	m_modules.push_back(module);
+	module->setInChunk(m_chunks.back().get());
+	Chunk *chunk = new Chunk();
+	chunk->f = m_chunks.back()->f;
+	m_chunks.push_back(chunk);
+	module->setOutChunk(chunk);
+	module->describe();
+}
+
+void ModuleState::addConvertIntToInt(FormatCode input, FormatCode output)
+{
+	if (input == output)
+		return;
+
+	assert(isInteger(input));
+	assert(isInteger(output));
+	addModule(new ConvertInt(input, output));
+}
+
+void ModuleState::addConvertIntToFloat(FormatCode input, FormatCode output)
+{
+	addModule(new ConvertIntToFloat(input, output));
+}
+
+void ModuleState::addConvertFloatToInt(FormatCode input, FormatCode output,
+	const PCMInfo &inputMapping, const PCMInfo &outputMapping)
+{
+	addModule(new ConvertFloatToIntClip(input, output, inputMapping, outputMapping));
+}
+
+void ModuleState::addConvertFloatToFloat(FormatCode input, FormatCode output)
+{
+	if (input == output)
+		return;
+
+	assert((input == kFloat && output == kDouble) ||
+		(input == kDouble && output == kFloat));
+	addModule(new ConvertFloat(input, output));
+}
+
+void ModuleState::print()
+{
+	fprintf(stderr, "modules:\n");
+	for (size_t i=0; i<m_modules.size(); i++)
+		fprintf(stderr, " %s (%p) in %p out %p\n",
+			m_modules[i]->name(), m_modules[i].get(),
+			m_modules[i]->inChunk(),
+			m_modules[i]->outChunk());
+	fprintf(stderr, "chunks:\n");
+	for (size_t i=0; i<m_chunks.size(); i++)
+		fprintf(stderr, " %p %s\n",
+			m_chunks[i].get(),
+			m_chunks[i]->f.description().c_str());
+}
diff --git a/libaudiofile/modules/ModuleState.h b/libaudiofile/modules/ModuleState.h
new file mode 100644
index 0000000..c7912d0
--- /dev/null
+++ b/libaudiofile/modules/ModuleState.h
@@ -0,0 +1,77 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef MODULESTATE_H
+#define MODULESTATE_H
+
+#include "Module.h"
+#include "Shared.h"
+#include "afinternal.h"
+#include <vector>
+
+class FileModule;
+class Module;
+
+class ModuleState : public Shared<ModuleState>
+{
+public:
+	ModuleState();
+	virtual ~ModuleState();
+
+	bool isDirty() const { return m_isDirty; }
+	void setDirty() { m_isDirty = true; }
+	status init(AFfilehandle file, Track *track);
+	status setup(AFfilehandle file, Track *track);
+	status reset(AFfilehandle file, Track *track);
+	status sync(AFfilehandle file, Track *track);
+
+	int numModules() const { return m_modules.size(); }
+	const std::vector<SharedPtr<Module> > &modules() const;
+	const std::vector<SharedPtr<Chunk> > &chunks() const;
+
+	bool mustUseAtomicNVFrames() const { return true; }
+
+	void print();
+
+	bool fileModuleHandlesSeeking() const;
+
+private:
+	std::vector<SharedPtr<Module> > m_modules;
+	std::vector<SharedPtr<Chunk> > m_chunks;
+	bool m_isDirty;
+
+	SharedPtr<FileModule> m_fileModule;
+	SharedPtr<Module> m_fileRebufferModule;
+
+	status initFileModule(AFfilehandle file, Track *track);
+
+	status arrange(AFfilehandle file, Track *track);
+
+	void addModule(Module *module);
+
+	void addConvertIntToInt(FormatCode input, FormatCode output);
+	void addConvertIntToFloat(FormatCode input, FormatCode output);
+	void addConvertFloatToInt(FormatCode input, FormatCode output,
+		const PCMInfo &inputMapping, const PCMInfo &outputMapping);
+	void addConvertFloatToFloat(FormatCode input, FormatCode output);
+};
+
+#endif
diff --git a/libaudiofile/modules/PCM.cpp b/libaudiofile/modules/PCM.cpp
new file mode 100644
index 0000000..ad4557a
--- /dev/null
+++ b/libaudiofile/modules/PCM.cpp
@@ -0,0 +1,202 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	PCM.cpp - read and file write module for uncompressed data
+*/
+
+#include "config.h"
+#include "PCM.h"
+
+#include <assert.h>
+#include <math.h>
+
+#include "Compiler.h"
+#include "FileModule.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "compression.h"
+#include "util.h"
+
+bool _af_pcm_format_ok (AudioFormat *f)
+{
+	assert(!isnan(f->pcm.slope));
+	assert(!isnan(f->pcm.intercept));
+	assert(!isnan(f->pcm.minClip));
+	assert(!isnan(f->pcm.maxClip));
+
+	return true;
+}
+
+class PCM : public FileModule
+{
+public:
+	static PCM *createCompress(Track *track, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+	static PCM *createDecompress(Track *track, File *fh, bool canSeek,
+		bool headerless, AFframecount *chunkFrames);
+
+	virtual const char *name() const OVERRIDE { return "pcm"; }
+	virtual void runPull() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+
+private:
+	int m_bytesPerFrame;
+
+	/* saved_fpos_next_frame and saved_nextfframe apply only to writing. */
+	int m_saved_fpos_next_frame;
+	int m_saved_nextfframe;
+
+	PCM(Mode, Track *, File *, bool canSeek);
+};
+
+PCM::PCM(Mode mode, Track *track, File *fh, bool canSeek) :
+	FileModule(mode, track, fh, canSeek),
+	m_bytesPerFrame(track->f.bytesPerFrame(false)),
+	m_saved_fpos_next_frame(-1),
+	m_saved_nextfframe(-1)
+{
+	if (mode == Decompress)
+		track->f.compressionParams = AU_NULL_PVLIST;
+}
+
+PCM *PCM::createCompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkframes)
+{
+	return new PCM(Compress, track, fh, canSeek);
+}
+
+void PCM::runPush()
+{
+	AFframecount frames2write = m_inChunk->frameCount;
+	AFframecount n;
+
+	/*
+		WARNING: due to the optimization explained at the end
+		of arrangemodules(), the pcm file module cannot depend
+		on the presence of the intermediate working buffer
+		which _AFsetupmodules usually allocates for file
+		modules in their input or output chunk (for reading or
+		writing, respectively).
+
+		Fortunately, the pcm module has no need for such a buffer.
+	*/
+
+	ssize_t bytesWritten = write(m_inChunk->buffer, m_bytesPerFrame * frames2write);
+	n = bytesWritten >= 0 ? bytesWritten / m_bytesPerFrame : 0;
+
+	if (n != frames2write)
+		reportWriteError(n, frames2write);
+
+	m_track->nextfframe += n;
+	m_track->totalfframes = m_track->nextfframe;
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+}
+
+void PCM::sync1()
+{
+	m_saved_fpos_next_frame = m_track->fpos_next_frame;
+	m_saved_nextfframe = m_track->nextfframe;
+}
+
+void PCM::sync2()
+{
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+
+	/* We can afford to seek because sync2 is rare. */
+	m_track->fpos_after_data = tell();
+
+	m_track->fpos_next_frame = m_saved_fpos_next_frame;
+	m_track->nextfframe = m_saved_nextfframe;
+}
+
+PCM *PCM::createDecompress(Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkframes)
+{
+	return new PCM(Decompress, track, fh, canSeek);
+}
+
+void PCM::runPull()
+{
+	AFframecount framesToRead = m_outChunk->frameCount;
+
+	/*
+		WARNING: Due to the optimization explained at the end of
+		arrangemodules(), the pcm file module cannot depend on
+		the presence of the intermediate working buffer which
+		_AFsetupmodules usually allocates for file modules in
+		their input or output chunk (for reading or writing,
+		respectively).
+
+		Fortunately, the pcm module has no need for such a buffer.
+	*/
+
+	/*
+		Limit the number of frames to be read to the number of
+		frames left in the track.
+	*/
+	if (m_track->totalfframes != -1 &&
+		m_track->nextfframe + framesToRead > m_track->totalfframes)
+	{
+		framesToRead = m_track->totalfframes - m_track->nextfframe;
+	}
+
+	ssize_t bytesRead = read(m_outChunk->buffer, m_bytesPerFrame * framesToRead);
+	AFframecount framesRead = bytesRead >= 0 ? bytesRead / m_bytesPerFrame : 0;
+
+	m_track->nextfframe += framesRead;
+	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
+
+	/*
+		If we got EOF from read, then we return the actual amount read.
+
+		Complain only if there should have been more frames in the file.
+	*/
+
+	if (framesRead != framesToRead && m_track->totalfframes != -1)
+		reportReadError(framesRead, framesToRead);
+
+	m_outChunk->frameCount = framesRead;
+}
+
+void PCM::reset2()
+{
+	m_track->fpos_next_frame = m_track->fpos_first_frame +
+		m_bytesPerFrame * m_track->nextfframe;
+
+	m_track->frames2ignore = 0;
+}
+
+FileModule *_AFpcminitcompress (Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return PCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
+}
+
+FileModule *_AFpcminitdecompress (Track *track, File *fh, bool canSeek,
+	bool headerless, AFframecount *chunkFrames)
+{
+	return PCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
+}
diff --git a/libaudiofile/modules/PCM.h b/libaudiofile/modules/PCM.h
new file mode 100644
index 0000000..f576873
--- /dev/null
+++ b/libaudiofile/modules/PCM.h
@@ -0,0 +1,45 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	PCM.h
+*/
+
+#ifndef MODULES_PCM_H
+#define MODULES_PCM_H
+
+#include "afinternal.h"
+#include "audiofile.h"
+
+class File;
+class FileModule;
+struct AudioFormat;
+struct Track;
+
+bool _af_pcm_format_ok (AudioFormat *f);
+
+FileModule *_AFpcminitcompress(Track *, File *, bool seekok,
+	bool headerless, AFframecount *chunkframes);
+
+FileModule *_AFpcminitdecompress(Track *, File *, bool seekok,
+	bool headerless, AFframecount *chunkframes);
+
+#endif /* MODULES_PCM_H */
diff --git a/libaudiofile/modules/RebufferModule.cpp b/libaudiofile/modules/RebufferModule.cpp
new file mode 100644
index 0000000..5fe10d7
--- /dev/null
+++ b/libaudiofile/modules/RebufferModule.cpp
@@ -0,0 +1,271 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "RebufferModule.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <string.h>
+
+RebufferModule::RebufferModule(Direction direction, int bytesPerFrame,
+	int numFrames, bool multipleOf) :
+	m_direction(direction),
+	m_bytesPerFrame(bytesPerFrame),
+	m_numFrames(numFrames),
+	m_multipleOf(multipleOf),
+	m_eof(false),
+	m_sentShortChunk(false),
+	m_buffer(NULL),
+	m_offset(-1),
+	m_savedBuffer(NULL),
+	m_savedOffset(-1)
+{
+	if (m_direction == FixedToVariable)
+		initFixedToVariable();
+	else
+		initVariableToFixed();
+}
+
+RebufferModule::~RebufferModule()
+{
+	delete [] m_buffer;
+	delete [] m_savedBuffer;
+}
+
+void RebufferModule::initFixedToVariable()
+{
+	m_offset = m_numFrames;
+	m_buffer = new char[m_numFrames * m_bytesPerFrame];
+}
+
+void RebufferModule::initVariableToFixed()
+{
+	m_offset = 0;
+	m_buffer = new char[m_numFrames * m_bytesPerFrame];
+	m_savedBuffer = new char[m_numFrames * m_bytesPerFrame];
+}
+
+void RebufferModule::maxPull()
+{
+	assert(m_direction == FixedToVariable);
+	if (m_multipleOf)
+		m_inChunk->frameCount = m_outChunk->frameCount + m_numFrames;
+	else
+		m_inChunk->frameCount = m_numFrames;
+}
+
+void RebufferModule::maxPush()
+{
+	assert(m_direction == VariableToFixed);
+	if (m_multipleOf)
+		m_outChunk->frameCount = m_inChunk->frameCount + m_numFrames;
+	else
+		m_outChunk->frameCount = m_numFrames;
+}
+
+void RebufferModule::runPull()
+{
+	int framesToPull = m_outChunk->frameCount;
+	const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
+	char *outBuffer = static_cast<char *>(m_outChunk->buffer);
+
+	assert(m_offset > 0 && m_offset <= m_numFrames);
+
+	/*
+		A module should not pull more frames from its input
+		after receiving a short chunk.
+	*/
+	assert(!m_sentShortChunk);
+
+	if (m_offset < m_numFrames)
+	{
+		int buffered = m_numFrames - m_offset;
+		int n = std::min(framesToPull, buffered);
+		memcpy(outBuffer, m_buffer + m_offset * m_bytesPerFrame,
+			n * m_bytesPerFrame);
+		outBuffer += buffered * m_bytesPerFrame;
+		framesToPull -= buffered;
+		m_offset += n;
+	}
+
+	// Try to pull more frames from the source.
+	while (!m_eof && framesToPull > 0)
+	{
+		int framesRequested;
+		if (m_multipleOf)
+			// Round framesToPull up to nearest multiple of m_numFrames.
+			framesRequested = ((framesToPull - 1) / m_numFrames + 1) * m_numFrames;
+		else
+			framesRequested = m_numFrames;
+
+		assert(framesRequested > 0);
+
+		pull(framesRequested);
+
+		int framesReceived = m_inChunk->frameCount;
+
+		if (framesReceived != framesRequested)
+			m_eof = true;
+
+		memcpy(outBuffer, inBuffer,
+			std::min(framesToPull, framesReceived) * m_bytesPerFrame);
+
+		outBuffer += framesReceived * m_bytesPerFrame;
+		framesToPull -= framesReceived;
+
+		if (m_multipleOf)
+			assert(m_eof || framesToPull <= 0);
+
+		if (framesToPull < 0)
+		{
+			assert(m_offset == m_numFrames);
+
+			m_offset = m_numFrames + framesToPull;
+
+			assert(m_offset > 0 && m_offset <= m_numFrames);
+
+			memcpy(m_buffer + m_offset * m_bytesPerFrame,
+				inBuffer + (framesReceived + framesToPull) * m_bytesPerFrame,
+				(m_numFrames - m_offset) * m_bytesPerFrame);
+		}
+		else
+		{
+			assert(m_offset == m_numFrames);
+		}
+	}
+
+	if (m_eof && framesToPull > 0)
+	{
+		// Output short chunk.
+		m_outChunk->frameCount -= framesToPull;
+		m_sentShortChunk = true;
+		assert(m_offset == m_numFrames);
+	}
+	else
+	{
+		assert(framesToPull <= 0);
+		assert(m_offset == m_numFrames + framesToPull);
+	}
+	assert(m_offset > 0 && m_offset <= m_numFrames);
+}
+
+void RebufferModule::reset1()
+{
+	m_offset = m_numFrames;
+	m_eof = false;
+	m_sentShortChunk = false;
+	assert(m_offset > 0 && m_offset <= m_numFrames);
+}
+
+void RebufferModule::reset2()
+{
+	assert(m_offset > 0 && m_offset <= m_numFrames);
+}
+
+void RebufferModule::runPush()
+{
+	int framesToPush = m_inChunk->frameCount;
+	const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
+	char *outBuffer = static_cast<char *>(m_outChunk->buffer);
+
+	assert(m_offset >= 0 && m_offset < m_numFrames);
+
+	// Check that we will be able to push even one block.
+	if (m_offset + framesToPush >= m_numFrames)
+	{
+		if (m_offset > 0)
+			memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);
+
+		if (m_multipleOf)
+		{
+			// Round down to nearest multiple of m_numFrames.
+			int n = ((m_offset + framesToPush) / m_numFrames) * m_numFrames;
+
+			assert(n > m_offset);
+			memcpy(outBuffer + m_offset * m_bytesPerFrame,
+				inBuffer,
+				(n - m_offset) * m_bytesPerFrame);
+
+			push(n);
+
+			inBuffer += (n - m_offset) * m_bytesPerFrame;
+			framesToPush -= n - m_offset;
+			assert(framesToPush >= 0);
+			m_offset = 0;
+		}
+		else
+		{
+			while (m_offset + framesToPush >= m_numFrames)
+			{
+				int n = m_numFrames - m_offset;
+				memcpy(outBuffer + m_offset * m_bytesPerFrame,
+					inBuffer,
+					n * m_bytesPerFrame);
+
+				push(m_numFrames);
+
+				inBuffer += n * m_bytesPerFrame;
+				framesToPush -= n;
+				assert(framesToPush >= 0);
+				m_offset = 0;
+			}
+		}
+
+		assert(m_offset == 0);
+	}
+
+	assert(m_offset + framesToPush < m_numFrames);
+
+	// Save remaining samples in buffer.
+	if (framesToPush > 0)
+	{
+		memcpy(m_buffer + m_offset * m_bytesPerFrame,
+			inBuffer,
+			framesToPush * m_bytesPerFrame);
+		m_offset += framesToPush;
+	}
+
+	assert(m_offset >= 0 && m_offset < m_numFrames);
+}
+
+void RebufferModule::sync1()
+{
+	assert(m_offset >= 0 && m_offset < m_numFrames);
+
+	// Save all the frames and the offset so we can restore our state later.
+	memcpy(m_savedBuffer, m_buffer, m_numFrames * m_bytesPerFrame);
+	m_savedOffset = m_offset;
+}
+
+void RebufferModule::sync2()
+{
+	assert(m_offset >= 0 && m_offset < m_numFrames);
+
+	memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);
+
+	push(m_offset);
+
+	memcpy(m_buffer, m_savedBuffer, m_numFrames * m_bytesPerFrame);
+	m_offset = m_savedOffset;
+
+	assert(m_offset >= 0 && m_offset < m_numFrames);
+}
diff --git a/libaudiofile/modules/RebufferModule.h b/libaudiofile/modules/RebufferModule.h
new file mode 100644
index 0000000..f0f263d
--- /dev/null
+++ b/libaudiofile/modules/RebufferModule.h
@@ -0,0 +1,68 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef REBUFFER_MODULE_H
+#define REBUFFER_MODULE_H
+
+#include "Compiler.h"
+#include "Module.h"
+
+class RebufferModule : public Module
+{
+public:
+	enum Direction
+	{
+		FixedToVariable,
+		VariableToFixed
+	};
+
+	RebufferModule(Direction, int bytesPerFrame, int numFrames, bool multipleOf);
+	virtual ~RebufferModule();
+
+	virtual const char *name() const OVERRIDE { return "rebuffer"; }
+
+	virtual void maxPull() OVERRIDE;
+	virtual void maxPush() OVERRIDE;
+
+	virtual void runPull() OVERRIDE;
+	virtual void reset1() OVERRIDE;
+	virtual void reset2() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void sync1() OVERRIDE;
+	virtual void sync2() OVERRIDE;
+
+private:
+	Direction m_direction;
+	int m_bytesPerFrame;
+	int m_numFrames;
+	bool m_multipleOf; // buffer to multiple of m_numFrames
+	bool m_eof; // end of input stream reached
+	bool m_sentShortChunk; // end of input stream indicated
+	char *m_buffer;
+	int m_offset;
+	char *m_savedBuffer;
+	int m_savedOffset;
+
+	void initFixedToVariable();
+	void initVariableToFixed();
+};
+
+#endif // REBUFFER_MODULE_H
diff --git a/libaudiofile/modules/SimpleModule.cpp b/libaudiofile/modules/SimpleModule.cpp
new file mode 100644
index 0000000..2bae1eb
--- /dev/null
+++ b/libaudiofile/modules/SimpleModule.cpp
@@ -0,0 +1,174 @@
+/*
+	Audio File Library
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+#include "SimpleModule.h"
+
+#include <algorithm>
+
+void SimpleModule::runPull()
+{
+	pull(m_outChunk->frameCount);
+	run(*m_inChunk, *m_outChunk);
+}
+
+void SimpleModule::runPush()
+{
+	m_outChunk->frameCount = m_inChunk->frameCount;
+	run(*m_inChunk, *m_outChunk);
+	push(m_outChunk->frameCount);
+}
+
+ApplyChannelMatrix::ApplyChannelMatrix(FormatCode format, bool isReading,
+	int inChannels, int outChannels,
+	double minClip, double maxClip, const double *matrix) :
+	m_format(format),
+	m_inChannels(inChannels),
+	m_outChannels(outChannels),
+	m_minClip(minClip),
+	m_maxClip(maxClip),
+	m_matrix(NULL)
+{
+	m_matrix = new double[m_inChannels * m_outChannels];
+	if (matrix)
+	{
+		if (isReading)
+		{
+			// Copy channel matrix for reading.
+			std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
+		}
+		else
+		{
+			// Transpose channel matrix for writing.
+			for (int i=0; i < inChannels; i++)
+				for (int j=0; j < outChannels; j++)
+					m_matrix[j*inChannels + i] = matrix[i*outChannels + j];
+		}
+	}
+	else
+	{
+		initDefaultMatrix();
+	}
+}
+
+ApplyChannelMatrix::~ApplyChannelMatrix()
+{
+	delete [] m_matrix;
+}
+
+const char *ApplyChannelMatrix::name() const { return "channelMatrix"; }
+
+void ApplyChannelMatrix::describe()
+{
+	m_outChunk->f.channelCount = m_outChannels;
+	m_outChunk->f.pcm.minClip = m_minClip;
+	m_outChunk->f.pcm.maxClip = m_maxClip;
+}
+
+void ApplyChannelMatrix::run(Chunk &inChunk, Chunk &outChunk)
+{
+	switch (m_format)
+	{
+		case kInt8:
+			run<int8_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
+			break;
+		case kInt16:
+			run<int16_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
+			break;
+		case kInt24:
+		case kInt32:
+			run<int32_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
+			break;
+		case kFloat:
+			run<float>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
+			break;
+		case kDouble:
+			run<double>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
+			break;
+		default:
+			assert(false);
+	}
+}
+
+template <typename T>
+void ApplyChannelMatrix::run(const void *inputData, void *outputData, int frameCount)
+{
+	const T *input = reinterpret_cast<const T *>(inputData);
+	T *output = reinterpret_cast<T *>(outputData);
+	for (int frame=0; frame<frameCount; frame++)
+	{
+		const T *inputSave = input;
+		const double *m = m_matrix;
+		for (int outChannel=0; outChannel < m_outChannels; outChannel++)
+		{
+			input = inputSave;
+			double t = 0;
+			for (int inChannel=0; inChannel < m_inChannels; inChannel++)
+				t += *input++ * *m++;
+			*output++ = t;
+		}
+	}
+}
+
+void ApplyChannelMatrix::initDefaultMatrix()
+{
+	const double *matrix = NULL;
+	if (m_inChannels==1 && m_outChannels==2)
+	{
+		static const double m[]={1,1};
+		matrix = m;
+	}
+	else if (m_inChannels==1 && m_outChannels==4)
+	{
+		static const double m[]={1,1,0,0};
+		matrix = m;
+	}
+	else if (m_inChannels==2 && m_outChannels==1)
+	{
+		static const double m[]={.5,.5};
+		matrix = m;
+	}
+	else if (m_inChannels==2 && m_outChannels==4)
+	{
+		static const double m[]={1,0,0,1,0,0,0,0};
+		matrix = m;
+	}
+	else if (m_inChannels==4 && m_outChannels==1)
+	{
+		static const double m[]={.5,.5,.5,.5};
+		matrix = m;
+	}
+	else if (m_inChannels==4 && m_outChannels==2)
+	{
+		static const double m[]={1,0,1,0,0,1,0,1};
+		matrix = m;
+	}
+
+	if (matrix)
+	{
+		std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
+	}
+	else
+	{
+		for (int i=0; i < m_inChannels; i++)
+			for (int j=0; j < m_outChannels; j++)
+				m_matrix[j*m_inChannels + i] = (i==j) ? 1 : 0;
+	}
+}
diff --git a/libaudiofile/modules/SimpleModule.h b/libaudiofile/modules/SimpleModule.h
new file mode 100644
index 0000000..bad85ad
--- /dev/null
+++ b/libaudiofile/modules/SimpleModule.h
@@ -0,0 +1,760 @@
+/*
+	Audio File Library
+	Copyright (C) 2010, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef SIMPLE_MODULE_H
+#define SIMPLE_MODULE_H
+
+#include "config.h"
+
+#include "Compiler.h"
+#include "Module.h"
+#include "byteorder.h"
+
+#include <algorithm>
+#include <cassert>
+#include <climits>
+#include <functional>
+
+class SimpleModule : public Module
+{
+public:
+	virtual void runPull() OVERRIDE;
+	virtual void runPush() OVERRIDE;
+	virtual void run(Chunk &inChunk, Chunk &outChunk) = 0;
+};
+
+struct SwapModule : public SimpleModule
+{
+public:
+	virtual const char *name() const OVERRIDE { return "swap"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.byteOrder = m_inChunk->f.byteOrder == AF_BYTEORDER_BIGENDIAN ?
+			AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		switch (m_inChunk->f.bytesPerSample(false))
+		{
+			case 2:
+				run<2, int16_t>(inChunk, outChunk); break;
+			case 3:
+				run<3, char>(inChunk, outChunk); break;
+			case 4:
+				run<4, int32_t>(inChunk, outChunk); break;
+			case 8:
+				run<8, int64_t>(inChunk, outChunk); break;
+			default:
+				assert(false); break;
+		}
+	}
+
+private:
+	template <int N, typename T>
+	void run(Chunk &inChunk, Chunk &outChunk)
+	{
+		int sampleCount = inChunk.f.channelCount * inChunk.frameCount;
+		runSwap<N, T>(reinterpret_cast<const T *>(inChunk.buffer),
+			reinterpret_cast<T *>(outChunk.buffer),
+			sampleCount);
+	}
+	template <int N, typename T>
+	void runSwap(const T *input, T *output, int sampleCount)
+	{
+		for (int i=0; i<sampleCount; i++)
+			output[i] = byteswap(input[i]);
+	}
+};
+
+template <>
+inline void SwapModule::runSwap<3, char>(const char *input, char *output, int count)
+{
+	for (int i=0; i<count; i++)
+	{
+		output[3*i] = input[3*i+2];
+		output[3*i+1] = input[3*i+1];
+		output[3*i+2] = input[3*i];
+	}
+}
+
+template <typename UnaryFunction>
+void transform(const void *srcData, void *dstData, size_t count)
+{
+	typedef typename UnaryFunction::argument_type InputType;
+	typedef typename UnaryFunction::result_type OutputType;
+	const InputType *src = reinterpret_cast<const InputType *>(srcData);
+	OutputType *dst = reinterpret_cast<OutputType *>(dstData);
+	std::transform(src, src + count, dst, UnaryFunction());
+}
+
+template <FormatCode>
+struct IntTypes;
+
+template <>
+struct IntTypes<kInt8> { typedef int8_t SignedType; typedef uint8_t UnsignedType; };
+template <>
+struct IntTypes<kInt16> { typedef int16_t SignedType; typedef uint16_t UnsignedType; };
+template <>
+struct IntTypes<kInt24> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
+template <>
+struct IntTypes<kInt32> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
+
+template <FormatCode Format>
+struct signConverter
+{
+	typedef typename IntTypes<Format>::SignedType SignedType;
+	typedef typename IntTypes<Format>::UnsignedType UnsignedType;
+
+	static const int kScaleBits = (Format + 1) * CHAR_BIT - 1;
+	static const int kMaxSignedValue = (((1 << (kScaleBits - 1)) - 1) << 1) + 1;
+	static const int kMinSignedValue = -kMaxSignedValue - 1;
+
+	struct signedToUnsigned : public std::unary_function<SignedType, UnsignedType>
+	{
+		UnsignedType operator()(SignedType x) { return x - kMinSignedValue; }
+	};
+
+	struct unsignedToSigned : public std::unary_function<SignedType, UnsignedType>
+	{
+		SignedType operator()(UnsignedType x) { return x + kMinSignedValue; }
+	};
+};
+
+class ConvertSign : public SimpleModule
+{
+public:
+	ConvertSign(FormatCode format, bool fromSigned) :
+		m_format(format),
+		m_fromSigned(fromSigned)
+	{
+	}
+	virtual const char *name() const OVERRIDE { return "sign"; }
+	virtual void describe() OVERRIDE
+	{
+		const int scaleBits = m_inChunk->f.bytesPerSample(false) * CHAR_BIT;
+		m_outChunk->f.sampleFormat =
+			m_fromSigned ? AF_SAMPFMT_UNSIGNED : AF_SAMPFMT_TWOSCOMP;
+		double shift = -(1 << (scaleBits - 1));
+		if (m_fromSigned)
+			shift = -shift;
+		m_outChunk->f.pcm.intercept += shift;
+		m_outChunk->f.pcm.minClip += shift;
+		m_outChunk->f.pcm.maxClip += shift;
+	}
+	virtual void run(Chunk &input, Chunk &output) OVERRIDE
+	{
+		size_t count = input.frameCount * m_inChunk->f.channelCount;
+		if (m_fromSigned)
+			convertSignedToUnsigned(input.buffer, output.buffer, count);
+		else
+			convertUnsignedToSigned(input.buffer, output.buffer, count);
+	}
+
+private:
+	FormatCode m_format;
+	bool m_fromSigned;
+
+	template <FormatCode Format>
+	static void convertSignedToUnsigned(const void *src, void *dst, size_t count)
+	{
+		transform<typename signConverter<Format>::signedToUnsigned>(src, dst, count);
+	}
+	void convertSignedToUnsigned(const void *src, void *dst, size_t count)
+	{
+		switch (m_format)
+		{
+			case kInt8:
+				convertSignedToUnsigned<kInt8>(src, dst, count);
+				break;
+			case kInt16:
+				convertSignedToUnsigned<kInt16>(src, dst, count);
+				break;
+			case kInt24:
+				convertSignedToUnsigned<kInt24>(src, dst, count);
+				break;
+			case kInt32:
+				convertSignedToUnsigned<kInt32>(src, dst, count);
+				break;
+			default:
+				assert(false);
+		}
+	}
+
+	template <FormatCode Format>
+	static void convertUnsignedToSigned(const void *src, void *dst, size_t count)
+	{
+		transform<typename signConverter<Format>::unsignedToSigned>(src, dst, count);
+	}
+	void convertUnsignedToSigned(const void *src, void *dst, size_t count)
+	{
+		switch (m_format)
+		{
+			case kInt8:
+				convertUnsignedToSigned<kInt8>(src, dst, count);
+				break;
+			case kInt16:
+				convertUnsignedToSigned<kInt16>(src, dst, count);
+				break;
+			case kInt24:
+				convertUnsignedToSigned<kInt24>(src, dst, count);
+				break;
+			case kInt32:
+				convertUnsignedToSigned<kInt32>(src, dst, count);
+				break;
+			default:
+				assert(false);
+		}
+	}
+};
+
+struct Expand3To4Module : public SimpleModule
+{
+public:
+	Expand3To4Module(bool isSigned) : m_isSigned(isSigned)
+	{
+	}
+	virtual const char *name() const OVERRIDE { return "expand3to4"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.packed = false;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		int count = inChunk.f.channelCount * inChunk.frameCount;
+		if (m_isSigned)
+			run<int32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
+				reinterpret_cast<int32_t *>(outChunk.buffer),
+				count);
+		else
+			run<uint32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
+				reinterpret_cast<uint32_t *>(outChunk.buffer),
+				count);
+	}
+
+private:
+	bool m_isSigned;
+
+	template <typename T>
+	void run(const uint8_t *input, T *output, int sampleCount)
+	{
+		for (int i=0; i<sampleCount; i++)
+		{
+			T t =
+#ifdef WORDS_BIGENDIAN
+				(input[3*i] << 24) |
+				(input[3*i+1] << 16) |
+				input[3*i+2] << 8;
+#else
+				(input[3*i+2] << 24) |
+				(input[3*i+1] << 16) |
+				input[3*i] << 8;
+#endif
+			output[i] = t >> 8;
+		}
+	}
+};
+
+struct Compress4To3Module : public SimpleModule
+{
+public:
+	Compress4To3Module(bool isSigned) : m_isSigned(isSigned)
+	{
+	}
+	virtual const char *name() const OVERRIDE { return "compress4to3"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.packed = true;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		int count = inChunk.f.channelCount * inChunk.frameCount;
+		if (m_isSigned)
+			run<int32_t>(inChunk.buffer, outChunk.buffer, count);
+		else
+			run<uint32_t>(inChunk.buffer, outChunk.buffer, count);
+	}
+
+private:
+	bool m_isSigned;
+
+	template <typename T>
+	void run(const void *input, void *output, int count)
+	{
+		const T *in = reinterpret_cast<const T *>(input);
+		uint8_t *out = reinterpret_cast<uint8_t *>(output);
+		for (int i=0; i<count; i++)
+		{
+			uint8_t c0, c1, c2;
+			extract3(in[i], c0, c1, c2);
+			out[3*i] = c0;
+			out[3*i+1] = c1;
+			out[3*i+2] = c2;
+		}
+	}
+	template <typename T>
+	void extract3(T in, uint8_t &c0, uint8_t &c1, uint8_t &c2)
+	{
+#ifdef WORDS_BIGENDIAN
+			c0 = (in >> 16) & 0xff;
+			c1 = (in >> 8) & 0xff;
+			c2 = in & 0xff;
+#else
+			c2 = (in >> 16) & 0xff;
+			c1 = (in >> 8) & 0xff;
+			c0 = in & 0xff;
+#endif
+	}
+};
+
+template <typename Arg, typename Result>
+struct intToFloat : public std::unary_function<Arg, Result>
+{
+	Result operator()(Arg x) const { return x; }
+};
+
+struct ConvertIntToFloat : public SimpleModule
+{
+	ConvertIntToFloat(FormatCode inFormat, FormatCode outFormat) :
+		m_inFormat(inFormat), m_outFormat(outFormat)
+	{
+	}
+	virtual const char *name() const OVERRIDE { return "intToFloat"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.sampleFormat = m_outFormat == kDouble ?
+			AF_SAMPFMT_DOUBLE : AF_SAMPFMT_FLOAT;
+		m_outChunk->f.sampleWidth = m_outFormat == kDouble ? 64 : 32;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		const void *src = inChunk.buffer;
+		void *dst = outChunk.buffer;
+		int count = inChunk.frameCount * inChunk.f.channelCount;
+		if (m_outFormat == kFloat)
+		{
+			switch (m_inFormat)
+			{
+				case kInt8:
+					run<int8_t, float>(src, dst, count); break;
+				case kInt16:
+					run<int16_t, float>(src, dst, count); break;
+				case kInt24:
+				case kInt32:
+					run<int32_t, float>(src, dst, count); break;
+				default:
+					assert(false);
+			}
+		}
+		else if (m_outFormat == kDouble)
+		{
+			switch (m_inFormat)
+			{
+				case kInt8:
+					run<int8_t, double>(src, dst, count); break;
+				case kInt16:
+					run<int16_t, double>(src, dst, count); break;
+				case kInt24:
+				case kInt32:
+					run<int32_t, double>(src, dst, count); break;
+				default:
+					assert(false);
+			}
+		}
+	}
+
+private:
+	FormatCode m_inFormat, m_outFormat;
+
+	template <typename Arg, typename Result>
+	static void run(const void *src, void *dst, int count)
+	{
+		transform<intToFloat<Arg, Result> >(src, dst, count);
+	}
+};
+
+template <typename Arg, typename Result, unsigned shift>
+struct lshift : public std::unary_function<Arg, Result>
+{
+	Result operator()(const Arg &x) const { return x << shift; }
+};
+
+template <typename Arg, typename Result, unsigned shift>
+struct rshift : public std::unary_function<Arg, Result>
+{
+	Result operator()(const Arg &x) const { return x >> shift; }
+};
+
+struct ConvertInt : public SimpleModule
+{
+	ConvertInt(FormatCode inFormat, FormatCode outFormat) :
+		m_inFormat(inFormat),
+		m_outFormat(outFormat)
+	{
+		assert(isInteger(m_inFormat));
+		assert(isInteger(m_outFormat));
+	}
+	virtual const char *name() const OVERRIDE { return "convertInt"; }
+	virtual void describe() OVERRIDE
+	{
+		getDefaultPCMMapping(m_outChunk->f.sampleWidth,
+			m_outChunk->f.pcm.slope,
+			m_outChunk->f.pcm.intercept,
+			m_outChunk->f.pcm.minClip,
+			m_outChunk->f.pcm.maxClip);
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		const void *src = inChunk.buffer;
+		void *dst = outChunk.buffer;
+		size_t count = inChunk.frameCount * inChunk.f.channelCount;
+
+#define MASK(N, M) (((N)<<3) | (M))
+#define HANDLE(N, M) \
+	case MASK(N, M): convertInt<N, M>(src, dst, count); break;
+		switch (MASK(m_inFormat, m_outFormat))
+		{
+			HANDLE(kInt8, kInt16)
+			HANDLE(kInt8, kInt24)
+			HANDLE(kInt8, kInt32)
+			HANDLE(kInt16, kInt8)
+			HANDLE(kInt16, kInt24)
+			HANDLE(kInt16, kInt32)
+			HANDLE(kInt24, kInt8)
+			HANDLE(kInt24, kInt16)
+			HANDLE(kInt24, kInt32)
+			HANDLE(kInt32, kInt8)
+			HANDLE(kInt32, kInt16)
+			HANDLE(kInt32, kInt24)
+		}
+#undef MASK
+#undef HANDLE
+	}
+
+private:
+	FormatCode m_inFormat, m_outFormat;
+
+	void getDefaultPCMMapping(int &bits, double &slope, double &intercept,
+		double &minClip, double &maxClip)
+	{
+		bits = (m_outFormat + 1) * CHAR_BIT;
+		slope = (1LL << (bits - 1));
+		intercept = 0;
+		minClip = -(1 << (bits - 1));
+		maxClip = (1LL << (bits - 1)) - 1;
+	}
+
+	static bool isInteger(FormatCode code)
+	{
+		return code >= kInt8 && code <= kInt32;
+	}
+
+	template <FormatCode Input, FormatCode Output, bool = (Input > Output)>
+		struct shift;
+
+	template <FormatCode Input, FormatCode Output>
+	struct shift<Input, Output, true> :
+		public rshift<typename IntTypes<Input>::SignedType,
+			typename IntTypes<Output>::SignedType,
+			(Input - Output) * CHAR_BIT>
+	{
+	};
+
+	template <FormatCode Input, FormatCode Output>
+	struct shift<Input, Output, false> :
+		public lshift<typename IntTypes<Input>::SignedType,
+			typename IntTypes<Output>::SignedType,
+			(Output - Input) * CHAR_BIT>
+	{
+	};
+
+	template <FormatCode Input, FormatCode Output>
+	static void convertInt(const void *src, void *dst, int count)
+	{
+		transform<shift<Input, Output> >(src, dst, count);
+	}
+};
+
+template <typename Arg, typename Result>
+struct floatToFloat : public std::unary_function<Arg, Result>
+{
+	Result operator()(Arg x) const { return x; }
+};
+
+struct ConvertFloat : public SimpleModule
+{
+	ConvertFloat(FormatCode inFormat, FormatCode outFormat) :
+		m_inFormat(inFormat), m_outFormat(outFormat)
+	{
+		assert((m_inFormat == kFloat && m_outFormat == kDouble) ||
+			(m_inFormat == kDouble && m_outFormat == kFloat));
+	}
+	virtual const char *name() const OVERRIDE { return "convertFloat"; }
+	virtual void describe() OVERRIDE
+	{
+		switch (m_outFormat)
+		{
+			case kFloat:
+				m_outChunk->f.sampleFormat = AF_SAMPFMT_FLOAT;
+				m_outChunk->f.sampleWidth = 32;
+				break;
+			case kDouble:
+				m_outChunk->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+				m_outChunk->f.sampleWidth = 64;
+				break;
+			default:
+				assert(false);
+		}
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		const void *src = inChunk.buffer;
+		void *dst = outChunk.buffer;
+		size_t count = inChunk.frameCount * inChunk.f.channelCount;
+
+		switch (m_outFormat)
+		{
+			case kFloat:
+				transform<floatToFloat<double, float> >(src, dst, count);
+				break;
+			case kDouble:
+				transform<floatToFloat<float, double> >(src, dst, count);
+				break;
+			default:
+				assert(false);
+		}
+	}
+
+private:
+	FormatCode m_inFormat, m_outFormat;
+};
+
+struct Clip : public SimpleModule
+{
+	Clip(FormatCode format, const PCMInfo &outputMapping) :
+		m_format(format),
+		m_outputMapping(outputMapping)
+	{
+	}
+	virtual const char *name() const OVERRIDE { return "clip"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.pcm = m_outputMapping;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		const void *src = inChunk.buffer;
+		void *dst = outChunk.buffer;
+		int count = inChunk.frameCount * inChunk.f.channelCount;
+
+		switch (m_format)
+		{
+			case kInt8:
+				run<int8_t>(src, dst, count); break;
+			case kInt16:
+				run<int16_t>(src, dst, count); break;
+			case kInt24:
+			case kInt32:
+				run<int32_t>(src, dst, count); break;
+			case kFloat:
+				run<float>(src, dst, count); break;
+			case kDouble:
+				run<double>(src, dst, count); break;
+			default:
+				assert(false);
+		}
+	}
+
+private:
+	FormatCode m_format;
+	PCMInfo m_outputMapping;
+
+	template <typename T>
+	void run(const void *srcData, void *dstData, int count)
+	{
+		const T minValue = m_outputMapping.minClip;
+		const T maxValue = m_outputMapping.maxClip;
+
+		const T *src = reinterpret_cast<const T *>(srcData);
+		T *dst = reinterpret_cast<T *>(dstData);
+
+		for (int i=0; i<count; i++)
+		{
+			T t = src[i];
+			t = std::min(t, maxValue);
+			t = std::max(t, minValue);
+			dst[i] = t;
+		}
+	}
+};
+
+struct ConvertFloatToIntClip : public SimpleModule
+{
+	ConvertFloatToIntClip(FormatCode inputFormat, FormatCode outputFormat,
+		const PCMInfo &inputMapping, const PCMInfo &outputMapping) :
+		m_inputFormat(inputFormat),
+		m_outputFormat(outputFormat),
+		m_inputMapping(inputMapping),
+		m_outputMapping(outputMapping)
+	{
+		assert(m_inputFormat == kFloat || m_inputFormat == kDouble);
+		assert(m_outputFormat == kInt8 ||
+			m_outputFormat == kInt16 ||
+			m_outputFormat == kInt24 ||
+			m_outputFormat == kInt32);
+	}
+	virtual const char *name() const OVERRIDE { return "convertPCMMapping"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+		m_outChunk->f.sampleWidth = (m_outputFormat + 1) * CHAR_BIT;
+		m_outChunk->f.pcm = m_outputMapping;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		const void *src = inChunk.buffer;
+		void *dst = outChunk.buffer;
+		int count = inChunk.frameCount * inChunk.f.channelCount;
+
+		if (m_inputFormat == kFloat)
+		{
+			switch (m_outputFormat)
+			{
+				case kInt8:
+					run<float, int8_t>(src, dst, count); break;
+				case kInt16:
+					run<float, int16_t>(src, dst, count); break;
+				case kInt24:
+				case kInt32:
+					run<float, int32_t>(src, dst, count); break;
+				default:
+					assert(false);
+			}
+		}
+		else if (m_inputFormat == kDouble)
+		{
+			switch (m_outputFormat)
+			{
+				case kInt8:
+					run<double, int8_t>(src, dst, count); break;
+				case kInt16:
+					run<double, int16_t>(src, dst, count); break;
+				case kInt24:
+				case kInt32:
+					run<double, int32_t>(src, dst, count); break;
+				default:
+					assert(false);
+			}
+		}
+	}
+
+private:
+	FormatCode m_inputFormat, m_outputFormat;
+	PCMInfo m_inputMapping, m_outputMapping;
+
+	template <typename Input, typename Output>
+	void run(const void *srcData, void *dstData, int count)
+	{
+		const Input *src = reinterpret_cast<const Input *>(srcData);
+		Output *dst = reinterpret_cast<Output *>(dstData);
+
+		double m = m_outputMapping.slope / m_inputMapping.slope;
+		double b = m_outputMapping.intercept - m * m_inputMapping.intercept;
+		double minValue = m_outputMapping.minClip;
+		double maxValue = m_outputMapping.maxClip;
+
+		for (int i=0; i<count; i++)
+		{
+			double t = m * src[i] + b;
+			t = std::min(t, maxValue);
+			t = std::max(t, minValue);
+			dst[i] = static_cast<Output>(t);
+		}
+	}
+};
+
+struct ApplyChannelMatrix : public SimpleModule
+{
+public:
+	ApplyChannelMatrix(FormatCode format, bool isReading,
+		int inChannels, int outChannels,
+		double minClip, double maxClip, const double *matrix);
+	virtual ~ApplyChannelMatrix();
+	virtual const char *name() const OVERRIDE;
+	virtual void describe() OVERRIDE;
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE;
+
+private:
+	FormatCode m_format;
+	int m_inChannels, m_outChannels;
+	double m_minClip, m_maxClip;
+	double *m_matrix;
+
+	void initDefaultMatrix();
+	template <typename T>
+		void run(const void *input, void *output, int frameCount);
+};
+
+struct Transform : public SimpleModule
+{
+public:
+	Transform(FormatCode format,
+		const PCMInfo &inputMapping,
+		const PCMInfo &outputMapping) :
+		m_format(format),
+		m_inputMapping(inputMapping),
+		m_outputMapping(outputMapping)
+	{
+		assert(m_format == kFloat || m_format == kDouble);
+	}
+	virtual const char *name() const OVERRIDE { return "transform"; }
+	virtual void describe() OVERRIDE
+	{
+		m_outChunk->f.pcm = m_outputMapping;
+	}
+	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
+	{
+		int count = inChunk.frameCount * inChunk.f.channelCount;
+		if (m_format == kFloat)
+			run<float>(inChunk.buffer, outChunk.buffer, count);
+		else if (m_format == kDouble)
+			run<double>(inChunk.buffer, outChunk.buffer, count);
+		else
+			assert(false);
+	}
+
+private:
+	FormatCode m_format;
+	PCMInfo m_inputMapping, m_outputMapping;
+
+	template <typename T>
+	void run(const void *srcData, void *dstData, int count)
+	{
+		const T *src = reinterpret_cast<const T *>(srcData);
+		T *dst = reinterpret_cast<T *>(dstData);
+
+		double m = m_outputMapping.slope / m_inputMapping.slope;
+		double b = m_outputMapping.intercept - m * m_inputMapping.intercept;
+
+		for (int i=0; i<count; i++)
+			dst[i] = m * src[i] + b;
+	}
+};
+
+#endif // SIMPLE_MODULE_H
diff --git a/libaudiofile/modules/UT_RebufferModule.cpp b/libaudiofile/modules/UT_RebufferModule.cpp
new file mode 100644
index 0000000..0b73b12
--- /dev/null
+++ b/libaudiofile/modules/UT_RebufferModule.cpp
@@ -0,0 +1,336 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <limits>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "byteorder.h"
+#include "RebufferModule.h"
+
+static void setChunkData(Chunk &chunk, int frameOffset)
+{
+	int16_t *data = static_cast<int16_t *>(chunk.buffer);
+	int channels = chunk.f.channelCount;
+	for (unsigned i=0; i<chunk.frameCount; i++)
+		for (int c=0; c<channels; c++)
+			data[i*channels + c] = (frameOffset + i) * channels + c;
+}
+
+static void validateChunkData(const Chunk &chunk, int frameOffset)
+{
+	const int16_t *data = static_cast<const int16_t *>(chunk.buffer);
+	int channels = chunk.f.channelCount;
+	for (unsigned i=0; i < chunk.frameCount; i++)
+		for (int c=0; c < channels; c++)
+			EXPECT_EQ(data[i * channels + c],
+				int(frameOffset + i) * channels + c);
+}
+
+class TestSourceModule : public Module
+{
+public:
+	TestSourceModule() :
+		m_startFrame(0),
+		m_frameCount(0),
+		m_expectedRequestLength(0)
+	{
+	}
+	unsigned startFrame() const { return m_startFrame; }
+	void setStartFrame(unsigned startFrame) { m_startFrame = startFrame; }
+	unsigned frameCount() const { return m_frameCount; }
+	void setFrameCount(unsigned frameCount) { m_frameCount = frameCount; }
+	unsigned expectedRequestLength() const { return m_expectedRequestLength; }
+	void setExpectedRequestLength(unsigned expectedRequestLength)
+	{
+		m_expectedRequestLength = expectedRequestLength;
+	}
+
+	void runPull()
+	{
+		EXPECT_EQ(m_outChunk->frameCount, m_expectedRequestLength);
+		unsigned frameCount = std::min<unsigned>(m_outChunk->frameCount, m_frameCount);
+		m_outChunk->frameCount = frameCount;
+		setChunkData(*m_outChunk, m_startFrame);
+		m_startFrame += frameCount;
+		m_frameCount -= frameCount;
+	}
+
+private:
+	unsigned m_startFrame;
+	unsigned m_frameCount;
+	unsigned m_expectedRequestLength;
+};
+
+class TestSinkModule : public Module
+{
+public:
+	TestSinkModule() :
+		m_startFrame(0),
+		m_expectedRequestLength(0)
+	{
+	}
+	unsigned startFrame() const { return m_startFrame; }
+	void setStartFrame(unsigned startFrame) { m_startFrame = startFrame; }
+	unsigned expectedRequestLength() const { return m_expectedRequestLength; }
+	void setExpectedRequestLength(unsigned expectedRequestLength)
+	{
+		m_expectedRequestLength = expectedRequestLength;
+	}
+	void runPush()
+	{
+		EXPECT_EQ(m_inChunk->frameCount, m_expectedRequestLength);
+		validateChunkData(*m_inChunk, m_startFrame);
+		m_startFrame += m_inChunk->frameCount;
+	}
+
+private:
+	unsigned m_startFrame;
+	unsigned m_expectedRequestLength;
+};
+
+static AudioFormat createAudioFormat(int channels)
+{
+	AudioFormat f =
+	{
+		44100,
+		AF_SAMPFMT_TWOSCOMP,
+		16,
+		_AF_BYTEORDER_NATIVE,
+		{ 0, 0, 0, 0 },
+		channels,
+		AF_COMPRESSION_NONE,
+		NULL,
+		false
+	};
+
+	return f;
+}
+
+static void testFixedToVariable(bool multiple)
+{
+	const int channels = 2;
+	AudioFormat f = createAudioFormat(channels);
+
+	SharedPtr<RebufferModule> rebuffer =
+		new RebufferModule(RebufferModule::FixedToVariable, f.bytesPerFrame(),
+			10, multiple);
+
+	SharedPtr<TestSourceModule> source = new TestSourceModule();
+	rebuffer->setSource(source.get());
+
+	SharedPtr<Chunk> fixedChunk(new Chunk());
+	SharedPtr<Chunk> variableChunk(new Chunk());
+
+	const int maxFrameCount = 50;
+	fixedChunk->f = f;
+	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	variableChunk->f = f;
+	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	rebuffer->setInChunk(fixedChunk.get());
+	rebuffer->setOutChunk(variableChunk.get());
+
+	source->setOutChunk(fixedChunk.get());
+
+	// Initialize source to contain 100 frames.
+	source->setFrameCount(100);
+
+	// Request 22 frames from rebuffer module.
+	variableChunk->frameCount = 22;
+	source->setExpectedRequestLength(multiple ? 30 : 10);
+	rebuffer->runPull();
+	// Check that 30 frames have been pulled from source module.
+	EXPECT_EQ(30u, source->startFrame());
+	// Check that rebuffer module has fulfilled request of 22 frames.
+	EXPECT_EQ(22u, variableChunk->frameCount);
+	// Validate output data.
+	validateChunkData(*variableChunk, 0);
+
+	// Request 30 frames from rebuffer module.
+	variableChunk->frameCount = 30;
+	source->setExpectedRequestLength(multiple ? 30 : 10);
+	rebuffer->runPull();
+	// Check that 60 frames have been pulled from source module.
+	EXPECT_EQ(60u, source->startFrame());
+	// Check that rebuffer module has fulfilled request of 28 frames.
+	EXPECT_EQ(30u, variableChunk->frameCount);
+	// Validate output data.
+	validateChunkData(*variableChunk, 22);
+
+	// Request 50 frames from rebuffer module.
+	variableChunk->frameCount = 50;
+	source->setExpectedRequestLength(multiple ? 50 : 10);
+	rebuffer->runPull();
+	// Check that 100 frames have been pulled from source module.
+	EXPECT_EQ(100u, source->startFrame());
+	// Check that rebuffer module has filled 48 of 50 frames requested.
+	EXPECT_EQ(48u, variableChunk->frameCount);
+	// Validate output data.
+	validateChunkData(*variableChunk, 52);
+}
+
+TEST(RebufferModule, FixedToVariable)
+{
+	testFixedToVariable(false);
+}
+
+TEST(RebufferModule, FixedToVariable_Multiple)
+{
+	testFixedToVariable(true);
+}
+
+/*
+	Make a request to the rebuffer module which is large enough
+	to pull the final short chunk from the test source but which
+	doesn't consume all the frames of that chunk.
+
+	Verify that a subsequent request to the rebuffer module correctly
+	produces the remaining frames of that chunk.
+*/
+static void testBufferingAfterShortChunk(bool multiple)
+{
+	const int channels = 2;
+	AudioFormat f = createAudioFormat(channels);
+
+	SharedPtr<RebufferModule> rebuffer =
+		new RebufferModule(RebufferModule::FixedToVariable, f.bytesPerFrame(),
+			10, multiple);
+
+	SharedPtr<TestSourceModule> source = new TestSourceModule();
+	rebuffer->setSource(source.get());
+
+	SharedPtr<Chunk> fixedChunk(new Chunk());
+	SharedPtr<Chunk> variableChunk(new Chunk());
+
+	const int maxFrameCount = 30;
+	fixedChunk->f = f;
+	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	variableChunk->f = f;
+	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	rebuffer->setInChunk(fixedChunk.get());
+	rebuffer->setOutChunk(variableChunk.get());
+
+	source->setOutChunk(fixedChunk.get());
+
+	// Initialize source to contain 23 frames.
+	source->setFrameCount(23);
+
+	// Request 21 frames from rebuffer module.
+	variableChunk->frameCount = 21;
+	source->setExpectedRequestLength(multiple ? 30 : 10);
+	rebuffer->runPull();
+	// Check that all 23 frames have been pulled from source module.
+	EXPECT_EQ(23u, source->startFrame());
+	// Check that rebuffer module has fulfilled request of 21 frames.
+	EXPECT_EQ(21u, variableChunk->frameCount);
+	// Validate output data.
+	validateChunkData(*variableChunk, 0);
+
+	// Request 5 frames from rebuffer module.
+	variableChunk->frameCount = 5;
+	source->setExpectedRequestLength(-1);
+	rebuffer->runPull();
+	// Check that rebuffer module has delivered remaining 2 frames.
+	EXPECT_EQ(2u, variableChunk->frameCount);
+	// Validate output data.
+	validateChunkData(*variableChunk, 21);
+}
+
+TEST(RebufferModule, FixedToVariable_BufferingAfterShortChunk)
+{
+	testBufferingAfterShortChunk(false);
+}
+
+TEST(RebufferModule, FixedToVariable_BufferingAfterShortChunk_Multiple)
+{
+	testBufferingAfterShortChunk(true);
+}
+
+static void testVariableToFixed(bool multiple)
+{
+	const int channels = 2;
+	AudioFormat f = createAudioFormat(channels);
+
+	SharedPtr<RebufferModule> rebuffer =
+		new RebufferModule(RebufferModule::VariableToFixed, f.bytesPerFrame(),
+			10, multiple);
+	SharedPtr<TestSinkModule> sink = new TestSinkModule();
+	rebuffer->setSink(sink.get());
+
+	SharedPtr<Chunk> variableChunk(new Chunk());
+	SharedPtr<Chunk> fixedChunk(new Chunk());
+
+	const int maxFrameCount = 40;
+	variableChunk->f = f;
+	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	fixedChunk->f = f;
+	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());
+
+	rebuffer->setInChunk(variableChunk.get());
+	rebuffer->setOutChunk(fixedChunk.get());
+
+	sink->setInChunk(fixedChunk.get());
+
+	// Push 23 frames to the rebuffer module.
+	variableChunk->frameCount = 23;
+	setChunkData(*variableChunk, 0);
+	sink->setExpectedRequestLength(multiple ? 20 : 10);
+	rebuffer->runPush();
+	// Check that 20 frames have been pushed to the sink module.
+	EXPECT_EQ(sink->startFrame(), 20u);
+	// Check that the last push contained 20 (multiple) or 10 (single) frames.
+	EXPECT_EQ(fixedChunk->frameCount, multiple ? 20u : 10u);
+
+	// Push another 37 frames to the rebuffer module.
+	variableChunk->frameCount = 37;
+	setChunkData(*variableChunk, 23);
+	sink->setExpectedRequestLength(multiple ? 40 : 10);
+	rebuffer->runPush();
+	// Check that 60 frames have been pushed to the sink module.
+	EXPECT_EQ(sink->startFrame(), 60u);
+	// Check that the last push contained 40 (multiple) or 10 (single) frames.
+	EXPECT_EQ(fixedChunk->frameCount, multiple ? 40u : 10u);
+}
+
+TEST(RebufferModule, VariableToFixed)
+{
+	testVariableToFixed(false);
+}
+
+TEST(RebufferModule, VariableToFixed_Multiple)
+{
+	testVariableToFixed(true);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/libaudiofile/openclose.cpp b/libaudiofile/openclose.cpp
new file mode 100644
index 0000000..eef7b68
--- /dev/null
+++ b/libaudiofile/openclose.cpp
@@ -0,0 +1,462 @@
+/*
+	Audio File Library
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <audiofile.h>
+
+#include "File.h"
+#include "FileHandle.h"
+#include "Instrument.h"
+#include "Marker.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "modules/Module.h"
+#include "modules/ModuleState.h"
+#include "units.h"
+#include "util.h"
+
+static status _afOpenFile (int access, File *f, const char *filename,
+	AFfilehandle *file, AFfilesetup filesetup);
+
+int _af_identify (File *f, int *implemented)
+{
+	if (!f->canSeek())
+	{
+		_af_error(AF_BAD_LSEEK, "Cannot seek in file");
+		return AF_FILE_UNKNOWN;
+	}
+
+	AFfileoffset curpos = f->tell();
+
+	for (int i=0; i<_AF_NUM_UNITS; i++)
+	{
+		if (_af_units[i].recognize &&
+			_af_units[i].recognize(f))
+		{
+			if (implemented != NULL)
+				*implemented = _af_units[i].implemented;
+			f->seek(curpos, File::SeekFromBeginning);
+			return _af_units[i].fileFormat;
+		}
+	}
+
+	f->seek(curpos, File::SeekFromBeginning);
+
+	if (implemented != NULL)
+		*implemented = false;
+
+	return AF_FILE_UNKNOWN;
+}
+
+int afIdentifyFD (int fd)
+{
+	/*
+		Duplicate the file descriptor since otherwise the
+		original file descriptor would get closed when we close
+		the virtual file below.
+	*/
+	fd = dup(fd);
+	File *f = File::create(fd, File::ReadAccess);
+
+	int result = _af_identify(f, NULL);
+
+	delete f;
+
+	return result;
+}
+
+int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
+{
+	/*
+		Duplicate the file descriptor since otherwise the
+		original file descriptor would get closed when we close
+		the virtual file below.
+	*/
+	fd = dup(fd);
+
+	File *f = File::create(fd, File::ReadAccess);
+	if (!f)
+	{
+		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+		return AF_FILE_UNKNOWN;
+	}
+
+	int result = _af_identify(f, implemented);
+
+	delete f;
+
+	return result;
+}
+
+AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
+{
+	if (!mode)
+	{
+		_af_error(AF_BAD_ACCMODE, "null access mode");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	int access;
+	if (mode[0] == 'r')
+	{
+		access = _AF_READ_ACCESS;
+	}
+	else if (mode[0] == 'w')
+	{
+		access = _AF_WRITE_ACCESS;
+	}
+	else
+	{
+		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+		return AF_NULL_FILEHANDLE;
+	}
+
+	File *f = File::create(fd, access == _AF_READ_ACCESS ?
+		File::ReadAccess : File::WriteAccess);
+
+	AFfilehandle filehandle = NULL;
+	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
+	{
+		delete f;
+	}
+
+	return filehandle;
+}
+
+AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
+	const char *filename)
+{
+	if (!mode)
+	{
+		_af_error(AF_BAD_ACCMODE, "null access mode");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	int access;
+	if (mode[0] == 'r')
+		access = _AF_READ_ACCESS;
+	else if (mode[0] == 'w')
+		access = _AF_WRITE_ACCESS;
+	else
+	{
+		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+		return AF_NULL_FILEHANDLE;
+	}
+
+	File *f = File::create(fd, access == _AF_READ_ACCESS ?
+		File::ReadAccess : File::WriteAccess);
+
+	AFfilehandle filehandle;
+	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
+	{
+		delete f;
+	}
+
+	return filehandle;
+}
+
+AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
+{
+	if (!mode)
+	{
+		_af_error(AF_BAD_ACCMODE, "null access mode");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	int access;
+	if (mode[0] == 'r')
+	{
+		access = _AF_READ_ACCESS;
+	}
+	else if (mode[0] == 'w')
+	{
+		access = _AF_WRITE_ACCESS;
+	}
+	else
+	{
+		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+		return AF_NULL_FILEHANDLE;
+	}
+
+	File *f = File::open(filename,
+		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
+	if (!f)
+	{
+		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+		return AF_NULL_FILEHANDLE;
+	}
+
+	AFfilehandle filehandle;
+	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
+	{
+		delete f;
+	}
+
+	return filehandle;
+}
+
+AFfilehandle afOpenVirtualFile (AFvirtualfile *vf, const char *mode,
+	AFfilesetup setup)
+{
+	if (!vf)
+	{
+		_af_error(AF_BAD_OPEN, "null virtual file");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	if (!mode)
+	{
+		_af_error(AF_BAD_ACCMODE, "null access mode");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	int access;
+	if (mode[0] == 'r')
+	{
+		access = _AF_READ_ACCESS;
+	}
+	else if (mode[0] == 'w')
+	{
+		access = _AF_WRITE_ACCESS;
+	}
+	else
+	{
+		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+		return AF_NULL_FILEHANDLE;
+	}
+
+	File *f = File::create(vf,
+		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
+	if (!f)
+	{
+		_af_error(AF_BAD_OPEN, "could not open virtual file");
+		return AF_NULL_FILEHANDLE;
+	}
+
+	AFfilehandle filehandle;
+	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
+	{
+		delete f;
+	}
+
+	return filehandle;
+}
+
+static status _afOpenFile (int access, File *f, const char *filename,
+	AFfilehandle *file, AFfilesetup filesetup)
+{
+	int	fileFormat = AF_FILE_UNKNOWN;
+	int	implemented = true;
+
+	int		userSampleFormat = 0;
+	double		userSampleRate = 0.0;
+	PCMInfo	userPCM = {0};
+	bool		userFormatSet = false;
+
+	AFfilehandle	filehandle = AF_NULL_FILEHANDLE;
+	AFfilesetup	completesetup = AF_NULL_FILESETUP;
+
+	*file = AF_NULL_FILEHANDLE;
+
+	if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
+	{
+		if (!_af_filesetup_ok(filesetup))
+			return AF_FAIL;
+
+		fileFormat = filesetup->fileFormat;
+		if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
+		{
+			_af_error(AF_BAD_FILESETUP,
+				"warning: opening file for read access: "
+				"ignoring file setup with non-raw file format");
+			filesetup = AF_NULL_FILESETUP;
+			fileFormat = _af_identify(f, &implemented);
+		}
+	}
+	else if (filesetup == AF_NULL_FILESETUP)
+		fileFormat = _af_identify(f, &implemented);
+
+	if (fileFormat == AF_FILE_UNKNOWN)
+	{
+		if (filename != NULL)
+			_af_error(AF_BAD_NOT_IMPLEMENTED,
+				"'%s': unrecognized audio file format",
+				filename);
+		else
+			_af_error(AF_BAD_NOT_IMPLEMENTED,
+				"unrecognized audio file format");
+		return AF_FAIL;
+	}
+
+	const char *formatName = _af_units[fileFormat].name;
+
+	if (!implemented)
+	{
+		_af_error(AF_BAD_NOT_IMPLEMENTED,
+			"%s format not currently supported", formatName);
+	}
+
+	completesetup = NULL;
+	if (filesetup != AF_NULL_FILESETUP)
+	{
+		userSampleFormat = filesetup->tracks[0].f.sampleFormat;
+		userPCM = filesetup->tracks[0].f.pcm;
+		userSampleRate = filesetup->tracks[0].f.sampleRate;
+		userFormatSet = true;
+		if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
+			return AF_FAIL;
+	}
+
+	filehandle = _AFfilehandle::create(fileFormat);
+	if (!filehandle)
+	{
+		if (completesetup)
+			afFreeFileSetup(completesetup);
+		return AF_FAIL;
+	}
+
+	filehandle->m_fh = f;
+	filehandle->m_access = access;
+	filehandle->m_seekok = f->canSeek();
+	if (filename != NULL)
+		filehandle->m_fileName = strdup(filename);
+	else
+		filehandle->m_fileName = NULL;
+	filehandle->m_fileFormat = fileFormat;
+
+	status result = access == _AF_READ_ACCESS ?
+		filehandle->readInit(completesetup) :
+		filehandle->writeInit(completesetup);
+
+	if (result != AF_SUCCEED)
+	{
+		delete filehandle;
+		filehandle = AF_NULL_FILEHANDLE;
+		if (completesetup)
+			afFreeFileSetup(completesetup);
+		return AF_FAIL;
+	}
+
+	if (completesetup)
+		afFreeFileSetup(completesetup);
+
+	/*
+		Initialize virtual format.
+	*/
+	for (int t=0; t<filehandle->m_trackCount; t++)
+	{
+		Track *track = &filehandle->m_tracks[t];
+
+		track->v = track->f;
+
+		if (userFormatSet)
+		{
+			track->v.sampleFormat = userSampleFormat;
+			track->v.pcm = userPCM;
+			track->v.sampleRate = userSampleRate;
+		}
+
+		track->v.compressionType = AF_COMPRESSION_NONE;
+		track->v.compressionParams = NULL;
+
+#if WORDS_BIGENDIAN
+		track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
+#else
+		track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+#endif
+
+		track->ms = new ModuleState();
+		if (track->ms->init(filehandle, track) == AF_FAIL)
+		{
+			delete filehandle;
+			return AF_FAIL;
+		}
+	}
+
+	*file = filehandle;
+
+	return AF_SUCCEED;
+}
+
+int afSyncFile (AFfilehandle handle)
+{
+	if (!_af_filehandle_ok(handle))
+		return -1;
+
+	if (handle->m_access == _AF_WRITE_ACCESS)
+	{
+		/* Finish writes on all tracks. */
+		for (int trackno = 0; trackno < handle->m_trackCount; trackno++)
+		{
+			Track *track = &handle->m_tracks[trackno];
+
+			if (track->ms->isDirty() && track->ms->setup(handle, track) == AF_FAIL)
+				return -1;
+
+			if (track->ms->sync(handle, track) != AF_SUCCEED)
+				return -1;
+		}
+
+		/* Update file headers. */
+		if (handle->update() != AF_SUCCEED)
+			return AF_FAIL;
+	}
+	else if (handle->m_access == _AF_READ_ACCESS)
+	{
+		/* Do nothing. */
+	}
+	else
+	{
+		_af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
+			handle->m_access);
+		return AF_FAIL;
+	}
+
+	return AF_SUCCEED;
+}
+
+int afCloseFile (AFfilehandle file)
+{
+	int	err;
+
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	afSyncFile(file);
+
+	err = file->m_fh->close();
+	if (err < 0)
+		_af_error(AF_BAD_CLOSE, "close returned %d", err);
+
+	delete file->m_fh;
+	delete file;
+
+	return 0;
+}
diff --git a/libaudiofile/pcm.cpp b/libaudiofile/pcm.cpp
new file mode 100644
index 0000000..ddca196
--- /dev/null
+++ b/libaudiofile/pcm.cpp
@@ -0,0 +1,172 @@
+/*
+	Audio File Library
+	Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	pcm.cpp
+
+	This file declares default PCM mappings and defines routines
+	for accessing and modifying PCM mappings in a track.
+*/
+
+#include "config.h"
+
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "modules/Module.h"
+#include "modules/ModuleState.h"
+#include "pcm.h"
+#include "util.h"
+
+extern const PCMInfo _af_default_signed_integer_pcm_mappings[] =
+{
+	{0, 0, 0, 0},
+	{SLOPE_INT8, 0, MIN_INT8, MAX_INT8},
+	{SLOPE_INT16, 0, MIN_INT16, MAX_INT16},
+	{SLOPE_INT24, 0, MIN_INT24, MAX_INT24},
+	{SLOPE_INT32, 0, MIN_INT32, MAX_INT32}
+};
+
+extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[] =
+{
+	{0, 0, 0, 0},
+	{SLOPE_INT8, INTERCEPT_U_INT8, 0, MAX_U_INT8},
+	{SLOPE_INT16, INTERCEPT_U_INT16, 0, MAX_U_INT16},
+	{SLOPE_INT24, INTERCEPT_U_INT24, 0, MAX_U_INT24},
+	{SLOPE_INT32, INTERCEPT_U_INT32, 0, MAX_U_INT32}
+};
+
+extern const PCMInfo _af_default_float_pcm_mapping =
+{1, 0, 0, 0};
+
+extern const PCMInfo _af_default_double_pcm_mapping =
+{1, 0, 0, 0};
+
+/*
+	Initialize the PCM mapping for a given track.
+*/
+void afInitPCMMapping (AFfilesetup setup, int trackid,
+	double slope, double intercept, double minClip, double maxClip)
+{
+	if (!_af_filesetup_ok(setup))
+		return;
+
+	TrackSetup *track = setup->getTrack(trackid);
+	if (!track)
+		return;
+
+	track->f.pcm.slope = slope;
+	track->f.pcm.intercept = intercept;
+	track->f.pcm.minClip = minClip;
+	track->f.pcm.maxClip = maxClip;
+}
+
+int afSetVirtualPCMMapping (AFfilehandle file, int trackid,
+	double slope, double intercept, double minClip, double maxClip)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	track->v.pcm.slope = slope;
+	track->v.pcm.intercept = intercept;
+	track->v.pcm.minClip = minClip;
+	track->v.pcm.maxClip = maxClip;
+
+	track->ms->setDirty();
+
+	return 0;
+}
+
+int afSetTrackPCMMapping (AFfilehandle file, int trackid,
+	double slope, double intercept, double minClip, double maxClip)
+{
+	if (!_af_filehandle_ok(file))
+		return -1;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return -1;
+
+	/*
+		NOTE: this is highly unusual: we don't ordinarily
+		change track.f after the file is opened.
+
+		PCM mapping is the exception because this information
+		is not encoded in sound files' headers using today's
+		formats, so the user will probably want to set this
+		information on a regular basis.  The defaults may or
+		may not be what the user wants.
+	*/
+
+	track->f.pcm.slope = slope;
+	track->f.pcm.intercept = intercept;
+	track->f.pcm.minClip = minClip;
+	track->f.pcm.maxClip = maxClip;
+
+	track->ms->setDirty();
+
+	return 0;
+}
+
+void afGetPCMMapping (AFfilehandle file, int trackid,
+	double *slope, double *intercept, double *minClip, double *maxClip)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (slope)
+		*slope = track->f.pcm.slope;
+	if (intercept)
+		*intercept = track->f.pcm.intercept;
+	if (minClip)
+		*minClip = track->f.pcm.minClip;
+	if (maxClip)
+		*maxClip = track->f.pcm.maxClip;
+}
+
+void afGetVirtualPCMMapping (AFfilehandle file, int trackid,
+	double *slope, double *intercept, double *minClip, double *maxClip)
+{
+	if (!_af_filehandle_ok(file))
+		return;
+
+	Track *track = file->getTrack(trackid);
+	if (!track)
+		return;
+
+	if (slope)
+		*slope = track->v.pcm.slope;
+	if (intercept)
+		*intercept = track->v.pcm.intercept;
+	if (minClip)
+		*minClip = track->v.pcm.minClip;
+	if (maxClip)
+		*maxClip = track->v.pcm.maxClip;
+}
diff --git a/libaudiofile/pcm.h b/libaudiofile/pcm.h
new file mode 100644
index 0000000..83c9640
--- /dev/null
+++ b/libaudiofile/pcm.h
@@ -0,0 +1,75 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	pcm.h
+
+	This file defines various constants for PCM mapping.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+/*
+	SLOPE_INTN = 2^(N-1)
+*/
+#define SLOPE_INT8 (128.0)
+#define SLOPE_INT16 (32768.0)
+#define SLOPE_INT24 (8388608.0)
+#define SLOPE_INT32 (2147483648.0)
+
+/*
+	INTERCEPT_U_INTN = 2^(N-1)
+*/
+#define INTERCEPT_U_INT8 (128.0)
+#define INTERCEPT_U_INT16 (32768.0)
+#define INTERCEPT_U_INT24 (8388608.0)
+#define INTERCEPT_U_INT32 (2147483648.0)
+
+/*
+	MIN_INTN = -(2^(N-1))
+*/
+#define MIN_INT8 (-128.0)
+#define MIN_INT16 (-32768.0)
+#define MIN_INT24 (-8388608.0)
+#define MIN_INT32 (-2147483648.0)
+
+/*
+	MAX_INTN = 2^(N-1) - 1
+*/
+#define MAX_INT8 127.0
+#define MAX_INT16 32767.0
+#define MAX_INT24 8388607.0
+#define MAX_INT32 2147483647.0
+
+/*
+	MAX_U_INTN = 2^N - 1
+*/
+#define MAX_U_INT8 255.0
+#define MAX_U_INT16 65535.0
+#define MAX_U_INT24 16777215.0
+#define MAX_U_INT32 4294967295.0
+
+extern const PCMInfo _af_default_signed_integer_pcm_mappings[];
+extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[];
+extern const PCMInfo _af_default_float_pcm_mapping;
+extern const PCMInfo _af_default_double_pcm_mapping;
+
+#endif
diff --git a/libaudiofile/query.cpp b/libaudiofile/query.cpp
new file mode 100644
index 0000000..5d69386
--- /dev/null
+++ b/libaudiofile/query.cpp
@@ -0,0 +1,482 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	query.cpp
+
+	This file contains the implementation of the Audio File Library's
+	query mechanism.  Querying through the afQuery calls can allow the
+	programmer to determine the capabilities and characteristics of
+	the Audio File Library implementation and its supported formats.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "aupvlist.h"
+#include "error.h"
+#include "util.h"
+#include "units.h"
+#include "compression.h"
+#include "Instrument.h"
+
+AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryCompressionParameter (int arg1, int arg2, int arg3, int arg4);
+
+AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+	switch (querytype)
+	{
+		case AF_QUERYTYPE_INST:
+			return _afQueryInstrument(arg1, arg2, arg3, arg4);
+		case AF_QUERYTYPE_INSTPARAM:
+			return _afQueryInstrumentParameter(arg1, arg2, arg3, arg4);
+		case AF_QUERYTYPE_LOOP:
+			return _afQueryLoop(arg1, arg2, arg3, arg4);
+		case AF_QUERYTYPE_FILEFMT:
+			return _afQueryFileFormat(arg1, arg2, arg3, arg4);
+		case AF_QUERYTYPE_COMPRESSION:
+			return _afQueryCompression(arg1, arg2, arg3, arg4);
+		case AF_QUERYTYPE_COMPRESSIONPARAM:
+			/* FIXME: This selector is not implemented. */
+			return AU_NULL_PVLIST;
+		case AF_QUERYTYPE_MISC:
+			/* FIXME: This selector is not implemented. */
+			return AU_NULL_PVLIST;
+		case AF_QUERYTYPE_MARK:
+			return _afQueryMarker(arg1, arg2, arg3, arg4);
+	}
+
+	_af_error(AF_BAD_QUERYTYPE, "bad query type");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED3 */
+AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4)
+{
+	switch (arg1)
+	{
+		/* The following select only on arg1. */
+		case AF_QUERY_ID_COUNT:
+		{
+			int	count = 0, idx;
+			for (idx = 0; idx < _AF_NUM_UNITS; idx++)
+				if (_af_units[idx].implemented)
+					count++;
+			return _af_pv_long(count);
+		}
+		/* NOTREACHED */
+		break;
+
+		case AF_QUERY_IDS:
+		{
+			int	count = 0, idx;
+			int	*buffer;
+
+			buffer = (int *) _af_calloc(_AF_NUM_UNITS, sizeof (int));
+			if (buffer == NULL)
+				return AU_NULL_PVLIST;
+
+			for (idx = 0; idx < _AF_NUM_UNITS; idx++)
+				if (_af_units[idx].implemented)
+					buffer[count++] = idx;
+
+			if (count == 0)
+			{
+				free(buffer);
+				return AU_NULL_PVLIST;
+			}
+
+			return _af_pv_pointer(buffer);
+		}
+		/* NOTREACHED */
+		break;
+
+		/* The following select on arg2. */
+		case AF_QUERY_LABEL:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].label));
+
+		case AF_QUERY_NAME:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].name));
+
+		case AF_QUERY_DESC:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].description));
+
+		case AF_QUERY_IMPLEMENTED:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return _af_pv_long(0);
+			return _af_pv_long(_af_units[arg2].implemented);
+
+		/* The following select on arg3. */
+		case AF_QUERY_SAMPLE_FORMATS:
+			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			switch (arg2)
+			{
+				case AF_QUERY_DEFAULT:
+					return _af_pv_long(_af_units[arg3].defaultSampleFormat);
+				default:
+					break;
+			}
+			/* NOTREACHED */
+			break;
+
+		case AF_QUERY_SAMPLE_SIZES:
+			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+
+			switch (arg2)
+			{
+				case AF_QUERY_DEFAULT:
+					return _af_pv_long(_af_units[arg3].defaultSampleWidth);
+				default:
+					break;
+			}
+			/* NOTREACHED */
+			break;
+
+		case AF_QUERY_COMPRESSION_TYPES:
+		{
+			int	idx, count;
+			int	*buffer;
+
+			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+			{
+				_af_error(AF_BAD_QUERY,
+					"unrecognized file format %d", arg3);
+				return AU_NULL_PVLIST;
+			}
+
+			switch (arg2)
+			{
+				case AF_QUERY_VALUE_COUNT:
+					count = _af_units[arg3].compressionTypeCount;
+					return _af_pv_long(count);
+
+				case AF_QUERY_VALUES:
+					count = _af_units[arg3].compressionTypeCount;
+					if (count == 0)
+						return AU_NULL_PVLIST;
+
+					buffer = (int *) _af_calloc(count, sizeof (int));
+					if (buffer == NULL)
+						return AU_NULL_PVLIST;
+
+					for (idx = 0; idx < count; idx++)
+					{
+						buffer[idx] = _af_units[arg3].compressionTypes[idx];
+					}
+
+					return _af_pv_pointer(buffer);
+			}
+		}
+		break;
+	}
+
+	_af_error(AF_BAD_QUERY, "bad query selector");
+	return AU_NULL_PVLIST;
+}
+
+long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+	AUpvlist	list;
+	int		type;
+	long		value;
+
+	list = afQuery(querytype, arg1, arg2, arg3, arg4);
+	if (list == AU_NULL_PVLIST)
+		return -1;
+	AUpvgetvaltype(list, 0, &type);
+	if (type != AU_PVTYPE_LONG)
+		return -1;
+	AUpvgetval(list, 0, &value);
+	AUpvfree(list);
+	return value;
+}
+
+double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+	AUpvlist	list;
+	int		type;
+	double		value;
+
+	list = afQuery(querytype, arg1, arg2, arg3, arg4);
+	if (list == AU_NULL_PVLIST)
+		return -1;
+	AUpvgetvaltype(list, 0, &type);
+	if (type != AU_PVTYPE_DOUBLE)
+		return -1;
+	AUpvgetval(list, 0, &value);
+	AUpvfree(list);
+	return value;
+}
+
+void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+	AUpvlist	list;
+	int		type;
+	void		*value;
+
+	list = afQuery(querytype, arg1, arg2, arg3, arg4);
+	if (list == AU_NULL_PVLIST)
+		return NULL;
+	AUpvgetvaltype(list, 0, &type);
+	if (type != AU_PVTYPE_PTR)
+		return NULL;
+	AUpvgetval(list, 0, &value);
+	AUpvfree(list);
+	return value;
+}
+
+/* ARGSUSED3 */
+AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4)
+{
+	switch (arg1)
+	{
+		/* For the following query types, arg2 is the file format. */
+		case AF_QUERY_SUPPORTED:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(_af_units[arg2].instrumentParameterCount != 0);
+
+		case AF_QUERY_ID_COUNT:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(_af_units[arg2].instrumentParameterCount);
+
+		case AF_QUERY_IDS:
+		{
+			int	count;
+			int	*buffer;
+
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			count = _af_units[arg2].instrumentParameterCount;
+			if (count == 0)
+				return AU_NULL_PVLIST;
+			buffer = (int *) _af_calloc(count, sizeof (int));
+			if (buffer == NULL)
+				return AU_NULL_PVLIST;
+			for (int i=0; i<count; i++)
+				buffer[i] = _af_units[arg2].instrumentParameters[i].id;
+			return _af_pv_pointer(buffer);
+		}
+		/* NOTREACHED */
+		break;
+
+		/*
+			For the next few query types, arg2 is the file
+			format and arg3 is the instrument parameter id.
+		*/
+		case AF_QUERY_TYPE:
+		{
+			int	idx;
+
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+
+			idx = _af_instparam_index_from_id(arg2, arg3);
+			if (idx<0)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(_af_units[arg2].instrumentParameters[idx].type);
+		}
+
+		case AF_QUERY_NAME:
+		{
+			int	idx;
+
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			idx = _af_instparam_index_from_id(arg2, arg3);
+			if (idx < 0)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].instrumentParameters[idx].name));
+		}
+
+		case AF_QUERY_DEFAULT:
+		{
+			int	idx;
+
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			idx = _af_instparam_index_from_id(arg2, arg3);
+			if (idx >= 0)
+			{
+				AUpvlist	ret = AUpvnew(1);
+				AUpvsetparam(ret, 0, _af_units[arg2].instrumentParameters[idx].id);
+				AUpvsetvaltype(ret, 0, _af_units[arg2].instrumentParameters[idx].type);
+				AUpvsetval(ret, 0, const_cast<AFPVu *>(&_af_units[arg2].instrumentParameters[idx].defaultValue));
+				return ret;
+			}
+			return AU_NULL_PVLIST;
+		}
+	}
+
+	_af_error(AF_BAD_QUERY, "bad query selector");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4)
+{
+	if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+		return AU_NULL_PVLIST;
+
+	switch (arg1)
+	{
+		case AF_QUERY_SUPPORTED:
+			return _af_pv_long(_af_units[arg2].loopPerInstrumentCount != 0);
+		case AF_QUERY_MAX_NUMBER:
+			return _af_pv_long(_af_units[arg2].loopPerInstrumentCount);
+	}
+
+	_af_error(AF_BAD_QUERY, "bad query selector");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4)
+{
+	switch (arg1)
+	{
+		case AF_QUERY_SUPPORTED:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(_af_units[arg2].instrumentCount != 0);
+
+		case AF_QUERY_MAX_NUMBER:
+			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(_af_units[arg2].instrumentCount);
+	}
+
+	_af_error(AF_BAD_QUERY, "bad query selector");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED0 */
+AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4)
+{
+	_af_error(AF_BAD_NOT_IMPLEMENTED, "not implemented yet");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4)
+{
+	switch (arg1)
+	{
+		case AF_QUERY_SUPPORTED:
+			return _af_pv_long(_af_units[arg2].markerCount != 0);
+		case AF_QUERY_MAX_NUMBER:
+			return _af_pv_long(_af_units[arg2].markerCount);
+	}
+
+	_af_error(AF_BAD_QUERY, "bad query selector");
+	return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED0 */
+AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4)
+{
+	const CompressionUnit *unit = NULL;
+
+	switch (arg1)
+	{
+		case AF_QUERY_ID_COUNT:
+		{
+			int count = 0;
+			for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
+				if (_af_compression[i].implemented)
+					count++;
+			return _af_pv_long(count);
+		}
+
+		case AF_QUERY_IDS:
+		{
+			int *buf = (int *) _af_calloc(_AF_NUM_COMPRESSION, sizeof (int));
+			if (!buf)
+				return AU_NULL_PVLIST;
+
+			int count = 0;
+			for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
+			{
+				if (_af_compression[i].implemented)
+					buf[count++] = _af_compression[i].compressionID;
+			}
+			return _af_pv_pointer(buf);
+		}
+
+		case AF_QUERY_IMPLEMENTED:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return _af_pv_long(0);
+			return _af_pv_long(unit->implemented);
+
+		case AF_QUERY_NATIVE_SAMPFMT:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(unit->nativeSampleFormat);
+
+		case AF_QUERY_NATIVE_SAMPWIDTH:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return AU_NULL_PVLIST;
+			return _af_pv_long(unit->nativeSampleWidth);
+
+		case AF_QUERY_LABEL:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(unit->label));
+
+		case AF_QUERY_NAME:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(unit->shortname));
+
+		case AF_QUERY_DESC:
+			unit = _af_compression_unit_from_id(arg2);
+			if (!unit)
+				return AU_NULL_PVLIST;
+			return _af_pv_pointer(const_cast<char *>(unit->name));
+	}
+
+	_af_error(AF_BAD_QUERY, "unrecognized query selector %d\n", arg1);
+	return AU_NULL_PVLIST;
+}
diff --git a/libaudiofile/units.cpp b/libaudiofile/units.cpp
new file mode 100644
index 0000000..ffd0a63
--- /dev/null
+++ b/libaudiofile/units.cpp
@@ -0,0 +1,368 @@
+/*
+	Audio File Library
+	Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	units.cpp
+
+	This file contains the file format units.
+*/
+
+#include "config.h"
+
+#include "Features.h"
+#include "audiofile.h"
+#include "afinternal.h"
+#include "units.h"
+
+#include "AIFF.h"
+#include "AVR.h"
+#include "CAF.h"
+#include "FLACFile.h"
+#include "IFF.h"
+#include "IRCAM.h"
+#include "NeXT.h"
+#include "NIST.h"
+#include "Raw.h"
+#include "SampleVision.h"
+#include "VOC.h"
+#include "WAVE.h"
+
+#include "compression.h"
+
+#include "modules/ALAC.h"
+#include "modules/FLAC.h"
+#include "modules/G711.h"
+#include "modules/IMA.h"
+#include "modules/MSADPCM.h"
+#include "modules/PCM.h"
+
+const Unit _af_units[_AF_NUM_UNITS] =
+{
+	{
+		AF_FILE_RAWDATA,
+		"Raw Data", "Raw Sound Data", "raw",
+		true,
+		&RawFile::completeSetup,
+		&RawFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_RAW_NUM_COMPTYPES,
+		_af_raw_compression_types,
+		0,	/* maximum marker count */
+		0,	/* maximum instrument count */
+		0,	/* maxium number of loops per instrument */
+		0, NULL,
+	},
+	{
+		AF_FILE_AIFFC,
+		"AIFF-C", "AIFF-C File Format", "aifc",
+		true,
+		AIFFFile::completeSetup,
+		AIFFFile::recognizeAIFFC,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_AIFFC_NUM_COMPTYPES,
+		_af_aiffc_compression_types,
+		65535,	/* maximum marker count */
+		1,	/* maximum instrument count */
+		2,	/* maximum number of loops per instrument */
+		_AF_AIFF_NUM_INSTPARAMS,
+		_af_aiff_inst_params
+	},
+	{
+		AF_FILE_AIFF,
+		"AIFF", "Audio Interchange File Format", "aiff",
+		true,
+		AIFFFile::completeSetup,
+		AIFFFile::recognizeAIFF,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		0,	/* supported compression types */
+		NULL,
+		65535,	/* maximum marker count */
+		1,	/* maximum instrument count */
+		2,	/* maximum number of loops per instrument */
+		_AF_AIFF_NUM_INSTPARAMS,
+		_af_aiff_inst_params
+	},
+	{
+		AF_FILE_NEXTSND,
+		"NeXT .snd/Sun .au", "NeXT .snd/Sun .au Format", "next",
+		true,
+		NeXTFile::completeSetup,
+		NeXTFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_NEXT_NUM_COMPTYPES,
+		_af_next_compression_types,
+		0,	/* maximum marker count */
+		0,	/* maximum instrument count */
+		0,	/* maximum number of loops per instrument */
+		0, NULL
+	},
+	{
+		AF_FILE_WAVE,
+		"MS RIFF WAVE", "Microsoft RIFF WAVE Format", "wave",
+		true,
+		WAVEFile::completeSetup,
+		WAVEFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_WAVE_NUM_COMPTYPES,
+		_af_wave_compression_types,
+		AF_NUM_UNLIMITED,	/* maximum marker count */
+		1,			/* maximum instrument count */
+		AF_NUM_UNLIMITED,	/* maximum number of loops per instrument */
+		_AF_WAVE_NUM_INSTPARAMS,
+		_af_wave_inst_params
+	},
+	{
+		AF_FILE_IRCAM,
+		"BICSF", "Berkeley/IRCAM/CARL Sound Format", "bicsf",
+		true,
+		IRCAMFile::completeSetup,
+		IRCAMFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_IRCAM_NUM_COMPTYPES,
+		_af_ircam_compression_types,
+		0,		// maximum marker count
+		0,		// maximum instrument count
+		0,		// maximum number of loops per instrument
+		0,		// number of instrument parameters
+		NULL	// instrument parameters
+	},
+	{
+		AF_FILE_MPEG1BITSTREAM,
+		"MPEG", "MPEG Audio Bitstream", "mpeg",
+		false
+	},
+	{
+		AF_FILE_SOUNDDESIGNER1,
+		"Sound Designer 1", "Sound Designer 1 File Format", "sd1",
+		false
+	},
+	{
+		AF_FILE_SOUNDDESIGNER2,
+		"Sound Designer 2", "Sound Designer 2 File Format", "sd2",
+		false
+	},
+	{
+		AF_FILE_AVR,
+		"AVR", "Audio Visual Research File Format", "avr",
+		true,
+		AVRFile::completeSetup,
+		AVRFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		0,	/* number of compression types */
+		NULL,	/* compression types */
+		0,	/* maximum marker count */
+		0,	/* maximum instrument count */
+		0,	/* maximum number of loops per instrument */
+		0,	/* number of instrument parameters */
+	},
+	{
+		AF_FILE_IFF_8SVX,
+		"IFF/8SVX", "Amiga IFF/8SVX Sound File Format", "iff",
+		true,
+		IFFFile::completeSetup,
+		IFFFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 8,
+		0,	/* number of compression types */
+		NULL,	/* compression types */
+		0,	/* maximum marker count */
+		0,	/* maximum instrument count */
+		0,	/* maximum number of loops per instrument */
+		0,	/* number of instrument parameters */
+	},
+	{
+		AF_FILE_SAMPLEVISION,
+		"Sample Vision", "Sample Vision File Format", "smp",
+		true,
+		SampleVisionFile::completeSetup,
+		SampleVisionFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		0,		// number of compression types
+		NULL,	// compression types
+		0,		// maximum marker count
+		0,		// maximum instrument count
+		0,		// maximum number of loops per instrument
+		0,		// number of instrument parameters
+		NULL	// instrument parameters
+	},
+	{
+		AF_FILE_VOC,
+		"VOC", "Creative Voice File Format", "voc",
+		true,
+		VOCFile::completeSetup,
+		VOCFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_VOC_NUM_COMPTYPES,
+		_af_voc_compression_types,
+		0,		// maximum marker count
+		0,		// maximum instrument count
+		0,		// maximum number of loops per instrument
+		0,		// number of instrument parameters
+		NULL	// instrument parameters
+	},
+	{
+		AF_FILE_NIST_SPHERE,
+		"NIST SPHERE", "NIST SPHERE File Format", "nist",
+		true,
+		NISTFile::completeSetup,
+		NISTFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		0,	/* number of compression types */
+		NULL,	/* compression types */
+		0,	/* maximum marker count */
+		0,	/* maximum instrument count */
+		0,	/* maximum number of loops per instrument */
+		0,	/* number of instrument parameters */
+		NULL	/* instrument parameters */
+	},
+	{
+		AF_FILE_SOUNDFONT2,
+		"SoundFont 2", "SoundFont 2 File Format", "sf2",
+		false
+	},
+	{
+		AF_FILE_CAF,
+		"CAF", "Core Audio Format", "caf",
+		true,
+		CAFFile::completeSetup,
+		CAFFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_CAF_NUM_COMPTYPES,
+		_af_caf_compression_types,
+		0,		// maximum marker count
+		0,		// maximum instrument count
+		0,		// maximum number of loops per instrument
+		0,		// number of instrument parameters
+		NULL	// instrument parameters
+	},
+	{
+		AF_FILE_FLAC,
+		"FLAC", "Free Lossless Audio Codec", "flac",
+		true,
+		FLACFile::completeSetup,
+		FLACFile::recognize,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		_AF_FLAC_NUM_COMPTYPES,
+		_af_flac_compression_types,
+		0,		// maximum marker count
+		0,		// maximum instrument count
+		0,		// maximum number of loops per instrument
+		0,		// number of instrument parameters
+		NULL	// instrument parameters
+	}
+};
+
+const CompressionUnit _af_compression[_AF_NUM_COMPRESSION] =
+{
+	{
+		AF_COMPRESSION_NONE,
+		true,
+		"none",	/* label */
+		"none",	/* short name */
+		"not compressed",
+		1.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		false,	/* needsRebuffer */
+		false,	/* multiple_of */
+		_af_pcm_format_ok,
+		_AFpcminitcompress, _AFpcminitdecompress
+	},
+	{
+		AF_COMPRESSION_G711_ULAW,
+		true,
+		"ulaw",	/* label */
+		"CCITT G.711 u-law",	/* shortname */
+		"CCITT G.711 u-law",
+		2.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		false,	/* needsRebuffer */
+		false,	/* multiple_of */
+		_af_g711_format_ok,
+		_AFg711initcompress, _AFg711initdecompress
+	},
+	{
+		AF_COMPRESSION_G711_ALAW,
+		true,
+		"alaw",	/* label */
+		"CCITT G.711 A-law",	/* short name */
+		"CCITT G.711 A-law",
+		2.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		false,	/* needsRebuffer */
+		false,	/* multiple_of */
+		_af_g711_format_ok,
+		_AFg711initcompress, _AFg711initdecompress
+	},
+	{
+		AF_COMPRESSION_IMA,
+		true,
+		"ima4",	/* label */
+		"IMA ADPCM",	/* short name */
+		"IMA DVI ADPCM",
+		4.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		true,	/* needsRebuffer */
+		false,	/* multiple_of */
+		_af_ima_adpcm_format_ok,
+		_af_ima_adpcm_init_compress, _af_ima_adpcm_init_decompress
+	},
+	{
+		AF_COMPRESSION_MS_ADPCM,
+		true,
+		"msadpcm",	/* label */
+		"MS ADPCM",	/* short name */
+		"Microsoft ADPCM",
+		4.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		true,	/* needsRebuffer */
+		false,	/* multiple_of */
+		_af_ms_adpcm_format_ok,
+		_af_ms_adpcm_init_compress, _af_ms_adpcm_init_decompress
+	},
+	{
+		AF_COMPRESSION_FLAC,
+#if ENABLE(FLAC)
+		true,
+#else
+		false,
+#endif
+		"flac",	// label
+		"FLAC",	// short name
+		"Free Lossless Audio Codec",
+		1.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		false,	// needsRebuffer
+		false,	// multiple_of
+		_af_flac_format_ok,
+		_af_flac_init_compress, _af_flac_init_decompress
+	},
+	{
+		AF_COMPRESSION_ALAC,
+		true,
+		"alac",	// label
+		"ALAC",	// short name
+		"Apple Lossless Audio Codec",
+		1.0,
+		AF_SAMPFMT_TWOSCOMP, 16,
+		true,	// needsRebuffer
+		false,	// multiple_of
+		_af_alac_format_ok,
+		_af_alac_init_compress, _af_alac_init_decompress
+	}
+};
diff --git a/libaudiofile/units.h b/libaudiofile/units.h
new file mode 100644
index 0000000..fe179ba
--- /dev/null
+++ b/libaudiofile/units.h
@@ -0,0 +1,89 @@
+/*
+	Audio File Library
+	Copyright (C) 2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	units.h
+
+	This file defines the internal Unit and CompressionUnit
+	structures for the Audio File Library.
+*/
+
+#ifndef UNIT_H
+#define UNIT_H
+
+#include "audiofile.h"
+#include "afinternal.h"
+
+struct AudioFormat;
+class FileModule;
+
+struct Unit
+{
+	int	fileFormat;	/* AF_FILEFMT_... */
+	const char *name;		/* a 2-3 word name of the file format */
+	const char *description;	/* a more descriptive name for the format */
+	const char *label;		/* a 4-character label for the format */
+	bool implemented;	/* if implemented */
+
+	AFfilesetup (*completesetup) (AFfilesetup setup);
+	bool (*recognize) (File *fh);
+
+	int defaultSampleFormat;
+	int defaultSampleWidth;
+
+	int compressionTypeCount;
+	const int *compressionTypes;
+
+	int markerCount;
+
+	int instrumentCount;
+	int loopPerInstrumentCount;
+
+	int instrumentParameterCount;
+	const InstParamInfo *instrumentParameters;
+};
+
+struct CompressionUnit
+{
+	int	compressionID;	/* AF_COMPRESSION_... */
+	bool implemented;
+	const char *label;		/* 4-character (approximately) label */
+	const char *shortname;	/* short name in English */
+	const char *name;		/* long name in English */
+	double squishFactor;	/* compression ratio */
+	int	nativeSampleFormat;	/* AF_SAMPFMT_... */
+	int	nativeSampleWidth;	/* sample width in bits */
+	bool	needsRebuffer;	/* if there are chunk boundary requirements */
+	bool	multiple_of;	/* can accept any multiple of chunksize */
+	bool	(*fmtok) (AudioFormat *format);
+
+	FileModule *(*initcompress) (Track *track, File *fh,
+		bool seekok, bool headerless, AFframecount *chunkframes);
+	FileModule *(*initdecompress) (Track *track, File *fh,
+		bool seekok, bool headerless, AFframecount *chunkframes);
+};
+
+#define _AF_NUM_UNITS 17
+#define _AF_NUM_COMPRESSION 7
+
+extern const Unit _af_units[_AF_NUM_UNITS];
+extern const CompressionUnit _af_compression[_AF_NUM_COMPRESSION];
+
+#endif /* UNIT_H */
diff --git a/libaudiofile/util.cpp b/libaudiofile/util.cpp
new file mode 100644
index 0000000..71dbf7c
--- /dev/null
+++ b/libaudiofile/util.cpp
@@ -0,0 +1,384 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2000, Silicon Graphics, Inc.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	util.c
+
+	This file contains general utility routines for the Audio File
+	Library.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "aupvlist.h"
+
+#include "AudioFormat.h"
+#include "File.h"
+#include "FileHandle.h"
+#include "Setup.h"
+#include "Track.h"
+#include "afinternal.h"
+#include "aupvinternal.h"
+#include "byteorder.h"
+#include "compression.h"
+#include "pcm.h"
+#include "units.h"
+#include "util.h"
+
+/*
+	_af_filesetup_ok and _af_filehandle_ok are sanity check routines
+	which are called at the beginning of every external subroutine.
+*/
+bool _af_filesetup_ok (AFfilesetup setup)
+{
+	if (setup == AF_NULL_FILESETUP)
+	{
+		_af_error(AF_BAD_FILESETUP, "null file setup");
+		return false;
+	}
+	if (setup->valid != _AF_VALID_FILESETUP)
+	{
+		_af_error(AF_BAD_FILESETUP, "invalid file setup");
+		return false;
+	}
+	return true;
+}
+
+bool _af_filehandle_ok (AFfilehandle file)
+{
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		_af_error(AF_BAD_FILEHANDLE, "null file handle");
+		return false;
+	}
+	if (file->m_valid != _AF_VALID_FILEHANDLE)
+	{
+		_af_error(AF_BAD_FILEHANDLE, "invalid file handle");
+		return false;
+	}
+	return true;
+}
+
+void *_af_malloc (size_t size)
+{
+	void	*p;
+
+	if (size <= 0)
+	{
+		_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
+		return NULL;
+	}
+
+	p = malloc(size);
+
+#ifdef AF_DEBUG
+	if (p)
+		memset(p, 0xff, size);
+#endif
+
+	if (p == NULL)
+	{
+		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
+		return NULL;
+	}
+
+	return p;
+}
+
+char *_af_strdup (const char *s)
+{
+	char *p = (char *) malloc(strlen(s) + 1);
+
+	if (p)
+		strcpy(p, s);
+
+	return p;
+}
+
+void *_af_realloc (void *p, size_t size)
+{
+	if (size <= 0)
+	{
+		_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
+		return NULL;
+	}
+
+	p = realloc(p, size);
+
+	if (p == NULL)
+	{
+		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
+		return NULL;
+	}
+
+	return p;
+}
+
+void *_af_calloc (size_t nmemb, size_t size)
+{
+	void	*p;
+
+	if (nmemb <= 0 || size <= 0)
+	{
+		_af_error(AF_BAD_MALLOC, "bad memory allocation size request "
+			"%zd elements of %zd bytes each", nmemb, size);
+		return NULL;
+	}
+
+	p = calloc(nmemb, size);
+
+	if (p == NULL)
+	{
+		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed",
+			nmemb*size);
+		return NULL;
+	}
+
+	return p;
+}
+
+AUpvlist _af_pv_long (long val)
+{
+	AUpvlist	ret = AUpvnew(1);
+	AUpvsetparam(ret, 0, 0);
+	AUpvsetvaltype(ret, 0, AU_PVTYPE_LONG);
+	AUpvsetval(ret, 0, &val);
+	return ret;
+}
+
+AUpvlist _af_pv_double (double val)
+{
+	AUpvlist	ret = AUpvnew(1);
+	AUpvsetparam(ret, 0, 0);
+	AUpvsetvaltype(ret, 0, AU_PVTYPE_DOUBLE);
+	AUpvsetval(ret, 0, &val);
+	return ret;
+}
+
+AUpvlist _af_pv_pointer (void *val)
+{
+	AUpvlist	ret = AUpvnew(1);
+	AUpvsetparam(ret, 0, 0);
+	AUpvsetvaltype(ret, 0, AU_PVTYPE_PTR);
+	AUpvsetval(ret, 0, &val);
+	return ret;
+}
+
+bool _af_pv_getlong (AUpvlist pvlist, int param, long *l)
+{
+	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
+	{
+		int	p, t;
+
+		AUpvgetparam(pvlist, i, &p);
+
+		if (p != param)
+			continue;
+
+		AUpvgetvaltype(pvlist, i, &t);
+
+		/* Ensure that this parameter is of type AU_PVTYPE_LONG. */
+		if (t != AU_PVTYPE_LONG)
+			return false;
+
+		AUpvgetval(pvlist, i, l);
+		return true;
+	}
+
+	return false;
+}
+
+bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d)
+{
+	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
+	{
+		int	p, t;
+
+		AUpvgetparam(pvlist, i, &p);
+
+		if (p != param)
+			continue;
+
+		AUpvgetvaltype(pvlist, i, &t);
+
+		/* Ensure that this parameter is of type AU_PVTYPE_DOUBLE. */
+		if (t != AU_PVTYPE_DOUBLE)
+			return false;
+
+		AUpvgetval(pvlist, i, d);
+		return true;
+	}
+
+	return false;
+}
+
+bool _af_pv_getptr (AUpvlist pvlist, int param, void **v)
+{
+	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
+	{
+		int	p, t;
+
+		AUpvgetparam(pvlist, i, &p);
+
+		if (p != param)
+			continue;
+
+		AUpvgetvaltype(pvlist, i, &t);
+
+		/* Ensure that this parameter is of type AU_PVTYPE_PTR. */
+		if (t != AU_PVTYPE_PTR)
+			return false;
+
+		AUpvgetval(pvlist, i, v);
+		return true;
+	}
+
+	return false;
+}
+
+int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4)
+{
+	int	size = 0;
+
+	switch (format->sampleFormat)
+	{
+		case AF_SAMPFMT_FLOAT:
+			size = sizeof (float);
+			break;
+		case AF_SAMPFMT_DOUBLE:
+			size = sizeof (double);
+			break;
+		default:
+			size = (int) (format->sampleWidth + 7) / 8;
+			if (format->compressionType == AF_COMPRESSION_NONE &&
+				size == 3 && stretch3to4)
+				size = 4;
+			break;
+	}
+
+	return size;
+}
+
+float _af_format_sample_size (const AudioFormat *fmt, bool stretch3to4)
+{
+	const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
+	float squishFactor = unit->squishFactor;
+
+	return _af_format_sample_size_uncompressed(fmt, stretch3to4) /
+		squishFactor;
+}
+
+int _af_format_frame_size_uncompressed (const AudioFormat *fmt, bool stretch3to4)
+{
+	return _af_format_sample_size_uncompressed(fmt, stretch3to4) *
+		fmt->channelCount;
+}
+
+float _af_format_frame_size (const AudioFormat *fmt, bool stretch3to4)
+{
+	const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
+	float squishFactor = unit->squishFactor;
+
+	return _af_format_frame_size_uncompressed(fmt, stretch3to4) /
+		squishFactor;
+}
+
+/*
+	Set the sampleFormat and sampleWidth fields in f, and set the
+	PCM info to the appropriate default values for the given sample
+	format and sample width.
+*/
+status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth)
+{
+	switch (sampleFormat)
+	{
+		case AF_SAMPFMT_UNSIGNED:
+		case AF_SAMPFMT_TWOSCOMP:
+		if (sampleWidth < 1 || sampleWidth > 32)
+		{
+			_af_error(AF_BAD_SAMPFMT,
+				"illegal sample width %d for integer data",
+				sampleWidth);
+			return AF_FAIL;
+		}
+		else
+		{
+			int bytes;
+
+			f->sampleFormat = sampleFormat;
+			f->sampleWidth = sampleWidth;
+
+			bytes = _af_format_sample_size_uncompressed(f, false);
+
+			if (sampleFormat == AF_SAMPFMT_TWOSCOMP)
+				f->pcm = _af_default_signed_integer_pcm_mappings[bytes];
+			else
+				f->pcm = _af_default_unsigned_integer_pcm_mappings[bytes];
+		}
+		break;
+
+		case AF_SAMPFMT_FLOAT:
+			f->sampleFormat = sampleFormat;
+			f->sampleWidth = 32;
+			f->pcm = _af_default_float_pcm_mapping;
+			break;
+		case AF_SAMPFMT_DOUBLE:
+			f->sampleFormat = sampleFormat;
+			f->sampleWidth = 64;      /*for convenience */
+			f->pcm = _af_default_double_pcm_mapping;
+			break;
+		default:
+			_af_error(AF_BAD_SAMPFMT, "unknown sample format %d",
+				sampleFormat);
+			return AF_FAIL;
+	}
+
+	return AF_SUCCEED;
+}
+
+/*
+	Verify the uniqueness of the nids ids given.
+
+	idname is the name of what the ids identify, as in "loop"
+	iderr is an error as in AF_BAD_LOOPID
+*/
+bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr)
+{
+	for (int i = 0; i < nids; i++)
+	{
+		for (int j = 0; j < i; j++)
+		{
+			if (ids[i] == ids[j])
+			{
+				_af_error(iderr, "nonunique %s id %d", idname, ids[i]);
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
diff --git a/libaudiofile/util.h b/libaudiofile/util.h
new file mode 100644
index 0000000..7a570a7
--- /dev/null
+++ b/libaudiofile/util.h
@@ -0,0 +1,64 @@
+/*
+	Audio File Library
+	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+/*
+	util.h
+
+	This file contains some general utility functions for the Audio
+	File Library.
+*/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+
+struct AudioFormat;
+
+bool _af_filesetup_ok (AFfilesetup setup);
+bool _af_filehandle_ok (AFfilehandle file);
+
+void *_af_malloc (size_t size);
+void *_af_realloc (void *ptr, size_t size);
+void *_af_calloc (size_t nmemb, size_t size);
+char *_af_strdup (const char *s);
+
+AUpvlist _af_pv_long (long val);
+AUpvlist _af_pv_double (double val);
+AUpvlist _af_pv_pointer (void *val);
+
+bool _af_pv_getlong (AUpvlist pvlist, int param, long *l);
+bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d);
+bool _af_pv_getptr (AUpvlist pvlist, int param, void **v);
+
+bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr);
+
+float _af_format_frame_size (const AudioFormat *format, bool stretch3to4);
+int _af_format_frame_size_uncompressed (const AudioFormat *format, bool stretch3to4);
+float _af_format_sample_size (const AudioFormat *format, bool stretch3to4);
+int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4);
+
+status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth);
+
+#endif
diff --git a/sfcommands/.gitignore b/sfcommands/.gitignore
new file mode 100644
index 0000000..9409fce
--- /dev/null
+++ b/sfcommands/.gitignore
@@ -0,0 +1,2 @@
+sfconvert
+sfinfo
diff --git a/sfcommands/Makefile.am b/sfcommands/Makefile.am
new file mode 100644
index 0000000..f2884d4
--- /dev/null
+++ b/sfcommands/Makefile.am
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile
+
+bin_PROGRAMS = sfconvert sfinfo
+
+sfconvert_SOURCES = sfconvert.c printinfo.c printinfo.h
+
+sfinfo_SOURCES = sfinfo.c printinfo.c printinfo.h
+
+LDADD = $(top_builddir)/libaudiofile/libaudiofile.la
+
+DEPENDENCIES = $(top_builddir)/libaudiofile/libaudiofile.la
+
+AM_CFLAGS = -Wall $(WERROR_CFLAGS)
diff --git a/sfcommands/printinfo.c b/sfcommands/printinfo.c
new file mode 100644
index 0000000..60e6947
--- /dev/null
+++ b/sfcommands/printinfo.c
@@ -0,0 +1,216 @@
+/*
+	Audio File Library
+
+	Copyright 1998, 2011, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	printinfo.c
+
+	This file contains the function used by the sf commands to print
+	information regarding a file.
+*/
+
+#include "config.h"
+#include "printinfo.h"
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static char *copyrightstring (AFfilehandle file);
+
+bool printfileinfo (const char *filename)
+{
+	AFfilehandle file = afOpenFile(filename, "r", NULL);
+	if (!file)
+		return false;
+
+	int fileFormat = afGetFileFormat(file, NULL);
+	const char *formatstring =
+		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_DESC,
+			fileFormat, 0, 0);
+	const char *labelstring =
+		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_LABEL,
+			fileFormat, 0, 0);
+
+	if (!formatstring || !labelstring)
+		return false;
+
+	printf("File Name      %s\n", filename);
+	printf("File Format    %s (%s)\n", formatstring, labelstring);
+
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+
+	int byteOrder = afGetByteOrder(file, AF_DEFAULT_TRACK);
+
+	printf("Data Format    ");
+
+	int compressionType = afGetCompression(file, AF_DEFAULT_TRACK);
+	if (compressionType == AF_COMPRESSION_NONE)
+	{
+		switch (sampleFormat)
+		{
+			case AF_SAMPFMT_TWOSCOMP:
+				printf("%d-bit integer (2's complement, %s)",
+					sampleWidth,
+					byteOrder == AF_BYTEORDER_BIGENDIAN ?
+						"big endian" : "little endian");
+				break;
+			case AF_SAMPFMT_UNSIGNED:
+				printf("%d-bit integer (unsigned, %s)",
+					sampleWidth,
+					byteOrder == AF_BYTEORDER_BIGENDIAN ?
+						"big endian" : "little endian");
+				break;
+			case AF_SAMPFMT_FLOAT:
+				printf("single-precision (32-bit) floating point, %s",
+					byteOrder == AF_BYTEORDER_BIGENDIAN ?
+						"big endian" : "little endian");
+				break;
+			case AF_SAMPFMT_DOUBLE:
+				printf("double-precision (64-bit) floating point, %s",
+					byteOrder == AF_BYTEORDER_BIGENDIAN ?
+						"big endian" : "little endian");
+				break;
+			default:
+				printf("unknown");
+				break;
+		}
+	}
+	else
+	{
+		const char *compressionName =
+			(const char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
+				AF_QUERY_NAME, compressionType, 0, 0);
+
+		if (!compressionName)
+			printf("unknown compression");
+		else
+			printf("%s compression", compressionName);
+	}
+	printf("\n");
+
+	printf("Audio Data     %jd bytes begins at offset %jd (%jx hex)\n",
+		(intmax_t) afGetTrackBytes(file, AF_DEFAULT_TRACK),
+		(intmax_t) afGetDataOffset(file, AF_DEFAULT_TRACK),
+		(uintmax_t) afGetDataOffset(file, AF_DEFAULT_TRACK));
+
+	printf("               %d channel%s, %jd frames\n",
+		afGetChannels(file, AF_DEFAULT_TRACK),
+		afGetChannels(file, AF_DEFAULT_TRACK) > 1 ? "s" : "",
+		(intmax_t) afGetFrameCount(file, AF_DEFAULT_TRACK));
+
+	printf("Sampling Rate  %.2f Hz\n", afGetRate(file, AF_DEFAULT_TRACK));
+
+	printf("Duration       %.3f seconds\n",
+		afGetFrameCount(file, AF_DEFAULT_TRACK) /
+		afGetRate(file, AF_DEFAULT_TRACK));
+
+	char *copyright = copyrightstring(file);
+	if (copyright)
+	{
+		printf("Copyright      %s\n", copyright);
+		free(copyright);
+	}
+
+	afCloseFile(file);
+
+	return true;
+}
+
+static char *copyrightstring (AFfilehandle file)
+{
+	char	*copyright = NULL;
+	int		*miscids;
+	int		i, misccount;
+
+	misccount = afGetMiscIDs(file, NULL);
+	miscids = (int *) malloc(sizeof (int) * misccount);
+	afGetMiscIDs(file, miscids);
+
+	for (i=0; i<misccount; i++)
+	{
+		if (afGetMiscType(file, miscids[i]) != AF_MISC_COPY)
+			continue;
+
+		/*
+			If this code executes, the miscellaneous chunk is a
+			copyright chunk.
+		*/
+		int datasize = afGetMiscSize(file, miscids[i]);
+		char *data = (char *) malloc(datasize);
+		afReadMisc(file, miscids[i], data, datasize);
+		copyright = data;
+		break;
+	}
+
+	free(miscids);
+
+	return copyright;
+}
+
+/*
+    0.73s 44100.00 aiff  1ch 16b -- flute.aif
+*/
+bool printshortinfo (const char *filename)
+{
+	AFfilehandle file = afOpenFile(filename, "r", NULL);;
+	if (!file)
+		return false;
+
+	int fileFormat = afGetFileFormat(file, NULL);
+	double sampleRate = afGetRate(file, AF_DEFAULT_TRACK);
+	double duration = afGetFrameCount(file, AF_DEFAULT_TRACK) / sampleRate;
+	const char *labelString =
+		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_LABEL,
+			fileFormat, 0, 0);
+	int channels = afGetChannels(file, AF_DEFAULT_TRACK);
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+
+	int compressionType = afGetCompression(file, AF_DEFAULT_TRACK);
+	const char *compressionName = "--";
+	if (compressionType != AF_COMPRESSION_NONE)
+	{
+		compressionName =
+			(const char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
+				AF_QUERY_NAME, compressionType, 0, 0);
+		if (!compressionName)
+			compressionName = "unk";
+	}
+
+	printf("%8.2fs %8.2f %4s %2dch %2db %s %s\n",
+		duration,
+		sampleRate,
+		labelString,
+		channels,
+		sampleWidth,
+		compressionName,
+		filename);
+
+	afCloseFile(file);
+
+	return true;
+}
diff --git a/sfcommands/printinfo.h b/sfcommands/printinfo.h
new file mode 100644
index 0000000..9e20a99
--- /dev/null
+++ b/sfcommands/printinfo.h
@@ -0,0 +1,29 @@
+/*
+	Audio File Library
+
+	Copyright 2011, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef PRINTINFO_H
+#define PRINTINFO_H
+
+#include <stdbool.h>
+
+bool printfileinfo(const char *filename);
+bool printshortinfo(const char *filename);
+
+#endif
diff --git a/sfcommands/sfconvert.c b/sfcommands/sfconvert.c
new file mode 100644
index 0000000..80a1bc4
--- /dev/null
+++ b/sfcommands/sfconvert.c
@@ -0,0 +1,366 @@
+/*
+	Audio File Library
+
+	Copyright (C) 1998, 2011-2012, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	sfconvert is a program which can convert various parameters of
+	sound files.
+*/
+
+#include "config.h"
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "printinfo.h"
+
+void printversion (void);
+void printusage (void);
+void usageerror (void);
+bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid);
+
+int main (int argc, char **argv)
+{
+	if (argc == 2)
+	{
+		if (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))
+		{
+			printversion();
+			exit(EXIT_SUCCESS);
+		}
+
+		if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
+		{
+			printusage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	if (argc < 3)
+		usageerror();
+
+	const char *inFileName = argv[1];
+	const char *outFileName = argv[2];
+
+	int outFileFormat = AF_FILE_UNKNOWN;
+	int outSampleFormat = -1, outSampleWidth = -1, outChannelCount = -1;
+	int outCompression = AF_COMPRESSION_NONE;
+	double outMaxAmp = 1.0;
+
+	int i = 3;
+
+	while (i < argc)
+	{
+		if (!strcmp(argv[i], "format"))
+		{
+			if (i + 1 >= argc)
+				usageerror();
+
+			if (!strcmp(argv[i+1], "aiff"))
+				outFileFormat = AF_FILE_AIFF;
+			else if (!strcmp(argv[i+1], "aifc"))
+				outFileFormat = AF_FILE_AIFFC;
+			else if (!strcmp(argv[i+1], "wave"))
+				outFileFormat = AF_FILE_WAVE;
+			else if (!strcmp(argv[i+1], "next"))
+				outFileFormat = AF_FILE_NEXTSND;
+			else if (!strcmp(argv[i+1], "bics"))
+				outFileFormat = AF_FILE_BICSF;
+			else if (!strcmp(argv[i+1], "smp"))
+				outFileFormat = AF_FILE_SAMPLEVISION;
+			else if (!strcmp(argv[i+1], "voc"))
+				outFileFormat = AF_FILE_VOC;
+			else if (!strcmp(argv[i+1], "nist"))
+				outFileFormat = AF_FILE_NIST_SPHERE;
+			else if (!strcmp(argv[i+1], "caf"))
+				outFileFormat = AF_FILE_CAF;
+			else if (!strcmp(argv[i+1], "flac"))
+				outFileFormat = AF_FILE_FLAC;
+			else
+			{
+				fprintf(stderr, "sfconvert: Unknown format %s.\n", argv[i+1]);
+				exit(EXIT_FAILURE);
+			}
+
+			// Increment for argument.
+			i++;
+		}
+		else if (!strcmp(argv[i], "channels"))
+		{
+			if (i + 1 >= argc)
+				usageerror();
+
+			outChannelCount = atoi(argv[i+1]);
+			if (outChannelCount < 1)
+				usageerror();
+
+			// Increment for argument.
+			i++;
+		}
+		else if (!strcmp(argv[i], "float"))
+		{
+			if (i + 1 >= argc)
+				usageerror();
+
+			outSampleFormat = AF_SAMPFMT_FLOAT;
+			outSampleWidth = 32;
+			outMaxAmp = atof(argv[i+1]);
+
+			// outMaxAmp is currently unused.
+			(void) outMaxAmp;
+
+			// Increment for argument.
+			i++;
+		}
+		else if (!strcmp(argv[i], "integer"))
+		{
+			if (i + 2 >= argc)
+				usageerror();
+
+			outSampleWidth = atoi(argv[i+1]);
+			if (outSampleWidth < 1 || outSampleWidth > 32)
+				usageerror();
+
+			if (!strcmp(argv[i+2], "2scomp"))
+				outSampleFormat = AF_SAMPFMT_TWOSCOMP;
+			else if (!strcmp(argv[i+2], "unsigned"))
+				outSampleFormat = AF_SAMPFMT_UNSIGNED;
+			else
+				usageerror();
+
+			// Increment for arguments.
+			i += 2;
+		}
+		else if (!strcmp(argv[i], "compression"))
+		{
+			if (i + 1 >= argc)
+				usageerror();
+
+			if (!strcmp(argv[i+1], "none"))
+				outCompression = AF_COMPRESSION_NONE;
+			else if (!strcmp(argv[i+1], "ulaw"))
+				outCompression = AF_COMPRESSION_G711_ULAW;
+			else if (!strcmp(argv[i+1], "alaw"))
+				outCompression = AF_COMPRESSION_G711_ALAW;
+			else if (!strcmp(argv[i+1], "ima"))
+				outCompression = AF_COMPRESSION_IMA;
+			else if (!strcmp(argv[i+1], "msadpcm"))
+				outCompression = AF_COMPRESSION_MS_ADPCM;
+			else if (!strcmp(argv[i+1], "flac"))
+				outCompression = AF_COMPRESSION_FLAC;
+			else if (!strcmp(argv[i+1], "alac"))
+				outCompression = AF_COMPRESSION_ALAC;
+			else
+			{
+				fprintf(stderr, "sfconvert: Unknown compression format %s.\n", argv[i+1]);
+				exit(EXIT_FAILURE);
+			}
+
+			i++;
+		}
+		else
+		{
+			printf("Unrecognized command %s\n", argv[i]);
+		}
+
+		i++;
+	}
+
+	AFfilehandle inFile = afOpenFile(inFileName, "r", AF_NULL_FILESETUP);
+	if (!inFile)
+	{
+		printf("Could not open file '%s' for reading.\n", inFileName);
+		return EXIT_FAILURE;
+	}
+
+	// Get audio format parameters from input file.
+	int fileFormat = afGetFileFormat(inFile, NULL);
+	int channelCount = afGetChannels(inFile, AF_DEFAULT_TRACK);
+	double sampleRate = afGetRate(inFile, AF_DEFAULT_TRACK);
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(inFile, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+
+	// Initialize output audio format parameters.
+	AFfilesetup outFileSetup = afNewFileSetup();
+
+	if (outFileFormat == -1)
+		outFileFormat = fileFormat;
+
+	if (outSampleFormat == -1 || outSampleWidth == -1)
+	{
+		outSampleFormat = sampleFormat;
+		outSampleWidth = sampleWidth;
+	}
+
+	if (outChannelCount == -1)
+		outChannelCount = channelCount;
+
+	afInitFileFormat(outFileSetup, outFileFormat);
+	afInitCompression(outFileSetup, AF_DEFAULT_TRACK, outCompression);
+	afInitSampleFormat(outFileSetup, AF_DEFAULT_TRACK, outSampleFormat,
+		outSampleWidth);
+	afInitChannels(outFileSetup, AF_DEFAULT_TRACK, outChannelCount);
+	afInitRate(outFileSetup, AF_DEFAULT_TRACK, sampleRate);
+
+	AFfilehandle outFile = afOpenFile(outFileName, "w", outFileSetup);
+	if (!outFile)
+	{
+		printf("Could not open file '%s' for writing.\n", outFileName);
+		return EXIT_FAILURE;
+	}
+
+	afFreeFileSetup(outFileSetup);
+
+	/*
+		Set the output file's virtual audio format parameters
+		to match the audio format parameters of the input file.
+	*/
+	afSetVirtualChannels(outFile, AF_DEFAULT_TRACK, channelCount);
+	afSetVirtualSampleFormat(outFile, AF_DEFAULT_TRACK, sampleFormat,
+		sampleWidth);
+
+	bool success = copyaudiodata(inFile, outFile, AF_DEFAULT_TRACK);
+
+	afCloseFile(inFile);
+	afCloseFile(outFile);
+
+	if (!success)
+	{
+		unlink(outFileName);
+		return EXIT_FAILURE;
+	}
+
+	printfileinfo(inFileName);
+	putchar('\n');
+	printfileinfo(outFileName);
+
+	return EXIT_SUCCESS;
+}
+
+void printusage (void)
+{
+	printf("usage: sfconvert infile outfile [ options ... ] [ output keywords ... ]\n");
+	printf("\n");
+
+	printf("Where keywords specify format of input or output soundfile:\n");
+	printf("    format f       file format f (see below)\n");
+	printf("    compression c  compression format c (see below)\n");
+	printf("    byteorder e    endian (e is big or little)\n");
+	printf("    channels n     n-channel file (1 or 2)\n");
+	printf("    integer n s    n-bit integer file, where s is one of\n");
+	printf("                       2scomp: 2's complement signed data\n");
+	printf("                       unsigned: unsigned data\n");
+	printf("    float m        floating point file, maxamp m (usually 1.0)\n");
+	printf("\n");
+
+	printf("Currently supported file formats are:\n");
+	printf("\n");
+	printf("    aiff    Audio Interchange File Format\n");
+	printf("    aifc    AIFF-C File Format\n");
+	printf("    next    NeXT/Sun Format\n");
+	printf("    wave    MS RIFF WAVE Format\n");
+	printf("    bics    Berkeley/IRCAM/CARL Sound File Format\n");
+	printf("    smp     Sample Vision Format\n");
+	printf("    voc     Creative Voice File\n");
+	printf("    nist    NIST SPHERE Format\n");
+	printf("    caf     Core Audio Format\n");
+	printf("\n");
+
+	printf("Currently supported compression formats are:\n");
+	printf("\n");
+	printf("    ulaw    G.711 u-law\n");
+	printf("    alaw    G.711 A-law\n");
+	printf("    ima     IMA ADPCM\n");
+	printf("    msadpcm MS ADPCM\n");
+	printf("    flac    FLAC\n");
+	printf("    alac    Apple Lossless Audio Codec\n");
+	printf("\n");
+}
+
+void usageerror (void)
+{
+	printusage();
+	exit(EXIT_FAILURE);
+}
+
+void printversion (void)
+{
+	printf("sfconvert: Audio File Library version %s\n", VERSION);
+}
+
+/*
+	Copy audio data from one file to another.  This function
+	assumes that the virtual sample formats of the two files
+	match.
+*/
+bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid)
+{
+	int frameSize = afGetVirtualFrameSize(infile, trackid, 1);
+
+	const int kBufferFrameCount = 65536;
+	void *buffer = malloc(kBufferFrameCount * frameSize);
+
+	AFframecount totalFrames = afGetFrameCount(infile, AF_DEFAULT_TRACK);
+	AFframecount totalFramesWritten = 0;
+
+	bool success = true;
+
+	while (totalFramesWritten < totalFrames)
+	{
+		AFframecount framesToRead = totalFrames - totalFramesWritten;
+		if (framesToRead > kBufferFrameCount)
+			framesToRead = kBufferFrameCount;
+
+		AFframecount framesRead = afReadFrames(infile, trackid, buffer,
+			framesToRead);
+
+		if (framesRead < framesToRead)
+		{
+			fprintf(stderr, "Bad read of audio track data.\n");
+			success = false;
+			break;
+		}
+
+		AFframecount framesWritten = afWriteFrames(outfile, trackid, buffer,
+			framesRead);
+
+		if (framesWritten < framesRead)
+		{
+			fprintf(stderr, "Bad write of audio track data.\n");
+			success = false;
+			break;
+		}
+
+		totalFramesWritten += framesWritten;
+	}
+
+	free(buffer);
+
+	return success;
+}
diff --git a/sfcommands/sfinfo.c b/sfcommands/sfinfo.c
new file mode 100644
index 0000000..c8fb913
--- /dev/null
+++ b/sfcommands/sfinfo.c
@@ -0,0 +1,120 @@
+/*
+	Audio File Library
+
+	Copyright 1998, 2011, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	sfinfo.c
+
+	This program displays information about audio files.
+*/
+
+#include "config.h"
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "printinfo.h"
+
+bool reportError = false;
+
+void errorHandler(long error, const char *message)
+{
+	if (reportError)
+		fprintf(stderr, "sfinfo: %s [error %ld]\n", message, error);
+}
+
+void printusage()
+{
+	printf("usage: sfinfo [options...] soundfiles...\n");
+	printf("options:\n");
+	printf("  -s, --short        Print information in short format\n");
+	printf("  -r, --reporterror  Report errors when reading sound files\n");
+	printf("  -h, --help         Print this help message\n");
+	printf("  -v, --version      Print version\n");
+}
+
+void printversion()
+{
+	printf("sfinfo: Audio File Library version %s\n", VERSION);
+}
+
+int main(int argc, char **argv)
+{
+	bool brief = false;
+
+	afSetErrorHandler(errorHandler);
+
+	if (argc == 1)
+	{
+		printusage();
+		return 0;
+	}
+
+	static struct option long_options[] =
+	{
+		{"short", 0, 0, 's'},
+		{"reporterror", 0, 0, 'r'},
+		{"help", 0, 0, 'h'},
+		{"version", 0, 0, 'v'},
+		{0, 0, 0, 0}
+	};
+
+	int result;
+	int option_index = 1;
+	while ((result = getopt_long(argc, argv, "srhv", long_options,
+		&option_index)) != -1)
+	{
+		switch (result)
+		{
+			case 's':
+				brief = true;
+				break;
+			case 'r':
+				reportError = true;
+				break;
+			case 'h':
+				printusage();
+				exit(EXIT_SUCCESS);
+			case 'v':
+				printversion();
+				exit(EXIT_SUCCESS);
+		}
+	}
+
+	int i = optind;
+	while (i < argc)
+	{
+		bool processed = brief ? printshortinfo(argv[i]) :
+			printfileinfo(argv[i]);
+		i++;
+		if (!brief && processed && i < argc)
+			putchar('\n');
+	}
+
+	return 0;
+}
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..77b848d
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,43 @@
+ADPCM
+AES
+ALAC
+ChannelMatrix
+Error
+FLAC
+FloatToInt
+FormatWithChannels
+Identify
+Instrument
+IntToFloat
+InvalidCompressionFormat
+InvalidSampleFormat
+Large
+Loop
+Marker
+Miscellaneous
+NeXT
+PCMData
+PCMMapping
+Pipe
+Query
+SampleFormat
+Seek
+Sign
+VirtualFile
+coverage
+floatto24
+instparamtest
+instparamwrite
+printmarkers
+query2
+sixteen-to-eight
+testaupv
+testchannelmatrix
+testdouble
+testfloat
+testmarkers
+twentyfour
+twentyfour2
+writealaw
+writeraw
+writeulaw
diff --git a/test/ADPCM.cpp b/test/ADPCM.cpp
new file mode 100644
index 0000000..7e7da3a
--- /dev/null
+++ b/test/ADPCM.cpp
@@ -0,0 +1,159 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <cstdlib>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static const int kIMABytesPerPacketQT = 34;
+static const int kIMABytesPerPacketWAVE = 256;
+
+static const int kIMAFramesPerPacketQT = 64;
+static const int kIMAFramesPerPacketWAVE = 505;
+
+static const int kIMAThresholdQT = 128;
+static const int kIMAThresholdWAVE = 16;
+
+static const int kMSADPCMBytesPerPacket = 256;
+static const int kMSADPCMFramesPerPacket = 500;
+static const int kMSADPCMThreshold = 16;
+
+static void testADPCM(int fileFormat, int compressionFormat, int channelCount,
+	int bytesPerPacket, int framesPerPacket, int frameCount, int threshold)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("ADPCM", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
+	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+	afFreeFileSetup(setup);
+
+	int16_t *data = new int16_t[frameCount * channelCount];
+	for (int i=0; i<frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+			data[i*channelCount + c] = i * ((c&1) ? -1 : 1);
+	
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
+	ASSERT_TRUE(file);
+	ASSERT_EQ(afGetCompression(file, AF_DEFAULT_TRACK), compressionFormat);
+	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);
+	ASSERT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
+		(bytesPerPacket * frameCount) / framesPerPacket);
+
+	int16_t *readData = new int16_t[frameCount * channelCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+
+	for (int i=0; i<frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+			EXPECT_LE(std::abs(data[i*channelCount + c] - readData[i*channelCount + c]), threshold);
+
+	int16_t *offsetReadData = new int16_t[frameCount * channelCount];
+
+	// Read entire file with a seek before each read operation.
+	for (AFframecount offset = 0; offset < frameCount; offset += framesPerPacket + 3)
+	{
+		ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, offset), offset);
+
+		AFframecount framesToRead = 1091;
+		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, offsetReadData, framesToRead);
+		ASSERT_EQ(framesRead, std::min(framesToRead, frameCount - offset));
+
+		for (int i=0; i<framesRead; i++)
+			for (int c=0; c<channelCount; c++)
+				EXPECT_EQ(readData[(i+offset)*channelCount + c],
+					offsetReadData[i*channelCount + c]);
+	}
+
+	// Read entire file sequentially in multiple read operations.
+	ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);
+
+	AFframecount framesToRead = 1087;
+	for (AFframecount offset = 0; offset < frameCount; offset += framesToRead)
+	{
+		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, offsetReadData, framesToRead);
+		ASSERT_EQ(framesRead, std::min(framesToRead, frameCount - offset));
+
+		for (int i=0; i<framesRead; i++)
+			for (int c=0; c<channelCount; c++)
+				EXPECT_EQ(readData[(i+offset)*channelCount + c],
+					offsetReadData[i*channelCount + c]);
+	}
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	delete [] data;
+	delete [] readData;
+	delete [] offsetReadData;
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(IMA, CAF)
+{
+	for (int channelCount=1; channelCount<=2; channelCount++)
+		testADPCM(AF_FILE_CAF, AF_COMPRESSION_IMA, channelCount,
+			channelCount * kIMABytesPerPacketQT, kIMAFramesPerPacketQT,
+			500 * kIMAFramesPerPacketQT, kIMAThresholdQT);
+}
+
+TEST(IMA, AIFFC)
+{
+	for (int channelCount=1; channelCount<=2; channelCount++)
+		testADPCM(AF_FILE_AIFFC, AF_COMPRESSION_IMA, channelCount,
+			channelCount * kIMABytesPerPacketQT, kIMAFramesPerPacketQT,
+			500 * kIMAFramesPerPacketQT, kIMAThresholdQT);
+}
+
+TEST(IMA, WAVE)
+{
+	for (int channelCount=1; channelCount<=2; channelCount++)
+		testADPCM(AF_FILE_WAVE, AF_COMPRESSION_IMA, channelCount,
+			channelCount * kIMABytesPerPacketWAVE, kIMAFramesPerPacketWAVE,
+			50 * kIMAFramesPerPacketWAVE, kIMAThresholdWAVE);
+}
+
+TEST(MSADPCM, WAVE)
+{
+	for (int channelCount=1; channelCount<=2; channelCount++)
+		testADPCM(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, channelCount,
+			channelCount * kMSADPCMBytesPerPacket, kMSADPCMFramesPerPacket,
+			50 * kMSADPCMFramesPerPacket, kMSADPCMThreshold);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/AES.cpp b/test/AES.cpp
new file mode 100644
index 0000000..6675293
--- /dev/null
+++ b/test/AES.cpp
@@ -0,0 +1,110 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static void testAESSupported(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("AES", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitAESChannelDataTo(setup, AF_DEFAULT_TRACK, true);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+
+	afFreeFileSetup(setup);
+
+	unsigned char aesData[24];
+	for (int i=0; i<24; i++)
+		aesData[i] = 3*i + 1;
+	afSetAESChannelData(file, AF_DEFAULT_TRACK, aesData);
+
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file);
+
+	unsigned char readAESData[24];
+	EXPECT_TRUE(afGetAESChannelData(file, AF_DEFAULT_TRACK, readAESData));
+	EXPECT_TRUE(!memcmp(aesData, readAESData, 24));
+
+	afCloseFile(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(AES_Supported, AIFFC) { testAESSupported(AF_FILE_AIFFC); }
+TEST(AES_Supported, AIFF) { testAESSupported(AF_FILE_AIFF); }
+
+static void testAESUnsupported(int fileFormat)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("AES", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitAESChannelDataTo(setup, AF_DEFAULT_TRACK, true);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(AES_Unsupported, Raw) { testAESUnsupported(AF_FILE_RAWDATA); }
+TEST(AES_Unsupported, NeXT) { testAESUnsupported(AF_FILE_NEXTSND); }
+TEST(AES_Unsupported, WAVE) { testAESUnsupported(AF_FILE_WAVE); }
+TEST(AES_Unsupported, IRCAM) { testAESUnsupported(AF_FILE_IRCAM); }
+TEST(AES_Unsupported, AVR) { testAESUnsupported(AF_FILE_AVR); }
+TEST(AES_Unsupported, IFF) { testAESUnsupported(AF_FILE_IFF_8SVX); }
+TEST(AES_Unsupported, SampleVision) { testAESUnsupported(AF_FILE_SAMPLEVISION); }
+TEST(AES_Unsupported, VOC) { testAESUnsupported(AF_FILE_VOC); }
+TEST(AES_Unsupported, NIST) { testAESUnsupported(AF_FILE_NIST_SPHERE); }
+TEST(AES_Unsupported, CAF) { testAESUnsupported(AF_FILE_CAF); }
+TEST(AES_Unsupported, FLAC) { testAESUnsupported(AF_FILE_FLAC); }
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/ALAC.cpp b/test/ALAC.cpp
new file mode 100644
index 0000000..e18c8eb
--- /dev/null
+++ b/test/ALAC.cpp
@@ -0,0 +1,128 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "Lossless.h"
+#include "TestUtilities.h"
+
+template <typename SampleType>
+static void testALAC(int fileFormat, int channelCount, int sampleWidth, int frameCount)
+{
+	testLossless<SampleType>("ALAC", fileFormat, AF_COMPRESSION_ALAC,
+		channelCount, sampleWidth, frameCount);
+}
+
+TEST(ALAC, ALAC_16)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testALAC<int16_t>(AF_FILE_CAF, channelCount, 16, 82421);
+}
+
+TEST(ALAC, ALAC_20)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testALAC<int32_t>(AF_FILE_CAF, channelCount, 20, 82421);
+}
+
+TEST(ALAC, ALAC_24)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testALAC<int32_t>(AF_FILE_CAF, channelCount, 24, 82421);
+}
+
+TEST(ALAC, ALAC_32)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testALAC<int32_t>(AF_FILE_CAF, channelCount, 32, 82421);
+}
+
+static void testInvalidSampleFormat(int sampleFormat, int sampleWidth)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("ALAC", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_CAF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_ALAC);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(ALAC, InvalidSampleWidths)
+{
+	IgnoreErrors ignoreErrors;
+
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+	{
+		if (sampleWidth == 16 ||
+			sampleWidth == 20 ||
+			sampleWidth == 24 ||
+			sampleWidth == 32)
+			continue;
+
+		testInvalidSampleFormat(AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+}
+
+TEST(ALAC, InvalidSampleFormats)
+{
+	IgnoreErrors ignoreErrors;
+
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+		testInvalidSampleFormat(AF_SAMPFMT_UNSIGNED, sampleWidth);
+
+	testInvalidSampleFormat(AF_SAMPFMT_FLOAT, 32);
+	testInvalidSampleFormat(AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(ALAC, InvalidChannels)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("ALAC", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_CAF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 9);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_ALAC);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/ChannelMatrix.cpp b/test/ChannelMatrix.cpp
new file mode 100644
index 0000000..09d5dd1
--- /dev/null
+++ b/test/ChannelMatrix.cpp
@@ -0,0 +1,225 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <string>
+
+#include "TestUtilities.h"
+
+template <typename T>
+void testChannelMatrixReading(int sampleFormat, int sampleWidth)
+{
+	// Create test file.
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));
+
+	const int channelCount = 2;
+	const int frameCount = 10;
+	const T samples[channelCount * frameCount] =
+	{
+		2, 3, 5, 7, 11,
+		13, 17, 19, 23, 29,
+		31, 37, 41, 43, 47,
+		53, 59, 61, 67, 71
+	};
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFFC);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	afFreeFileSetup(setup);
+	EXPECT_TRUE(file);
+
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK,
+		samples, frameCount);
+	EXPECT_EQ(framesWritten, frameCount);
+
+	EXPECT_EQ(afCloseFile(file), 0);
+
+	// Open file for reading and read data using different channel matrices.
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	EXPECT_TRUE(file);
+
+	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 2);
+	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);
+
+	afSetVirtualChannels(file, AF_DEFAULT_TRACK, 1);
+
+	for (int c=0; c<2; c++)
+	{
+		double channelMatrix[2] = { 0, 0 };
+		channelMatrix[c] = 1;
+		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);
+
+		EXPECT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);
+
+		T *readSamples = new T[frameCount]; 
+		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
+			readSamples, frameCount);
+		EXPECT_EQ(framesRead, frameCount);
+
+		for (int i=0; i<frameCount; i++)
+			EXPECT_EQ(readSamples[i], samples[2*i + c]);
+
+		delete [] readSamples;
+	}
+
+	EXPECT_EQ(afCloseFile(file), 0);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(ChannelMatrix, ReadInt8)
+{
+	testChannelMatrixReading<int8_t>(AF_SAMPFMT_TWOSCOMP, 8);
+}
+
+TEST(ChannelMatrix, ReadInt16)
+{
+	testChannelMatrixReading<int16_t>(AF_SAMPFMT_TWOSCOMP, 16);
+}
+
+TEST(ChannelMatrix, ReadInt24)
+{
+	testChannelMatrixReading<int32_t>(AF_SAMPFMT_TWOSCOMP, 24);
+}
+
+TEST(ChannelMatrix, ReadInt32)
+{
+	testChannelMatrixReading<int32_t>(AF_SAMPFMT_TWOSCOMP, 32);
+}
+
+TEST(ChannelMatrix, ReadFloat)
+{
+	testChannelMatrixReading<float>(AF_SAMPFMT_FLOAT, 32);
+}
+
+TEST(ChannelMatrix, ReadDouble)
+{
+	testChannelMatrixReading<double>(AF_SAMPFMT_DOUBLE, 64);
+}
+
+template <typename T>
+void testChannelMatrixWriting(int sampleFormat, int sampleWidth)
+{
+	const int channelCount = 2;
+	const int frameCount = 10;
+	const T samples[channelCount * frameCount] =
+	{
+		2, 3, 5, 7, 11,
+		13, 17, 19, 23, 29,
+		31, 37, 41, 43, 47,
+		53, 59, 61, 67, 71
+	};
+
+	for (int c=0; c<2; c++)
+	{
+		// Create test file.
+		std::string testFileName;
+		ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));
+
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+		AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+		afFreeFileSetup(setup);
+		EXPECT_TRUE(file);
+
+		afSetVirtualChannels(file, AF_DEFAULT_TRACK, 2);
+
+		double channelMatrix[2] = { 0, 0 };
+		channelMatrix[c] = 1;
+		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);
+
+		AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK,
+			samples, frameCount);
+		EXPECT_EQ(framesWritten, frameCount);
+
+		EXPECT_EQ(afCloseFile(file), 0);
+
+		// Open file for reading.
+		file = afOpenFile(testFileName.c_str(), "r", NULL);
+		EXPECT_TRUE(file);
+
+		EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
+		EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);
+
+		T *readSamples = new T[frameCount]; 
+		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
+			readSamples, frameCount);
+		EXPECT_EQ(framesRead, frameCount);
+
+		for (int i=0; i<frameCount; i++)
+			EXPECT_EQ(readSamples[i], samples[2*i + c]);
+
+		delete [] readSamples;
+
+		EXPECT_EQ(afCloseFile(file), 0);
+
+		ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+	}
+}
+
+TEST(ChannelMatrix, WriteInt8)
+{
+	testChannelMatrixWriting<int8_t>(AF_SAMPFMT_TWOSCOMP, 8);
+}
+
+TEST(ChannelMatrix, WriteInt16)
+{
+	testChannelMatrixWriting<int16_t>(AF_SAMPFMT_TWOSCOMP, 16);
+}
+
+TEST(ChannelMatrix, WriteInt24)
+{
+	testChannelMatrixWriting<int32_t>(AF_SAMPFMT_TWOSCOMP, 24);
+}
+
+TEST(ChannelMatrix, WriteInt32)
+{
+	testChannelMatrixWriting<int32_t>(AF_SAMPFMT_TWOSCOMP, 32);
+}
+
+TEST(ChannelMatrix, WriteFloat)
+{
+	testChannelMatrixWriting<float>(AF_SAMPFMT_FLOAT, 32);
+}
+
+TEST(ChannelMatrix, WriteDouble)
+{
+	testChannelMatrixWriting<double>(AF_SAMPFMT_DOUBLE, 64);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Error.cpp b/test/Error.cpp
new file mode 100644
index 0000000..5e10be2
--- /dev/null
+++ b/test/Error.cpp
@@ -0,0 +1,259 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <stdio.h>
+#include <gtest/gtest.h>
+
+struct ErrorListener *g_listener;
+
+struct ErrorListener
+{
+	ErrorListener(long expectedError) :
+		m_expectedError(expectedError),
+		m_receivedError(-1),
+		m_oldErrorFunction(0)
+	{
+		g_listener = this;
+		m_oldErrorFunction = afSetErrorHandler(errorHandlerHelper);
+	}
+	~ErrorListener()
+	{
+		g_listener = 0;
+		EXPECT_EQ(m_expectedError, m_receivedError);
+		afSetErrorHandler(m_oldErrorFunction);
+	}
+
+	long m_expectedError;
+	long m_receivedError;
+	AFerrfunc m_oldErrorFunction;
+
+	static void errorHandlerHelper(long error, const char *description)
+	{
+		g_listener->errorHandler(error, description);
+	}
+	void errorHandler(long error, const char *description)
+	{
+		m_receivedError = error;
+		EXPECT_EQ(m_expectedError, m_receivedError);
+	}
+};
+
+#define TEST_ERROR(ExpectedError, Message, TestBody) \
+	{ \
+		SCOPED_TRACE(Message); \
+		ErrorListener el(ExpectedError); \
+		TestBody; \
+	}
+
+TEST(Data, Null)
+{
+	TEST_ERROR(AF_BAD_FILEHANDLE, "closing null file handle",
+		afCloseFile(AF_NULL_FILEHANDLE));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "reading from null file handle",
+		afReadFrames(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, 0));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "writing to null file handle",
+		afWriteFrames(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, 0));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "setting position on null file handle",
+		afSeekFrame(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, 0));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "retrieving position on null file handle",
+		afTellFrame(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+}
+
+TEST(Channels, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "initializing channels of null file setup",
+		afInitChannels(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 1));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting channels of null file handle",
+		afGetChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting virtual channels of null file handle",
+		afGetVirtualChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "setting virtual channels of null file handle",
+		afSetVirtualChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, 1));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "setting channel matrix of null file handle",
+		afSetChannelMatrix(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));
+}
+
+TEST(Rate, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "initializing rate of null file setup",
+		afInitRate(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 44100));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting rate of null file handle",
+		afGetRate(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+}
+
+TEST(Compression, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "initializing compression of null file setup",
+		afInitCompression(AF_NULL_FILESETUP, AF_DEFAULT_TRACK,
+			AF_COMPRESSION_NONE));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting compression of null file handle",
+		afGetCompression(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+}
+
+TEST(SampleFormat, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP,
+		"initializing sample format of null file setup",
+		afInitSampleFormat(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"getting sample format of null file handle",
+		afGetSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, NULL));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"getting virtual sample format of null file handle",
+		afGetVirtualSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, NULL));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"setting virtual sample format of null file handle",
+		afSetVirtualSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16));
+}
+
+TEST(ByteOrder, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP,
+		"initializing byte order of null file setup",
+		afInitByteOrder(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"getting byte order of null file handle",
+		afGetByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"getting virtual byte order of null file handle",
+		afGetVirtualByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"setting virtual byte order of null file handle",
+		afSetVirtualByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN));
+}
+
+TEST(DataOffset, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "initializing data offset of null file setup",
+		afInitDataOffset(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 0));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting data offset of null file handle",
+		afGetDataOffset(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+}
+
+TEST(FrameCount, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "initializing frame count of null file setup",
+		afInitFrameCount(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 0));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE, "getting frame count of null file handle",
+		afGetFrameCount(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
+}
+
+TEST(AES, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP,
+		"initializing AES channel data of null file setup",
+		afInitAESChannelData(AF_NULL_FILESETUP, AF_DEFAULT_TRACK));
+
+	TEST_ERROR(AF_BAD_FILESETUP,
+		"initializing AES channel data of null file setup",
+		afInitAESChannelDataTo(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 1));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"getting AES channel data of null file handle",
+		afGetAESChannelData(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));
+
+	TEST_ERROR(AF_BAD_FILEHANDLE,
+		"setting AES channel data of null file handle",
+		afSetAESChannelData(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));
+}
+
+TEST(Setup, Null)
+{
+	TEST_ERROR(AF_BAD_FILESETUP, "freeing null file setup",
+		afFreeFileSetup(AF_NULL_FILESETUP));
+}
+
+TEST(File, Bad)
+{
+	TEST_ERROR(AF_BAD_OPEN, "opening nonexistent file for reading",
+		afOpenFile("sldkjflsdkfjalksdjflaksdjflsakfdj", "r", NULL));
+
+	TEST_ERROR(AF_BAD_ACCMODE, "opening file with null access mode",
+		afOpenFile("", NULL, NULL));
+
+	TEST_ERROR(AF_BAD_ACCMODE, "opening file with invalid access mode",
+		afOpenFile("", "x", NULL));
+
+	TEST_ERROR(AF_BAD_FILEFMT, "initializing file format to invalid value",
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, 91094);
+		afFreeFileSetup(setup));
+
+	TEST_ERROR(AF_BAD_SAMPFMT,
+		"initializing sample format and sample width to invalid values",
+		AFfilesetup setup = afNewFileSetup();
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, 3992, 3932);
+		afFreeFileSetup(setup));
+}
+
+TEST(Query, Bad)
+{
+	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
+		afQueryLong(AF_QUERYTYPE_INST, 9999, 9999, 9999, 9999));
+
+	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
+		afQueryLong(AF_QUERYTYPE_INSTPARAM, 9999, 9999, 9999, 9999));
+
+	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
+		afQueryLong(AF_QUERYTYPE_FILEFMT, 9999, 9999, 9999, 9999));
+
+	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
+		afQueryLong(AF_QUERYTYPE_COMPRESSION, 9999, 9999, 9999, 9999));
+
+	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
+		afQueryLong(AF_QUERYTYPE_MARK, 9999, 9999, 9999, 9999));
+
+	TEST_ERROR(AF_BAD_QUERYTYPE, "querying using bad query type",
+		afQueryLong(9999, 9999, 9999, 9999, 9999));
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/FLAC.cpp b/test/FLAC.cpp
new file mode 100644
index 0000000..adb7ffd
--- /dev/null
+++ b/test/FLAC.cpp
@@ -0,0 +1,111 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "Lossless.h"
+#include "TestUtilities.h"
+
+template <typename SampleType>
+static void testFLAC(int channelCount, int sampleWidth, int frameCount)
+{
+	testLossless<SampleType>("FLAC", AF_FILE_FLAC, AF_COMPRESSION_FLAC,
+		channelCount, sampleWidth, frameCount);
+}
+
+TEST(FLAC, FLAC_16)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testFLAC<int16_t>(channelCount, 16, 82421);
+}
+
+TEST(FLAC, FLAC_24)
+{
+	for (int channelCount=1; channelCount<=8; channelCount++)
+		testFLAC<int32_t>(channelCount, 24, 82421);
+}
+
+static void testInvalidSampleFormat(int sampleFormat, int sampleWidth)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("FLAC", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_FLAC);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_FLAC);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(FLAC, InvalidSampleWidths)
+{
+	IgnoreErrors ignoreErrors;
+
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+	{
+		if (sampleWidth == 16 || sampleWidth == 24)
+			continue;
+
+		testInvalidSampleFormat(AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+}
+
+TEST(FLAC, InvalidSampleFormats)
+{
+	IgnoreErrors ignoreErrors;
+
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+		testInvalidSampleFormat(AF_SAMPFMT_UNSIGNED, sampleWidth);
+
+	testInvalidSampleFormat(AF_SAMPFMT_FLOAT, 32);
+	testInvalidSampleFormat(AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(FLAC, InvalidChannels)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("FLAC", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_FLAC);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 9);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_FLAC);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/FloatToInt.cpp b/test/FloatToInt.cpp
new file mode 100644
index 0000000..0d179a8
--- /dev/null
+++ b/test/FloatToInt.cpp
@@ -0,0 +1,166 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <limits>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+class FloatToIntTest : public testing::Test
+{
+protected:
+	virtual void SetUp()
+	{
+		ASSERT_TRUE(createTemporaryFile("FloatToInt", &m_testFileName));
+	}
+	virtual void TearDown()
+	{
+		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
+	}
+
+	AFfilehandle createTestFile(int sampleWidth)
+	{
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
+		afFreeFileSetup(setup);
+		return file;
+	}
+	AFfilehandle openTestFile(int sampleWidth)
+	{
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		return file;
+	}
+
+private:
+	std::string m_testFileName;
+};
+
+static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
+static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
+
+TEST_F(FloatToIntTest, Int8)
+{
+	AFfilehandle file = createTestFile(8);
+	const float data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(8);
+	ASSERT_TRUE(file != NULL);
+	int8_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const int8_t expectedData[] = { kMinInt8, 0, kMaxInt8 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
+static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();
+
+TEST_F(FloatToIntTest, Int16)
+{
+	AFfilehandle file = createTestFile(16);
+	const float data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(16);
+	ASSERT_TRUE(file != NULL);
+	int16_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const int16_t expectedData[] = { kMinInt16, 0, kMaxInt16 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt24 = -1<<23;
+static const int32_t kMaxInt24 = (1<<23) - 1;
+
+TEST_F(FloatToIntTest, Int24)
+{
+	AFfilehandle file = createTestFile(24);
+	const float data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(24);
+	ASSERT_TRUE(file != NULL);
+	int32_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const int32_t expectedData[] = { kMinInt24, 0, kMaxInt24 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
+static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
+
+TEST_F(FloatToIntTest, Int32)
+{
+	AFfilehandle file = createTestFile(32);
+	const float data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(32);
+	ASSERT_TRUE(file != NULL);
+	int32_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const int32_t expectedData[] = { kMinInt32, 0, kMaxInt32 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/FormatWithChannels.cpp b/test/FormatWithChannels.cpp
new file mode 100644
index 0000000..a547892
--- /dev/null
+++ b/test/FormatWithChannels.cpp
@@ -0,0 +1,123 @@
+/*
+	Copyright (C) 2016, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	Validate conversion when changing both sample format and channel count.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <algorithm>
+#include <climits>
+#include <limits>
+
+#include "TestUtilities.h"
+
+class FormatWithChannels : public testing::Test
+{
+protected:
+	virtual void SetUp()
+	{
+		ASSERT_TRUE(createTemporaryFile("FormatWithChannels", &m_testFileName));
+	}
+	virtual void TearDown()
+	{
+		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
+	}
+
+	AFfilehandle createTestFile(int sampleWidth, int channelCount)
+	{
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
+		afFreeFileSetup(setup);
+		return file;
+	}
+	AFfilehandle openTestFile(int sampleWidth, int channelCount)
+	{
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		afSetVirtualChannels(file, AF_DEFAULT_TRACK, channelCount);
+		int fileChannels = afGetChannels(file, AF_DEFAULT_TRACK);
+
+		double channelMatrix[fileChannels * channelCount];
+		for (int i = 0; i < fileChannels; i++)
+			for (int j = 0; j < channelCount; j++)
+				channelMatrix[j * fileChannels + i] = (i == j) ? 1 : 0;
+		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);
+		return file;
+	}
+
+private:
+	std::string m_testFileName;
+};
+
+const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
+const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
+const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
+const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();
+
+TEST_F(FormatWithChannels, Int16ToInt8)
+{
+	for (int fileChannels = 1; fileChannels <= 4; fileChannels++)
+	{
+		AFfilehandle file = createTestFile(16, fileChannels);
+		const int frameCount = 3;
+		int16_t data[frameCount * fileChannels];
+		std::fill(data, data + frameCount * fileChannels, 0);
+		data[0] = kMinInt16;
+		data[2 * fileChannels] = kMaxInt16;
+
+		AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+		ASSERT_EQ(framesWritten, frameCount);
+		afCloseFile(file);
+
+		file = openTestFile(8, 1);
+		ASSERT_TRUE(file != NULL);
+		int8_t readData[frameCount];
+		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+		ASSERT_EQ(framesRead, frameCount);
+		afCloseFile(file);
+		EXPECT_EQ(readData[0], kMinInt8);
+		EXPECT_EQ(readData[1], 0);
+		EXPECT_EQ(readData[2], kMaxInt8);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Identify.cpp b/test/Identify.cpp
new file mode 100644
index 0000000..4b63ba7
--- /dev/null
+++ b/test/Identify.cpp
@@ -0,0 +1,93 @@
+/*
+	Audio File Library
+	Copyright (C) 2014, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+
+#include "TestUtilities.h"
+
+const uint8_t kNeXTData[] =
+{
+	'.', 's', 'n', 'd',
+	0, 0, 0, 24, // offset of 24 bytes
+	0, 0, 0, 2, // unspecified length
+	0, 0, 0, 3, // 16-bit linear
+	0, 0, 172, 68, // 44100 Hz
+	0, 0, 0, 1, // 1 channel
+	0, 0
+};
+
+TEST(Identify, NeXT)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Identify", &testFileName));
+	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ASSERT_GT(fd, -1);
+	ASSERT_EQ(::write(fd, kNeXTData, sizeof (kNeXTData)), sizeof (kNeXTData));
+
+	EXPECT_TRUE(AF_FILE_NEXTSND == afIdentifyFD(fd));
+
+	int implemented = -1;
+	EXPECT_TRUE(AF_FILE_NEXTSND == afIdentifyNamedFD(fd, testFileName.c_str(), &implemented));
+	EXPECT_EQ(implemented, 1);
+
+	ASSERT_EQ(::close(fd), 0);
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(Identify, Empty)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Identify", &testFileName));
+	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ASSERT_GT(fd, -1);
+
+	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyFD(fd));
+
+	int implemented = -1;
+	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyNamedFD(fd, testFileName.c_str(), &implemented));
+	EXPECT_EQ(implemented, 0);
+
+	ASSERT_EQ(::close(fd), 0);
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(Identify, NonSeekable)
+{
+	int pipefd[2];
+	ASSERT_GE(::pipe(pipefd), 0);
+
+	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyFD(pipefd[0]));
+	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyNamedFD(pipefd[0], "", NULL));
+
+	ASSERT_EQ(::close(pipefd[0]), 0);
+	ASSERT_EQ(::close(pipefd[1]), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Instrument.cpp b/test/Instrument.cpp
new file mode 100644
index 0000000..32ac392
--- /dev/null
+++ b/test/Instrument.cpp
@@ -0,0 +1,108 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <stdlib.h>
+
+#include "TestUtilities.h"
+
+static void testInstrumentParameters(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Instrument", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	int instrumentIDs[] = {AF_DEFAULT_INST};
+	int numInstruments = sizeof (instrumentIDs) / sizeof (int);
+	afInitInstIDs(setup, instrumentIDs, numInstruments);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+
+	afFreeFileSetup(setup);
+
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE, 50);
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE, -30);
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY, 22);
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY, 111);
+
+	ASSERT_EQ(0, afCloseFile(file));
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file);
+	ASSERT_EQ(fileFormat, afGetFileFormat(file, NULL));
+
+	ASSERT_EQ(1, afGetInstIDs(file, NULL));
+	int readInstrumentIDs[1] = {0};
+	ASSERT_EQ(1, afGetInstIDs(file, readInstrumentIDs));
+	ASSERT_TRUE(AF_DEFAULT_INST == readInstrumentIDs[0]);
+
+	EXPECT_EQ(50,
+		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE));
+	EXPECT_EQ(-30,
+		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE));
+	EXPECT_EQ(22,
+		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY));
+	EXPECT_EQ(111,
+		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY));
+
+	ASSERT_EQ(0, afCloseFile(file));
+	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
+}
+
+TEST(Instrument, AIFF) { testInstrumentParameters(AF_FILE_AIFF); }
+TEST(Instrument, AIFFC) { testInstrumentParameters(AF_FILE_AIFFC); }
+
+static void testInstrumentUnsupported(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Instrument", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	int instrumentIDs[] = {AF_DEFAULT_INST};
+	int numInstruments = sizeof (instrumentIDs) / sizeof (int);
+	afInitInstIDs(setup, instrumentIDs, numInstruments);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
+}
+
+TEST(Instrument, Raw) { testInstrumentUnsupported(AF_FILE_RAWDATA); }
+TEST(Instrument, NeXT) { testInstrumentUnsupported(AF_FILE_NEXTSND); }
+TEST(Instrument, IRCAM) { testInstrumentUnsupported(AF_FILE_IRCAM); }
+TEST(Instrument, AVR) { testInstrumentUnsupported(AF_FILE_AVR); }
+TEST(Instrument, IFF_8SVX) { testInstrumentUnsupported(AF_FILE_IFF_8SVX); }
+TEST(Instrument, SampleVision) { testInstrumentUnsupported(AF_FILE_SAMPLEVISION); }
+TEST(Instrument, VOC) { testInstrumentUnsupported(AF_FILE_VOC); }
+TEST(Instrument, NIST) { testInstrumentUnsupported(AF_FILE_NIST_SPHERE); }
+TEST(Instrument, CAF) { testInstrumentUnsupported(AF_FILE_CAF); }
+TEST(Instrument, FLAC) { testInstrumentUnsupported(AF_FILE_FLAC); }
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/IntToFloat.cpp b/test/IntToFloat.cpp
new file mode 100644
index 0000000..b716635
--- /dev/null
+++ b/test/IntToFloat.cpp
@@ -0,0 +1,168 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits>
+#include <string>
+
+#include "TestUtilities.h"
+
+class IntToFloatTest : public testing::Test
+{
+protected:
+	virtual void SetUp()
+	{
+		ASSERT_TRUE(createTemporaryFile("IntToFloat", &m_testFileName));
+	}
+	virtual void TearDown()
+	{
+		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
+	}
+
+	static char kTestFileName[];
+
+	AFfilehandle createTestFile(int sampleWidth)
+	{
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
+		afFreeFileSetup(setup);
+		return file;
+	}
+	AFfilehandle openTestFile()
+	{
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
+		return file;
+	}
+
+private:
+	std::string m_testFileName;
+};
+
+static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
+static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
+
+TEST_F(IntToFloatTest, Int8)
+{
+	AFfilehandle file = createTestFile(8);
+	const int8_t data[] = { kMinInt8, 0, kMaxInt8 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	float readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<7) };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
+static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();
+
+TEST_F(IntToFloatTest, Int16)
+{
+	AFfilehandle file = createTestFile(16);
+	const int16_t data[] = { kMinInt16, 0, kMaxInt16 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	float readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<15) };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt24 = -1<<23;
+static const int32_t kMaxInt24 = (1<<23) - 1;
+
+TEST_F(IntToFloatTest, Int24)
+{
+	AFfilehandle file = createTestFile(24);
+	const int32_t data[] = { kMinInt24, 0, kMaxInt24 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	float readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<23) };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
+static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
+
+TEST_F(IntToFloatTest, Int32)
+{
+	AFfilehandle file = createTestFile(32);
+	const int32_t data[] = { kMinInt32, 0, kMaxInt32 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	float readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<31) };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/InvalidCompressionFormat.cpp b/test/InvalidCompressionFormat.cpp
new file mode 100644
index 0000000..686acc1
--- /dev/null
+++ b/test/InvalidCompressionFormat.cpp
@@ -0,0 +1,231 @@
+/*
+	Audio File Library
+	Copyright (C) 2012-2013, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "config.h"
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static const int kNativeByteOrder =
+#ifdef WORDS_BIGENDIAN
+	AF_BYTEORDER_BIGENDIAN;
+#else
+	AF_BYTEORDER_LITTLEENDIAN;
+#endif
+
+static const int kNonNativeByteOrder =
+#if WORDS_BIGENDIAN
+	AF_BYTEORDER_LITTLEENDIAN;
+#else
+	AF_BYTEORDER_BIGENDIAN;
+#endif
+
+static void runTest(int fileFormat, int compressionFormat, int channelCount = 1,
+	int sampleFormat = AF_SAMPFMT_TWOSCOMP, int sampleWidth = 16,
+	int byteOrder = kNativeByteOrder)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("InvalidCompressionFormat", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
+	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
+	afInitByteOrder(setup, AF_DEFAULT_TRACK, byteOrder);
+	ASSERT_TRUE(afOpenFile(testFileName.c_str(), "w", setup) == AF_NULL_FILEHANDLE);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(AIFF, mulaw) { runTest(AF_FILE_AIFF, AF_COMPRESSION_G711_ULAW); }
+TEST(AIFF, Alaw) { runTest(AF_FILE_AIFF, AF_COMPRESSION_G711_ALAW); }
+TEST(AIFF, IMA) { runTest(AF_FILE_AIFF, AF_COMPRESSION_IMA); }
+TEST(AIFF, MSADPCM) { runTest(AF_FILE_AIFF, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(AIFFC, MSADPCM) { runTest(AF_FILE_AIFFC, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(NeXT, IMA) { runTest(AF_FILE_NEXTSND, AF_COMPRESSION_IMA); }
+TEST(NeXT, MSADPCM) { runTest(AF_FILE_NEXTSND, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(IRCAM, IMA) { runTest(AF_FILE_BICSF, AF_COMPRESSION_IMA); }
+TEST(IRCAM, MSADPCM) { runTest(AF_FILE_BICSF, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(AVR, mulaw) { runTest(AF_FILE_AVR, AF_COMPRESSION_G711_ULAW); }
+TEST(AVR, Alaw) { runTest(AF_FILE_AVR, AF_COMPRESSION_G711_ALAW); }
+TEST(AVR, IMA) { runTest(AF_FILE_AVR, AF_COMPRESSION_IMA); }
+TEST(AVR, MSADPCM) { runTest(AF_FILE_AVR, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(IFF, mulaw) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_G711_ULAW); }
+TEST(IFF, Alaw) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_G711_ALAW); }
+TEST(IFF, IMA) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_IMA); }
+TEST(IFF, MSADPCM) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(SampleVision, mulaw) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_G711_ULAW); }
+TEST(SampleVision, Alaw) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_G711_ALAW); }
+TEST(SampleVision, IMA) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_IMA); }
+TEST(SampleVision, MSADPCM) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(VOC, IMA) { runTest(AF_FILE_VOC, AF_COMPRESSION_IMA); }
+TEST(VOC, MSADPCM) { runTest(AF_FILE_VOC, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(NIST, IMA) { runTest(AF_FILE_NIST_SPHERE, AF_COMPRESSION_IMA); }
+TEST(NIST, MSADPCM) { runTest(AF_FILE_NIST_SPHERE, AF_COMPRESSION_MS_ADPCM); }
+
+TEST(CAF, MSADPCM) { runTest(AF_FILE_CAF, AF_COMPRESSION_MS_ADPCM); }
+
+/*
+	Test that opening an audio file with an invalid number of channels
+	results in failure.
+*/
+
+TEST(AIFFC, IMA) { runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 3); }
+
+TEST(WAVE, IMA) { runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 3); }
+TEST(WAVE, MSADPCM) { runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 3); }
+
+TEST(CAF, IMA) { runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 3); }
+
+/*
+	Test that opening an audio file with an invalid sample format results
+	in failure.
+*/
+
+TEST(Mulaw, Signed)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+	{
+		if (sampleWidth==16)
+			continue;
+		runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+}
+
+TEST(Mulaw, Unsigned)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+		runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
+}
+
+TEST(Mulaw, Float)
+{
+	runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_FLOAT, 32);
+}
+
+TEST(Mulaw, Double)
+{
+	runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(IMA, Signed)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+	{
+		if (sampleWidth==16)
+			continue;
+		runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	}
+}
+
+TEST(IMA, Unsigned)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+	{
+		runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
+		runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
+		runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
+	}
+}
+
+TEST(IMA, Float)
+{
+	runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
+	runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
+}
+
+TEST(IMA, Double)
+{
+	runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
+	runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(MSADPCM, Signed)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+		if (sampleWidth!=16)
+			runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+}
+
+TEST(MSADPCM, Unsigned)
+{
+	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
+		runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
+}
+
+TEST(MSADPCM, Float)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_FLOAT, 32);
+}
+
+TEST(MSADPCM, Double)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(Mulaw, InvalidByteOrder)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_TWOSCOMP, 16,
+		kNonNativeByteOrder);
+}
+
+TEST(Alaw, InvalidByteOrder)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_G711_ALAW, 1, AF_SAMPFMT_TWOSCOMP, 16,
+		kNonNativeByteOrder);
+}
+
+TEST(IMA, InvalidByteOrder)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, 16,
+		kNonNativeByteOrder);
+}
+
+TEST(MSADPCM, InvalidByteOrder)
+{
+	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_TWOSCOMP, 16,
+		kNonNativeByteOrder);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/InvalidSampleFormat.cpp b/test/InvalidSampleFormat.cpp
new file mode 100644
index 0000000..2128ec2
--- /dev/null
+++ b/test/InvalidSampleFormat.cpp
@@ -0,0 +1,139 @@
+/*
+	Copyright (C) 2012, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+void runTest(int fileFormat, int sampleFormat, int sampleWidth)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("InvalidSampleFormat", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	ASSERT_TRUE(afOpenFile(testFileName.c_str(), "w", setup) == AF_NULL_FILEHANDLE);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+void testInt8(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 8);
+}
+
+void testUInt8(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 8);
+}
+
+void testInt16(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 16);
+}
+
+void testUInt16(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 16);
+}
+
+void testInt24(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 24);
+}
+
+void testUInt24(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 24);
+}
+
+void testInt32(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 32);
+}
+
+void testUInt32(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 32);
+}
+
+void testFloat32(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_FLOAT, 32);
+}
+
+void testFloat64(int fileFormat)
+{
+	runTest(fileFormat, AF_SAMPFMT_DOUBLE, 64);
+}
+
+TEST(AIFF, Float) { testFloat32(AF_FILE_AIFF); }
+TEST(AIFF, Double) { testFloat64(AF_FILE_AIFF); }
+
+TEST(IFF, Int16) { testInt16(AF_FILE_IFF_8SVX); }
+TEST(IFF, Int24) { testInt24(AF_FILE_IFF_8SVX); }
+TEST(IFF, Int32) { testInt32(AF_FILE_IFF_8SVX); }
+TEST(IFF, Float) { testFloat32(AF_FILE_IFF_8SVX); }
+TEST(IFF, Double) { testFloat64(AF_FILE_IFF_8SVX); }
+
+TEST(AVR, Int24) { testInt24(AF_FILE_AVR); }
+TEST(AVR, Int32) { testInt32(AF_FILE_AVR); }
+TEST(AVR, Float) { testFloat32(AF_FILE_AVR); }
+TEST(AVR, Double) { testFloat64(AF_FILE_AVR); }
+
+TEST(SampleVision, Int8) { testInt8(AF_FILE_SAMPLEVISION); }
+TEST(SampleVision, Int24) { testInt24(AF_FILE_SAMPLEVISION); }
+TEST(SampleVision, Int32) { testInt32(AF_FILE_SAMPLEVISION); }
+TEST(SampleVision, Float) { testFloat32(AF_FILE_SAMPLEVISION); }
+TEST(SampleVision, Double) { testFloat64(AF_FILE_SAMPLEVISION); }
+
+TEST(VOC, Int24) { testInt24(AF_FILE_VOC); }
+TEST(VOC, Int32) { testInt32(AF_FILE_VOC); }
+TEST(VOC, Float) { testFloat32(AF_FILE_VOC); }
+TEST(VOC, Double) { testFloat64(AF_FILE_VOC); }
+
+TEST(NIST, Int24) { testInt24(AF_FILE_NIST_SPHERE); }
+TEST(NIST, Int32) { testInt32(AF_FILE_NIST_SPHERE); }
+TEST(NIST, Float) { testFloat32(AF_FILE_NIST_SPHERE); }
+TEST(NIST, Double) { testFloat64(AF_FILE_NIST_SPHERE); }
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Large.cpp b/test/Large.cpp
new file mode 100644
index 0000000..652f023
--- /dev/null
+++ b/test/Large.cpp
@@ -0,0 +1,151 @@
+/*
+	Copyright (C) 2010-2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	This program tests writing and reading audio files with more
+	than 2^24 frames.
+
+	This program serves as a regression test for a bug in which
+	writing certain audio file formats with more than 2^24 frames
+	would produce files with incorrect sizes.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string>
+
+#include "TestUtilities.h"
+
+void testLargeFile(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	afFreeFileSetup(setup);
+	ASSERT_TRUE(file) << "Could not open file for writing";
+
+	const int bufferFrameCount = 32768;
+	int16_t *data = new int16_t[bufferFrameCount];
+	const AFframecount frameCount = 0x1000007;
+	AFframecount framesWritten = 0;
+	while (framesWritten < frameCount)
+	{
+		AFframecount framesToWrite = bufferFrameCount;
+		if (framesToWrite > frameCount - framesWritten)
+			framesToWrite = frameCount - framesWritten;
+		int dataValue = framesWritten % 32749;
+		for (int i=0; i<bufferFrameCount; i++, dataValue++)
+			data[i] = dataValue % 32749;
+		ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, data, framesToWrite),
+			framesToWrite);
+		framesWritten += framesToWrite;
+	}
+	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount) <<
+		"Incorrect frame count for file";
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
+	ASSERT_TRUE(file) << "Could not open file for reading";
+	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount) <<
+		"Incorrect frame count for file opened for reading";
+	ASSERT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
+		frameCount * sizeof (int16_t)) <<
+		"Incorrect byte size in file opened for reading";
+
+	AFframecount framesRead = 0;
+	while (framesRead < frameCount)
+	{
+		AFframecount framesToRead = bufferFrameCount;
+		if (framesToRead > frameCount - framesRead)
+			framesToRead = frameCount - framesRead;
+		afReadFrames(file, AF_DEFAULT_TRACK, data, framesToRead);
+		bool valid = true;
+		int dataValue = framesRead % 32749;
+		for (int i=0; i<framesToRead; i++, dataValue++)
+			if (data[i] != dataValue % 32749)
+			{
+				valid = false;
+				break;
+			}
+		ASSERT_TRUE(valid) << "Data read does not match data written";
+		framesRead += framesToRead;
+	}
+	delete [] data;
+	afCloseFile(file);
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(Large, AIFF)
+{
+	testLargeFile(AF_FILE_AIFF);
+}
+
+TEST(Large, AIFFC)
+{
+	testLargeFile(AF_FILE_AIFFC);
+}
+
+TEST(Large, NeXT)
+{
+	testLargeFile(AF_FILE_NEXTSND);
+}
+
+TEST(Large, WAVE)
+{
+	testLargeFile(AF_FILE_WAVE);
+}
+
+TEST(Large, IRCAM)
+{
+	testLargeFile(AF_FILE_IRCAM);
+}
+
+TEST(Large, AVR)
+{
+	testLargeFile(AF_FILE_AVR);
+}
+
+TEST(Large, CAF)
+{
+	testLargeFile(AF_FILE_CAF);
+}
+
+int main (int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Loop.cpp b/test/Loop.cpp
new file mode 100644
index 0000000..123e06a
--- /dev/null
+++ b/test/Loop.cpp
@@ -0,0 +1,140 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	Test that loops can be written to and read from an audio file.
+*/
+
+#include <audiofile.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+
+#include "TestUtilities.h"
+
+TEST(Loop, AIFF)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Loop", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	int markerIDs[] = { 1, 2, 3, 4 };
+	const int numMarkers = sizeof (markerIDs) / sizeof (int);
+	const char * const markerNames[numMarkers] =
+	{
+		"sustain loop start",
+		"sustain loop end",
+		"release loop start",
+		"release loop end"
+	};
+	const int markerPositions[] = { 0, 2, 4, 5 };
+	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, 4);
+	for (int i=0; i<numMarkers; i++)
+		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);
+
+	int loopIDs[] = {1, 2};
+	afInitLoopIDs(setup, AF_DEFAULT_INST, loopIDs, 2);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file) << "Could not open test file for writing";
+	afFreeFileSetup(setup);
+
+	const int frameCount = 5;
+	int16_t frames[frameCount] = {0};
+
+	EXPECT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, frames, frameCount),
+		frameCount);
+
+	for (int i=0; i<numMarkers; i++)
+		afSetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i], markerPositions[i]);
+
+	afSetLoopStart(file, AF_DEFAULT_INST, 1, 1);
+	afSetLoopEnd(file, AF_DEFAULT_INST, 1, 2);
+	afSetLoopStart(file, AF_DEFAULT_INST, 2, 3);
+	afSetLoopEnd(file, AF_DEFAULT_INST, 2, 4);
+
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file) << "Could not open test file for reading";
+
+	ASSERT_EQ(afGetLoopIDs(file, AF_DEFAULT_INST, NULL), 2);
+	int readLoopIDs[2];
+	afGetLoopIDs(file, AF_DEFAULT_INST, readLoopIDs);
+	for (int i=0; i<2; i++)
+		ASSERT_EQ(loopIDs[i], readLoopIDs[i]);
+
+	ASSERT_EQ(afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL), numMarkers);
+	int readMarkerIDs[numMarkers];
+	afGetMarkIDs(file, AF_DEFAULT_TRACK, readMarkerIDs);
+	for (int i=0; i<numMarkers; i++)
+		ASSERT_EQ(markerIDs[i], readMarkerIDs[i]);
+	
+	for (int i=0; i<numMarkers; i++)
+		ASSERT_TRUE(!strcmp(afGetMarkName(file, AF_DEFAULT_TRACK, markerIDs[i]),
+			markerNames[i]));
+
+	for (int i=0; i<numMarkers; i++)
+		ASSERT_EQ(afGetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i]),
+			markerPositions[i]);
+
+	ASSERT_EQ(afGetLoopStart(file, AF_DEFAULT_INST, 1), 1);
+	ASSERT_EQ(afGetLoopEnd(file, AF_DEFAULT_INST, 1), 2);
+	ASSERT_EQ(afGetLoopStart(file, AF_DEFAULT_INST, 2), 3);
+	ASSERT_EQ(afGetLoopEnd(file, AF_DEFAULT_INST, 2), 4);
+
+	ASSERT_TRUE(afGetLoopTrack(file, AF_DEFAULT_INST, 1) == AF_DEFAULT_TRACK);
+	ASSERT_TRUE(afGetLoopTrack(file, AF_DEFAULT_INST, 2) == AF_DEFAULT_TRACK);
+
+	ASSERT_EQ(afGetLoopStartFrame(file, AF_DEFAULT_INST, 1),
+		markerPositions[0]);
+	ASSERT_EQ(afGetLoopEndFrame(file, AF_DEFAULT_INST, 1),
+		markerPositions[1]);
+	ASSERT_EQ(afGetLoopStartFrame(file, AF_DEFAULT_INST, 2),
+		markerPositions[2]);
+	ASSERT_EQ(afGetLoopEndFrame(file, AF_DEFAULT_INST, 2),
+		markerPositions[3]);
+
+	afCloseFile(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Lossless.h b/test/Lossless.h
new file mode 100644
index 0000000..488f1ab
--- /dev/null
+++ b/test/Lossless.h
@@ -0,0 +1,163 @@
+/*
+	Audio File Library
+	Copyright (C) 2013 Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef Lossless_h
+#define Lossless_h
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+struct NaturalGenerator
+{
+	NaturalGenerator() : m_n(0)
+	{
+	}
+	int32_t operator() () { return ++m_n; }
+
+private:
+	int32_t m_n;
+};
+
+struct LinearCongruentialGenerator
+{
+	LinearCongruentialGenerator() : m_n(0)
+	{
+	}
+	int32_t operator() ()
+	{
+		m_n = 1664525 * m_n + 1013904223;
+		return static_cast<int32_t>(m_n);
+	}
+
+private:
+	uint32_t m_n;
+};
+
+static inline int32_t trim(int32_t n, int sampleWidth)
+{
+	unsigned shift = (((sampleWidth + 7) >> 3) << 3) - sampleWidth;
+	unsigned maskShift = 32 - sampleWidth;
+	n <<= shift;
+	return (n << maskShift) >> maskShift;
+}
+
+template <typename SampleType, typename Generator>
+static void testLossless(const char *prefix, int fileFormat,
+	int compressionFormat, int channelCount, int sampleWidth, int frameCount)
+{
+	SCOPED_TRACE(channelCount);
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile(prefix, &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+	afFreeFileSetup(setup);
+
+	Generator g;
+	SampleType *data = new SampleType[frameCount * channelCount];
+	for (int i=0; i<frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+			data[i*channelCount + c] = trim(g(), sampleWidth) * ((c&1) ? -1 : 1);
+
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(frameCount, framesWritten);
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
+	ASSERT_TRUE(file);
+	ASSERT_EQ(compressionFormat, afGetCompression(file, AF_DEFAULT_TRACK));
+	int readSampleFormat, readSampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &readSampleFormat, &readSampleWidth);
+	ASSERT_TRUE(AF_SAMPFMT_TWOSCOMP == readSampleFormat);
+	ASSERT_EQ(sampleWidth, readSampleWidth);
+	ASSERT_EQ(frameCount, afGetFrameCount(file, AF_DEFAULT_TRACK));
+
+	SampleType *readData = new SampleType[frameCount * channelCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(frameCount, framesRead);
+
+	for (int i=0; i<frameCount; i++)
+		for (int c=0; c<channelCount; c++)
+			EXPECT_EQ(data[i*channelCount + c], readData[i*channelCount + c]) <<
+				"failed at " << i;
+
+	// Read entire file with a seek before each read operation.
+	for (AFframecount offset = 0; offset < frameCount; offset += 373)
+	{
+		ASSERT_EQ(offset, afSeekFrame(file, AF_DEFAULT_TRACK, offset));
+
+		AFframecount framesToRead = 1091;
+		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, framesToRead);
+		ASSERT_EQ(std::min(framesToRead, frameCount - offset), framesRead);
+
+		for (int i=0; i<framesRead; i++)
+			for (int c=0; c<channelCount; c++)
+				EXPECT_EQ(data[(i+offset)*channelCount + c],
+					readData[i*channelCount + c]) << "failed at " << i;
+	}
+
+	// Read entire file sequentially in multiple read operations.
+	ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);
+
+	AFframecount framesToRead = 1087;
+	for (AFframecount offset = 0; offset < frameCount; offset += framesToRead)
+	{
+		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, framesToRead);
+		ASSERT_EQ(std::min(framesToRead, frameCount - offset), framesRead);
+
+		for (int i=0; i<framesRead; i++)
+			for (int c=0; c<channelCount; c++)
+				EXPECT_EQ(data[(i+offset)*channelCount + c],
+					readData[i*channelCount + c]) << "failed at " << i;
+	}
+
+	ASSERT_EQ(0, afCloseFile(file));
+
+	delete [] data;
+	delete [] readData;
+
+	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
+}
+
+template <typename SampleType>
+static void testLossless(const char *prefix, int fileFormat,
+	int compressionFormat, int channelCount, int sampleWidth, int frameCount)
+{
+	{
+		SCOPED_TRACE("Sequential");
+		testLossless<SampleType, NaturalGenerator>(prefix, fileFormat, compressionFormat, channelCount, sampleWidth, frameCount);
+	}
+	{
+		SCOPED_TRACE("Pseudo-random");
+		testLossless<SampleType, LinearCongruentialGenerator>(prefix, fileFormat, compressionFormat, channelCount, sampleWidth, frameCount);
+	}
+}
+
+#endif
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..78d4cd2
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,169 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile -I$(top_srcdir)
+
+TESTS = \
+	ADPCM \
+	AES \
+	ALAC \
+	ChannelMatrix \
+	Error \
+	FloatToInt \
+	FormatWithChannels \
+	Identify \
+	Instrument \
+	IntToFloat \
+	InvalidCompressionFormat \
+	InvalidSampleFormat \
+	Large \
+	Loop \
+	Marker \
+	Miscellaneous \
+	NeXT \
+	PCMData \
+	PCMMapping \
+	Pipe \
+	Query \
+	SampleFormat \
+	Seek \
+	Sign \
+	VirtualFile \
+	floatto24 \
+	query2 \
+	sixteen-to-eight \
+	testchannelmatrix \
+	testdouble \
+	testfloat \
+	testmarkers \
+	twentyfour \
+	twentyfour2 \
+	writealaw \
+	writeraw \
+	writeulaw
+
+if ENABLE_FLAC
+TESTS += FLAC
+endif
+
+check_PROGRAMS = \
+	$(TESTS) \
+	instparamtest \
+	instparamwrite \
+	printmarkers \
+	testaupv
+
+if ENABLE_VALGRIND
+VALGRIND_FLAGS = --quiet --leak-check=full --show-reachable=yes --error-exitcode=1
+TESTS_ENVIRONMENT = $(top_builddir)/libtool --mode=execute $(VALGRIND) $(VALGRIND_FLAGS)
+endif
+
+LIBAUDIOFILE = $(top_builddir)/libaudiofile/libaudiofile.la
+
+LDADD = $(LIBAUDIOFILE)
+
+DEPENDENCIES = $(LIBAUDIOFILE)
+
+LIBGTEST = ../gtest/libgtest.la
+
+ADPCM_SOURCES = ADPCM.cpp TestUtilities.cpp TestUtilities.h
+ADPCM_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+AES_SOURCES = AES.cpp TestUtilities.cpp TestUtilities.h
+AES_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+ALAC_SOURCES = ALAC.cpp Lossless.h TestUtilities.cpp TestUtilities.h
+ALAC_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+ChannelMatrix_SOURCES = ChannelMatrix.cpp TestUtilities.cpp TestUtilities.h
+ChannelMatrix_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Error_SOURCES = Error.cpp TestUtilities.cpp TestUtilities.h
+Error_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+FLAC_SOURCES = FLAC.cpp Lossless.h TestUtilities.cpp TestUtilities.h
+FLAC_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+FloatToInt_SOURCES = FloatToInt.cpp TestUtilities.cpp TestUtilities.h
+FloatToInt_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Identify_SOURCES = Identify.cpp TestUtilities.cpp TestUtilities.h
+Identify_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Instrument_SOURCES = Instrument.cpp TestUtilities.cpp TestUtilities.h
+Instrument_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+IntToFloat_SOURCES = IntToFloat.cpp TestUtilities.cpp TestUtilities.h
+IntToFloat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+FormatWithChannels_SOURCES = FormatWithChannels.cpp TestUtilities.cpp TestUtilities.h
+FormatWithChannels_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+InvalidCompressionFormat_SOURCES = InvalidCompressionFormat.cpp TestUtilities.cpp TestUtilities.h
+InvalidCompressionFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+InvalidSampleFormat_SOURCES = InvalidSampleFormat.cpp TestUtilities.cpp TestUtilities.h
+InvalidSampleFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Large_SOURCES = Large.cpp TestUtilities.cpp TestUtilities.h
+Large_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Loop_SOURCES = Loop.cpp TestUtilities.cpp TestUtilities.h
+Loop_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Marker_SOURCES = Marker.cpp TestUtilities.cpp TestUtilities.h
+Marker_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Miscellaneous_SOURCES = Miscellaneous.cpp TestUtilities.cpp TestUtilities.h
+Miscellaneous_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+NeXT_SOURCES = NeXT.cpp TestUtilities.cpp TestUtilities.h
+NeXT_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+PCMData_SOURCES = PCMData.cpp TestUtilities.cpp TestUtilities.h
+PCMData_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+PCMMapping_SOURCES = PCMMapping.cpp TestUtilities.cpp TestUtilities.h
+PCMMapping_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Pipe_SOURCES = Pipe.cpp TestUtilities.cpp TestUtilities.h
+Pipe_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Query_SOURCES = Query.cpp TestUtilities.cpp TestUtilities.h
+Query_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+SampleFormat_SOURCES = SampleFormat.cpp TestUtilities.cpp TestUtilities.h
+SampleFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Seek_SOURCES = Seek.cpp TestUtilities.cpp TestUtilities.h
+Seek_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+Sign_SOURCES = Sign.cpp TestUtilities.cpp TestUtilities.h
+Sign_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+VirtualFile_SOURCES = VirtualFile.cpp TestUtilities.cpp TestUtilities.h
+VirtualFile_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)
+
+floatto24_SOURCES = floatto24.c TestUtilities.cpp TestUtilities.h
+
+printmarkers_SOURCES = printmarkers.c
+printmarkers_LDADD = $(LIBAUDIOFILE) -lm
+
+sixteen_to_eight_SOURCES = sixteen-to-eight.c TestUtilities.cpp TestUtilities.h
+
+testchannelmatrix_SOURCES = testchannelmatrix.c TestUtilities.cpp TestUtilities.h
+
+testdouble_SOURCES = testdouble.c TestUtilities.cpp TestUtilities.h
+
+testfloat_SOURCES = testfloat.c TestUtilities.cpp TestUtilities.h
+
+testmarkers_SOURCES = testmarkers.c TestUtilities.cpp TestUtilities.h
+
+twentyfour_SOURCES = twentyfour.c TestUtilities.cpp TestUtilities.h
+
+twentyfour2_SOURCES = twentyfour2.c TestUtilities.cpp TestUtilities.h
+
+writealaw_SOURCES = writealaw.c TestUtilities.cpp TestUtilities.h
+
+writeraw_SOURCES = writeraw.c TestUtilities.cpp TestUtilities.h
+
+writeulaw_SOURCES = writeulaw.c TestUtilities.cpp TestUtilities.h
+
+AM_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
diff --git a/test/Marker.cpp b/test/Marker.cpp
new file mode 100644
index 0000000..6191191
--- /dev/null
+++ b/test/Marker.cpp
@@ -0,0 +1,169 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static void testMarkers(int fileFormat, bool supportsComments)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Marker", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	const int markerIDs[] = { 1, 2, 3, 5, 8 };
+	const int numMarkers = sizeof (markerIDs) / sizeof (int);
+	const char * const markerNames[numMarkers] =
+	{
+		"one",
+		"two",
+		"three",
+		"five",
+		"eight"
+	};
+	const char * const markerComments[numMarkers] =
+	{
+		"comment one",
+		"comment two",
+		"comment three",
+		"comment five",
+		"comment eight"
+	};
+	const int markerPositions[numMarkers] = { 1, 2, 3, 5, 8 };
+	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, numMarkers);
+	for (int i=0; i<numMarkers; i++)
+		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);
+
+	for (int i=0; i<numMarkers; i++)
+		afInitMarkComment(setup, AF_DEFAULT_TRACK, markerIDs[i], markerComments[i]);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file) << "Could not open test file for writing";
+	afFreeFileSetup(setup);
+
+	const int frameCount = 10;
+	int16_t frames[frameCount] = {0};
+
+	EXPECT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, frames, frameCount),
+		frameCount);
+
+	for (int i=0; i<numMarkers; i++)
+		afSetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i], markerPositions[i]);
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file) << "Could not open test file for reading";
+	EXPECT_EQ(afGetFileFormat(file, NULL), fileFormat);
+
+	ASSERT_EQ(afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL), numMarkers);
+	int readMarkerIDs[numMarkers];
+	afGetMarkIDs(file, AF_DEFAULT_TRACK, readMarkerIDs);
+	for (int i=0; i<numMarkers; i++)
+		EXPECT_EQ(markerIDs[i], readMarkerIDs[i]);
+	
+	for (int i=0; i<numMarkers; i++)
+		EXPECT_TRUE(!strcmp(afGetMarkName(file, AF_DEFAULT_TRACK, markerIDs[i]),
+			markerNames[i]));
+
+	for (int i=0; i<numMarkers; i++)
+	{
+		const char *comment = afGetMarkComment(file, AF_DEFAULT_TRACK,
+			markerIDs[i]);
+		if (supportsComments)
+			EXPECT_TRUE(!strcmp(comment, markerComments[i]));
+	}
+
+	for (int i=0; i<numMarkers; i++)
+		EXPECT_EQ(afGetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i]),
+			markerPositions[i]);
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(Marker, AIFF)
+{
+	testMarkers(AF_FILE_AIFF, false);
+}
+
+TEST(Marker, AIFC)
+{
+	testMarkers(AF_FILE_AIFFC, false);
+}
+
+TEST(Marker, WAVE)
+{
+	testMarkers(AF_FILE_WAVE, true);
+}
+
+static void testUnsupported(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Marker", &testFileName));
+
+	AFerrfunc errorHandler = afSetErrorHandler(NULL);
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+
+	const int markerIDs[] = { 1 };
+	const int numMarkers = sizeof (markerIDs) / sizeof (int);
+	const char * const markerNames[numMarkers] = { "name" };
+	const char * const markerComments[numMarkers] = { "comment" };
+	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, numMarkers);
+	for (int i=0; i<numMarkers; i++)
+		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);
+
+	for (int i=0; i<numMarkers; i++)
+		afInitMarkComment(setup, AF_DEFAULT_TRACK, markerIDs[i], markerComments[i]);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file) << "Did not expect opening test file for writing to succeed";
+	afFreeFileSetup(setup);
+
+	afSetErrorHandler(errorHandler);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(Unsupported, Raw) { testUnsupported(AF_FILE_RAWDATA); }
+TEST(Unsupported, NeXT) { testUnsupported(AF_FILE_NEXTSND); }
+TEST(Unsupported, IRCAM) { testUnsupported(AF_FILE_IRCAM); }
+TEST(Unsupported, AVR) { testUnsupported(AF_FILE_AVR); }
+TEST(Unsupported, IFF) { testUnsupported(AF_FILE_IFF_8SVX); }
+TEST(Unsupported, SampleVision) { testUnsupported(AF_FILE_SAMPLEVISION); }
+TEST(Unsupported, VOC) { testUnsupported(AF_FILE_VOC); }
+TEST(Unsupported, NIST) { testUnsupported(AF_FILE_NIST_SPHERE); }
+TEST(Unsupported, CAF) { testUnsupported(AF_FILE_CAF); }
+TEST(Unsupported, FLAC) { testUnsupported(AF_FILE_FLAC); }
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Miscellaneous.cpp b/test/Miscellaneous.cpp
new file mode 100644
index 0000000..ee08029
--- /dev/null
+++ b/test/Miscellaneous.cpp
@@ -0,0 +1,170 @@
+/*
+	Copyright (C) 2011-2014, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+struct Miscellaneous
+{
+	int id;
+	int type;
+	const char *data;
+};
+
+const Miscellaneous kMiscellaneous[] =
+{
+	{ 1, AF_MISC_COPY, "1806 Ludwig van Beethoven" },
+	{ 2, AF_MISC_NAME, "Violin Concerto in D major" }
+};
+
+const int kNumMiscellaneous = sizeof (kMiscellaneous) / sizeof (Miscellaneous);
+
+void writeMiscellaneous(int fileFormat, const std::string &testFileName)
+{
+	AFfilesetup setup = afNewFileSetup();
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitFileFormat(setup, fileFormat);
+	int *miscIDs = new int[kNumMiscellaneous];
+	for (int i=0; i<kNumMiscellaneous; i++)
+		miscIDs[i] = kMiscellaneous[i].id;
+	afInitMiscIDs(setup, miscIDs, kNumMiscellaneous);
+	delete [] miscIDs;
+	for (int i=0; i<kNumMiscellaneous; i++)
+	{
+		afInitMiscType(setup, kMiscellaneous[i].id, kMiscellaneous[i].type);
+		afInitMiscSize(setup, kMiscellaneous[i].id, strlen(kMiscellaneous[i].data));
+	}
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+	afFreeFileSetup(setup);
+	for (int i=0; i<kNumMiscellaneous; i++)
+	{
+		int result = afWriteMisc(file, kMiscellaneous[i].id,
+			kMiscellaneous[i].data,
+			strlen(kMiscellaneous[i].data));
+		EXPECT_EQ(strlen(kMiscellaneous[i].data), result);
+	}
+
+	const int16_t samples[] = { 1, 2, 3, 4 };
+	const int sampleCount = sizeof (samples) / sizeof (samples[0]);
+	EXPECT_EQ(sampleCount, afWriteFrames(file, AF_DEFAULT_TRACK, samples, sampleCount));
+	ASSERT_EQ(0, afCloseFile(file));
+}
+
+void readMiscellaneous(const std::string &testFileName)
+{
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file);
+	int count = afGetMiscIDs(file, NULL);
+	EXPECT_EQ(count, kNumMiscellaneous);
+	int miscIDs[kNumMiscellaneous];
+	afGetMiscIDs(file, miscIDs);
+	for (int i=0; i<kNumMiscellaneous; i++)
+		EXPECT_EQ(miscIDs[i], kMiscellaneous[i].id);
+	for (int i=0; i<kNumMiscellaneous; i++)
+	{
+		int misctype = afGetMiscType(file, miscIDs[i]);
+		EXPECT_EQ(misctype, kMiscellaneous[i].type);
+
+		int datasize = afGetMiscSize(file, miscIDs[i]);
+		EXPECT_EQ(datasize, strlen(kMiscellaneous[i].data));
+
+		char *data = new char[datasize];
+		EXPECT_EQ(datasize, afReadMisc(file, miscIDs[i], data, datasize));
+
+		EXPECT_TRUE(!memcmp(data, kMiscellaneous[i].data, datasize));
+
+		delete [] data;
+	}
+	ASSERT_EQ(0, afCloseFile(file));
+}
+
+void testMiscellaneous(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Miscellaneous", &testFileName));
+	writeMiscellaneous(fileFormat, testFileName);
+	readMiscellaneous(testFileName);
+	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
+}
+
+TEST(Miscellaneous, AIFF) { testMiscellaneous(AF_FILE_AIFF); }
+TEST(Miscellaneous, AIFFC) { testMiscellaneous(AF_FILE_AIFFC); }
+TEST(Miscellaneous, WAVE) { testMiscellaneous(AF_FILE_WAVE); }
+TEST(Miscellaneous, IFF_8SVX) { testMiscellaneous(AF_FILE_IFF_8SVX); }
+
+void testMiscellaneousUnsupported(int fileFormat)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Miscellaneous", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitFileFormat(setup, fileFormat);
+	int *miscIDs = new int[kNumMiscellaneous];
+	for (int i=0; i<kNumMiscellaneous; i++)
+		miscIDs[i] = kMiscellaneous[i].id;
+	afInitMiscIDs(setup, miscIDs, kNumMiscellaneous);
+	delete [] miscIDs;
+	for (int i=0; i<kNumMiscellaneous; i++)
+	{
+		afInitMiscType(setup, kMiscellaneous[i].id, kMiscellaneous[i].type);
+		afInitMiscSize(setup, kMiscellaneous[i].id, strlen(kMiscellaneous[i].data));
+	}
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_FALSE(file);
+	afFreeFileSetup(setup);
+
+	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
+}
+
+TEST(Miscellaneous, Raw) { testMiscellaneousUnsupported(AF_FILE_RAWDATA); }
+TEST(Miscellaneous, NeXT) { testMiscellaneousUnsupported(AF_FILE_NEXTSND); }
+TEST(Miscellaneous, IRCAM) { testMiscellaneousUnsupported(AF_FILE_IRCAM); }
+TEST(Miscellaneous, AVR) { testMiscellaneousUnsupported(AF_FILE_AVR); }
+TEST(Miscellaneous, SampleVision) { testMiscellaneousUnsupported(AF_FILE_SAMPLEVISION); }
+TEST(Miscellaneous, VOC) { testMiscellaneousUnsupported(AF_FILE_VOC); }
+TEST(Miscellaneous, NIST) { testMiscellaneousUnsupported(AF_FILE_NIST_SPHERE); }
+TEST(Miscellaneous, CAF) { testMiscellaneousUnsupported(AF_FILE_CAF); }
+TEST(Miscellaneous, FLAC) { testMiscellaneousUnsupported(AF_FILE_FLAC); }
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/NeXT.cpp b/test/NeXT.cpp
new file mode 100644
index 0000000..242788c
--- /dev/null
+++ b/test/NeXT.cpp
@@ -0,0 +1,189 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+
+#include "TestUtilities.h"
+
+const uint8_t kDataUnspecifiedLength[] =
+{
+	'.', 's', 'n', 'd',
+	0, 0, 0, 24, // offset of 24 bytes
+	0xff, 0xff, 0xff, 0xff, // unspecified length
+	0, 0, 0, 3, // 16-bit linear
+	0, 0, 172, 68, // 44100 Hz
+	0, 0, 0, 1, // 1 channel
+	0, 1,
+	0, 1,
+	0, 2,
+	0, 3,
+	0, 5,
+	0, 8,
+	0, 13,
+	0, 21,
+	0, 34,
+	0, 55
+};
+
+const uint8_t kDataTruncated[] =
+{
+	'.', 's', 'n', 'd',
+	0, 0, 0, 24, // offset of 24 bytes
+	0, 0, 0, 20, // length of 20 bytes
+	0, 0, 0, 3, // 16-bit linear
+	0, 0, 172, 68, // 44100 Hz
+	0, 0, 0, 1, // 1 channel
+	0, 1,
+	0, 1,
+	0, 2,
+	0, 3,
+	0, 5,
+	0, 8,
+	0, 13,
+	0, 21,
+	0, 34,
+	0, 55
+};
+
+const int16_t kFrames[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
+const int kFrameCount = sizeof (kFrames) / sizeof (kFrames[0]);
+
+TEST(NeXT, UnspecifiedLength)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));
+
+	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ASSERT_GT(fd, -1);
+	ASSERT_EQ(::write(fd, kDataUnspecifiedLength, sizeof (kDataUnspecifiedLength)), sizeof (kDataUnspecifiedLength));
+	::close(fd);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
+	EXPECT_TRUE(file);
+
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	EXPECT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	EXPECT_EQ(sampleWidth, 16);
+	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
+	EXPECT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
+		kFrameCount * sizeof (int16_t));
+	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), kFrameCount);
+
+	int16_t *data = new int16_t[kFrameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, data,
+		kFrameCount);
+	EXPECT_EQ(framesRead, kFrameCount);
+	for (int i=0; i<kFrameCount; i++)
+		EXPECT_EQ(data[i], kFrames[i]);
+	delete [] data;
+
+	afCloseFile(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(NeXT, Truncated)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));
+
+	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ASSERT_GT(fd, -1);
+	const size_t truncatedSize = sizeof (kDataTruncated) - 4;
+	const int truncatedFrameCount = kFrameCount - 2;
+	ASSERT_EQ(::write(fd, kDataTruncated, truncatedSize), truncatedSize);
+	::close(fd);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
+	EXPECT_TRUE(file);
+
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	EXPECT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	EXPECT_EQ(sampleWidth, 16);
+	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
+	EXPECT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
+		truncatedFrameCount * sizeof (int16_t));
+	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), truncatedFrameCount);
+
+	int16_t *data = new int16_t[truncatedFrameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, data,
+		truncatedFrameCount);
+	EXPECT_EQ(framesRead, truncatedFrameCount);
+	for (int i=0; i<truncatedFrameCount; i++)
+		EXPECT_EQ(data[i], kFrames[i]);
+	delete [] data;
+
+	afCloseFile(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+const uint8_t kDataZeroChannels[] =
+{
+	'.', 's', 'n', 'd',
+	0, 0, 0, 24, // offset of 24 bytes
+	0, 0, 0, 2, // 2 bytes
+	0, 0, 0, 3, // 16-bit linear
+	0, 0, 172, 68, // 44100 Hz
+	0, 0, 0, 0, // 0 channels
+	0, 1
+};
+
+TEST(NeXT, ZeroChannels)
+{
+	IgnoreErrors ignoreErrors;
+
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));
+
+	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ASSERT_GT(fd, -1);
+	ASSERT_EQ(::write(fd, kDataZeroChannels, sizeof (kDataZeroChannels)), sizeof (kDataZeroChannels));
+	::close(fd);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
+	EXPECT_FALSE(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/PCMData.cpp b/test/PCMData.cpp
new file mode 100644
index 0000000..752dc4a
--- /dev/null
+++ b/test/PCMData.cpp
@@ -0,0 +1,282 @@
+/*
+	Copyright (C) 2011-2013 Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	For each supported file format, test reading and writing audio
+	files with all applicable PCM audio data formats.
+*/
+
+#include <audiofile.h>
+#include <climits>
+#include <cmath>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+struct PCMMapping
+{
+	double slope, intercept, minClip, maxClip;
+};
+
+void getDefaultPCMMapping(int sampleFormat, int bitsPerSample, PCMMapping &m)
+{
+	switch (sampleFormat)
+	{
+		case AF_SAMPFMT_TWOSCOMP:
+		{
+			double s = std::pow(2.0, bitsPerSample - 1);
+			m.slope = s;
+			m.intercept = 0;
+			m.minClip = -s;
+			m.maxClip = s - 1;
+			break;
+		}
+		case AF_SAMPFMT_UNSIGNED:
+		{
+			double s = std::pow(2.0, bitsPerSample - 1);
+			m.slope = s;
+			m.intercept = s;
+			m.minClip = 0;
+			m.maxClip = 2 * s - 1;
+			break;
+		}
+		case AF_SAMPFMT_FLOAT:
+		case AF_SAMPFMT_DOUBLE:
+			m.slope = 1;
+			m.intercept = 0;
+			m.minClip = 0;
+			m.maxClip = 0;
+			break;
+	}
+}
+
+template <typename T, int kSampleFormat, int kBitsPerSample>
+void runTestWithChannels(int fileFormat, int channelCount)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("PCMData", &testFileName));
+
+	const int numFrames = 20;
+	const int numSamples = numFrames * channelCount;
+	T samples[numSamples];
+	for (int i=0; i<numFrames; i++)
+		for (int c=0; c<channelCount; c++)
+			samples[i*channelCount + c] = static_cast<T>(i*i + 3*c + 1);
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, kSampleFormat, kBitsPerSample);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file) << "Could not open file for writing";
+
+	afFreeFileSetup(setup);
+
+	PCMMapping mapping, defaultMapping;
+	getDefaultPCMMapping(kSampleFormat, kBitsPerSample, defaultMapping);
+
+	afGetPCMMapping(file, AF_DEFAULT_TRACK,
+		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
+	ASSERT_EQ(mapping.slope, defaultMapping.slope);
+	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
+	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
+	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);
+
+	afGetVirtualPCMMapping(file, AF_DEFAULT_TRACK,
+		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
+	ASSERT_EQ(mapping.slope, defaultMapping.slope);
+	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
+	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
+	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);
+
+	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numFrames),
+		numFrames) <<
+		"Number of frames written does not match number of frames requested";
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file) << "Could not open file for reading";
+
+	ASSERT_EQ(afGetFileFormat(file, NULL), fileFormat) <<
+		"Incorrect file format";
+
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ASSERT_EQ(sampleFormat, kSampleFormat) << "Incorrect sample format";
+	ASSERT_EQ(sampleWidth, kBitsPerSample) << "Incorrect sample width";
+
+	ASSERT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), channelCount) <<
+		"Incorrect number of channels";
+
+	afGetPCMMapping(file, AF_DEFAULT_TRACK,
+		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
+	ASSERT_EQ(mapping.slope, defaultMapping.slope);
+	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
+	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
+	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);
+
+	afGetVirtualPCMMapping(file, AF_DEFAULT_TRACK,
+		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
+	ASSERT_EQ(mapping.slope, defaultMapping.slope);
+	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
+	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
+	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);
+
+	T *samplesRead = new T[numSamples];
+	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, samplesRead, numFrames),
+		numFrames) <<
+		"Number of frames read does not match number of frames requested";
+
+	for (int i=0; i<numSamples; i++)
+		ASSERT_EQ(samplesRead[i], samples[i]) <<
+			"Data read from file does not match data written";
+
+	delete [] samplesRead;
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+template <typename T, int kSampleFormat, int kBitsPerSample>
+void runTest(int fileFormat)
+{
+	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 1);
+	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 2);
+	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 4);
+}
+
+void testInt8(int fileFormat)
+{
+	runTest<int8_t, AF_SAMPFMT_TWOSCOMP, 8>(fileFormat);
+}
+
+void testInt8MonoOnly(int fileFormat)
+{
+	runTestWithChannels<int8_t, AF_SAMPFMT_TWOSCOMP, 8>(fileFormat, 1);
+}
+
+void testUInt8(int fileFormat)
+{
+	runTest<uint8_t, AF_SAMPFMT_UNSIGNED, 8>(fileFormat);
+}
+
+void testInt16(int fileFormat)
+{
+	runTest<int16_t, AF_SAMPFMT_TWOSCOMP, 16>(fileFormat);
+}
+
+void testInt16MonoOnly(int fileFormat)
+{
+	runTestWithChannels<int16_t, AF_SAMPFMT_TWOSCOMP, 16>(fileFormat, 1);
+}
+
+void testInt24(int fileFormat)
+{
+	runTest<int32_t, AF_SAMPFMT_TWOSCOMP, 24>(fileFormat);
+}
+
+void testInt32(int fileFormat)
+{
+	runTest<int32_t, AF_SAMPFMT_TWOSCOMP, 32>(fileFormat);
+}
+
+void testFloat32(int fileFormat)
+{
+	runTest<float, AF_SAMPFMT_FLOAT, 32>(fileFormat);
+}
+
+void testFloat64(int fileFormat)
+{
+	runTest<double, AF_SAMPFMT_DOUBLE, 64>(fileFormat);
+}
+
+TEST(AIFF, Int8) { testInt8(AF_FILE_AIFF); }
+TEST(AIFF, Int16) { testInt16(AF_FILE_AIFF); }
+TEST(AIFF, Int24) { testInt24(AF_FILE_AIFF); }
+TEST(AIFF, Int32) { testInt32(AF_FILE_AIFF); }
+
+TEST(AIFFC, Int8) { testInt8(AF_FILE_AIFFC); }
+TEST(AIFFC, Int16) { testInt16(AF_FILE_AIFFC); }
+TEST(AIFFC, Int24) { testInt24(AF_FILE_AIFFC); }
+TEST(AIFFC, Int32) { testInt32(AF_FILE_AIFFC); }
+TEST(AIFFC, Float) { testFloat32(AF_FILE_AIFFC); }
+TEST(AIFFC, Double) { testFloat64(AF_FILE_AIFFC); }
+
+TEST(WAVE, UInt8) { testUInt8(AF_FILE_WAVE); }
+TEST(WAVE, Int16) { testInt16(AF_FILE_WAVE); }
+TEST(WAVE, Int24) { testInt24(AF_FILE_WAVE); }
+TEST(WAVE, Int32) { testInt32(AF_FILE_WAVE); }
+TEST(WAVE, Float) { testFloat32(AF_FILE_WAVE); }
+TEST(WAVE, Double) { testFloat64(AF_FILE_WAVE); }
+
+TEST(NeXT, Int8) { testInt8(AF_FILE_NEXTSND); }
+TEST(NeXT, Int16) { testInt16(AF_FILE_NEXTSND); }
+TEST(NeXT, Int24) { testInt24(AF_FILE_NEXTSND); }
+TEST(NeXT, Int32) { testInt32(AF_FILE_NEXTSND); }
+TEST(NeXT, Float) { testFloat32(AF_FILE_NEXTSND); }
+TEST(NeXT, Double) { testFloat64(AF_FILE_NEXTSND); }
+
+TEST(IRCAM, Int8) { testInt8(AF_FILE_IRCAM); }
+TEST(IRCAM, Int16) { testInt16(AF_FILE_IRCAM); }
+TEST(IRCAM, Int24) { testInt24(AF_FILE_IRCAM); }
+TEST(IRCAM, Int32) { testInt32(AF_FILE_IRCAM); }
+TEST(IRCAM, Float) { testFloat32(AF_FILE_IRCAM); }
+TEST(IRCAM, Double) { testFloat64(AF_FILE_IRCAM); }
+
+TEST(IFF, Int8) { testInt8MonoOnly(AF_FILE_IFF_8SVX); }
+
+TEST(AVR, Int8) { testInt8MonoOnly(AF_FILE_AVR); }
+TEST(AVR, Int16) { testInt16MonoOnly(AF_FILE_AVR); }
+
+TEST(SampleVision, Int16) { testInt16MonoOnly(AF_FILE_SAMPLEVISION); }
+
+TEST(VOC, UInt8) { testUInt8(AF_FILE_VOC); }
+TEST(VOC, Int16) { testInt16(AF_FILE_VOC); }
+
+TEST(NIST, Int16) { testInt16(AF_FILE_NIST_SPHERE); }
+
+TEST(CAF, Int8) { testInt8(AF_FILE_CAF); }
+TEST(CAF, Int16) { testInt16(AF_FILE_CAF); }
+TEST(CAF, Int24) { testInt24(AF_FILE_CAF); }
+TEST(CAF, Int32) { testInt32(AF_FILE_CAF); }
+TEST(CAF, Float) { testFloat32(AF_FILE_CAF); }
+TEST(CAF, Double) { testFloat64(AF_FILE_CAF); }
+
+int main (int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/PCMMapping.cpp b/test/PCMMapping.cpp
new file mode 100644
index 0000000..6053731
--- /dev/null
+++ b/test/PCMMapping.cpp
@@ -0,0 +1,116 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <limits>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+class PCMMappingTest : public testing::Test
+{
+protected:
+	virtual void SetUp()
+	{
+		ASSERT_TRUE(createTemporaryFile("PCMMapping", &m_testFileName));
+	}
+	virtual void TearDown()
+	{
+		::unlink(m_testFileName.c_str());
+	}
+
+	AFfilehandle createTestFile(int sampleFormat, int sampleWidth)
+	{
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
+		afFreeFileSetup(setup);
+		return file;
+	}
+	AFfilehandle openTestFile()
+	{
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
+		return file;
+	}
+
+private:
+	std::string m_testFileName;
+};
+
+TEST_F(PCMMappingTest, Float)
+{
+	AFfilehandle file = createTestFile(AF_SAMPFMT_FLOAT, 32);
+	const float data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	double slope = 2, intercept = 2, minClip = 0, maxClip = 4;
+	afSetVirtualPCMMapping(file, AF_DEFAULT_TRACK, slope, intercept, minClip, maxClip);
+	float readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const float expectedData[] = { 0, 2, 4 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+TEST_F(PCMMappingTest, Double)
+{
+	AFfilehandle file = createTestFile(AF_SAMPFMT_DOUBLE, 64);
+	const double data[] = { -1, 0, 1 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile();
+	ASSERT_TRUE(file != NULL);
+	double slope = 2, intercept = 2, minClip = 0, maxClip = 4;
+	afSetVirtualPCMMapping(file, AF_DEFAULT_TRACK, slope, intercept, minClip, maxClip);
+	double readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const double expectedData[] = { 0, 2, 4 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Pipe.cpp b/test/Pipe.cpp
new file mode 100644
index 0000000..d35298a
--- /dev/null
+++ b/test/Pipe.cpp
@@ -0,0 +1,85 @@
+/*
+	Copyright (C) 2012, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+#include <audiofile.h>
+
+TEST(Pipe, Pipe)
+{
+	const int kFrameCount = 500;
+	const int kSampleCount = 2 * kFrameCount;
+
+	int16_t data[kSampleCount];
+	int16_t readData[kSampleCount];
+
+	for (int i=0; i<kSampleCount; i++)
+		data[i] = 3*i + 2;
+
+	AFfilesetup setup = afNewFileSetup();
+	ASSERT_TRUE(setup);
+
+	afInitFileFormat(setup, AF_FILE_RAWDATA);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
+	afInitRate(setup, AF_DEFAULT_TRACK, 44100);
+
+	int pipefd[2];
+	ASSERT_GE(::pipe(pipefd), 0);
+
+	AFfilehandle handle;
+
+	// Write into pipe.
+	handle = afOpenFD(pipefd[1], "w", setup);
+	ASSERT_TRUE(handle);
+	AFframecount framesWritten;
+	framesWritten = afWriteFrames(handle, AF_DEFAULT_TRACK, data, kFrameCount);
+	ASSERT_EQ(framesWritten, kFrameCount);
+	ASSERT_EQ(afCloseFile(handle), 0);
+
+	// Read from pipe.
+	handle = afOpenFD(pipefd[0], "r", setup);
+	ASSERT_TRUE(handle);
+	AFframecount framesRead;
+	framesRead = afReadFrames(handle, AF_DEFAULT_TRACK, readData, kFrameCount);
+	ASSERT_EQ(framesRead, kFrameCount);
+	ASSERT_TRUE(!::memcmp(readData, data, kFrameCount * sizeof (int16_t))) <<
+		"Data read does not match data written";
+	ASSERT_EQ(afCloseFile(handle), 0);
+
+	afFreeFileSetup(setup);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Query.cpp b/test/Query.cpp
new file mode 100644
index 0000000..01e603f
--- /dev/null
+++ b/test/Query.cpp
@@ -0,0 +1,131 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+TEST(Query, FileFormats)
+{
+	IgnoreErrors ignoreErrors;
+
+	int fileFormats[] =
+	{
+		AF_FILE_UNKNOWN,
+		AF_FILE_RAWDATA,
+		AF_FILE_AIFFC,
+		AF_FILE_AIFF,
+		AF_FILE_NEXTSND,
+		AF_FILE_WAVE,
+		AF_FILE_BICSF,
+		AF_FILE_MPEG1BITSTREAM,
+		AF_FILE_SOUNDDESIGNER1,
+		AF_FILE_SOUNDDESIGNER2,
+		AF_FILE_AVR,
+		AF_FILE_IFF_8SVX,
+		AF_FILE_SAMPLEVISION,
+		AF_FILE_VOC,
+		AF_FILE_NIST_SPHERE,
+		AF_FILE_SOUNDFONT2,
+		AF_FILE_CAF
+	};
+	int numFileFormats = sizeof (fileFormats) / sizeof (int);
+	for (int i=0; i<numFileFormats; i++)
+	{
+		long implemented = afQueryLong(AF_QUERYTYPE_FILEFMT,
+			AF_QUERY_IMPLEMENTED, fileFormats[i], 0, 0);
+		const char *label =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
+				AF_QUERY_LABEL, fileFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(label);
+		const char *name =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
+				AF_QUERY_NAME, fileFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(name);
+		const char *description =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
+				AF_QUERY_DESC, fileFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(description);
+	}
+}
+
+TEST(Query, CompressionFormats)
+{
+	IgnoreErrors ignoreErrors;
+
+	int compressionFormats[] =
+	{
+		AF_COMPRESSION_NONE,
+		AF_COMPRESSION_G711_ULAW,
+		AF_COMPRESSION_G711_ALAW,
+		AF_COMPRESSION_IMA,
+		AF_COMPRESSION_MS_ADPCM,
+		AF_COMPRESSION_G722,
+		AF_COMPRESSION_APPLE_ACE2,
+		AF_COMPRESSION_APPLE_ACE8,
+		AF_COMPRESSION_APPLE_MAC3,
+		AF_COMPRESSION_APPLE_MAC6
+	};
+	int numCompressionFormats = sizeof (compressionFormats) / sizeof (int);
+	for (int i=0; i<numCompressionFormats; i++)
+	{
+		long implemented = afQueryLong(AF_QUERYTYPE_COMPRESSION,
+			AF_QUERY_IMPLEMENTED, compressionFormats[i], 0, 0);
+		long nativeSampleFormat = afQueryLong(AF_QUERYTYPE_COMPRESSION,
+			AF_QUERY_NATIVE_SAMPFMT, compressionFormats[i], 0, 0);
+		if (implemented)
+			EXPECT_TRUE(nativeSampleFormat == AF_SAMPFMT_TWOSCOMP ||
+				nativeSampleFormat == AF_SAMPFMT_UNSIGNED ||
+				nativeSampleFormat == AF_SAMPFMT_FLOAT ||
+				nativeSampleFormat == AF_SAMPFMT_DOUBLE);
+		long nativeSampleWidth = afQueryLong(AF_QUERYTYPE_COMPRESSION,
+			AF_QUERY_NATIVE_SAMPWIDTH, compressionFormats[i], 0, 0);
+		if (implemented)
+		{
+			EXPECT_GE(nativeSampleWidth, 1);
+			EXPECT_LE(nativeSampleWidth, 64);
+		}
+		const char *label =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
+				AF_QUERY_LABEL, compressionFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(label);
+		const char *name =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
+				AF_QUERY_NAME, compressionFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(name);
+		const char *description =
+			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
+				AF_QUERY_DESC, compressionFormats[i], 0, 0));
+		if (implemented)
+			EXPECT_TRUE(description);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/SampleFormat.cpp b/test/SampleFormat.cpp
new file mode 100644
index 0000000..a7eae82
--- /dev/null
+++ b/test/SampleFormat.cpp
@@ -0,0 +1,80 @@
+/*
+	Audio File Library
+	Copyright (C) 2013, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+TEST(SampleFormat, NullArguments)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("SampleFormat", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFFC);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file);
+	afFreeFileSetup(setup);
+
+	int sampleFormat, sampleWidth;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	ASSERT_EQ(sampleWidth, 16);
+
+	sampleFormat = -1;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, NULL, &sampleWidth);
+	ASSERT_EQ(sampleFormat, -1);
+	ASSERT_EQ(sampleWidth, 16);
+
+	sampleWidth = -1;
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, NULL);
+	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	ASSERT_EQ(sampleWidth, -1);
+
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	ASSERT_EQ(sampleWidth, 16);
+
+	sampleFormat = -1;
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, NULL, &sampleWidth);
+	ASSERT_EQ(sampleFormat, -1);
+	ASSERT_EQ(sampleWidth, 16);
+
+	sampleWidth = -1;
+	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, NULL);
+	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
+	ASSERT_EQ(sampleWidth, -1);
+
+	ASSERT_EQ(afCloseFile(file), 0);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Seek.cpp b/test/Seek.cpp
new file mode 100644
index 0000000..a2b7678
--- /dev/null
+++ b/test/Seek.cpp
@@ -0,0 +1,113 @@
+/*
+	Copyright (C) 2003, 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+	This program tests seeking within an audio file.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <stdlib.h>
+#include <string>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+TEST(Seek, Seek)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("Seek", &testFileName));
+
+	const int kFrameCount = 2000;
+	const int kPadFrameCount = kFrameCount + 5;
+	const int kDataLength = kFrameCount * sizeof (int16_t);
+
+	int16_t data[kFrameCount];
+	int16_t readData[kPadFrameCount];
+
+	AFfilesetup setup = afNewFileSetup();
+	ASSERT_TRUE(setup);
+
+	afInitFileFormat(setup, AF_FILE_AIFF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file) << "could not open file for writing";
+
+	afFreeFileSetup(setup);
+
+	/* Initialize data to a nontrivial test pattern. */
+	for (int i=0; i<kFrameCount; i++)
+	{
+		if ((i%2) != 0)
+			data[i] = i;
+		else
+			data[i] = -i;
+	}
+
+	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, data, kFrameCount),
+		kFrameCount);
+
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
+	ASSERT_TRUE(file) << "Could not open file for reading";
+
+	/*
+		For each position in the file, seek to that position and
+		read to the end of the file, checking that the data read
+		matches the data written.
+	*/
+	for (int i=0; i<kFrameCount; i++)
+	{
+		memset(readData, 0, kDataLength);
+
+		AFfileoffset currentposition = afSeekFrame(file, AF_DEFAULT_TRACK, i);
+		ASSERT_EQ(currentposition, i) << "Incorrect seek position";
+
+		AFframecount framesread = afReadFrames(file, AF_DEFAULT_TRACK,
+			readData + i, kPadFrameCount);
+		ASSERT_EQ(framesread, kFrameCount - i) <<
+			"Incorrect number of frames read";
+
+		ASSERT_TRUE(!memcmp(data + i, readData + i,
+			framesread * sizeof (int16_t))) <<
+			"Error in data read";
+	}
+
+	afCloseFile(file);
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main (int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/Sign.cpp b/test/Sign.cpp
new file mode 100644
index 0000000..7275399
--- /dev/null
+++ b/test/Sign.cpp
@@ -0,0 +1,169 @@
+/*
+	Copyright (C) 2010, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <limits>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+class SignConversionTest : public testing::Test
+{
+protected:
+	virtual void SetUp()
+	{
+		ASSERT_TRUE(createTemporaryFile("Sign", &m_testFileName));
+	}
+	virtual void TearDown()
+	{
+		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
+	}
+
+	AFfilehandle createTestFile(int sampleWidth)
+	{
+		AFfilesetup setup = afNewFileSetup();
+		afInitFileFormat(setup, AF_FILE_AIFFC);
+		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
+		afFreeFileSetup(setup);
+		return file;
+	}
+	AFfilehandle openTestFile(int sampleWidth)
+	{
+		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
+		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_UNSIGNED, sampleWidth);
+		return file;
+	}
+
+private:
+	std::string m_testFileName;
+};
+
+static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
+static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
+static const uint8_t kMaxUInt8 = std::numeric_limits<uint8_t>::max();
+
+TEST_F(SignConversionTest, Int8)
+{
+	AFfilehandle file = createTestFile(8);
+	const int8_t data[] = { kMinInt8, 0, kMaxInt8 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(8);
+	ASSERT_TRUE(file != NULL);
+	uint8_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const uint8_t expectedData[] = { 0, -kMinInt8, kMaxUInt8 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
+static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();
+static const uint16_t kMaxUInt16 = std::numeric_limits<uint16_t>::max();
+
+TEST_F(SignConversionTest, Int16)
+{
+	AFfilehandle file = createTestFile(16);
+	const int16_t data[] = { kMinInt16, 0, kMaxInt16 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(16);
+	ASSERT_TRUE(file != NULL);
+	uint16_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const uint16_t expectedData[] = { 0, -kMinInt16, kMaxUInt16 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt24 = -1<<23;
+static const int32_t kMaxInt24 = (1<<23) - 1;
+static const uint32_t kMaxUInt24 = (1<<24) - 1;
+
+TEST_F(SignConversionTest, Int24)
+{
+	AFfilehandle file = createTestFile(24);
+	const int32_t data[] = { kMinInt24, 0, kMaxInt24 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(24);
+	ASSERT_TRUE(file != NULL);
+	uint32_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const uint32_t expectedData[] = { 0, -kMinInt24, kMaxUInt24 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
+static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
+static const uint32_t kMaxUInt32 = std::numeric_limits<uint32_t>::max();
+
+TEST_F(SignConversionTest, Int32)
+{
+	AFfilehandle file = createTestFile(32);
+	const int32_t data[] = { kMinInt32, 0, kMaxInt32 };
+	const int frameCount = sizeof (data) / sizeof (data[0]);
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
+	ASSERT_EQ(framesWritten, frameCount);
+	afCloseFile(file);
+	file = openTestFile(32);
+	ASSERT_TRUE(file != NULL);
+	uint32_t readData[frameCount];
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
+	ASSERT_EQ(framesRead, frameCount);
+	afCloseFile(file);
+	const uint32_t expectedData[] = { 0, -kMinInt32, kMaxUInt32 };
+	for (int i=0; i<frameCount; i++)
+		EXPECT_EQ(readData[i], expectedData[i]);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/TestUtilities.cpp b/test/TestUtilities.cpp
new file mode 100644
index 0000000..b675919
--- /dev/null
+++ b/test/TestUtilities.cpp
@@ -0,0 +1,46 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#include "TestUtilities.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+bool createTemporaryFile(const std::string &prefix, std::string *path)
+{
+	*path = "/tmp/" + prefix + "-XXXXXX";
+	int fd = ::mkstemp(const_cast<char *>(path->c_str()));
+	if (fd < 0)
+		return false;
+	::close(fd);
+	return true;
+}
+
+bool createTemporaryFile(const char *prefix, char **path)
+{
+	*path = NULL;
+	std::string pathString;
+	bool result = createTemporaryFile(prefix, &pathString);
+	if (result)
+		*path = ::strdup(pathString.c_str());
+	return result;
+}
diff --git a/test/TestUtilities.h b/test/TestUtilities.h
new file mode 100644
index 0000000..c00ee6c
--- /dev/null
+++ b/test/TestUtilities.h
@@ -0,0 +1,62 @@
+/*
+	Audio File Library
+	Copyright (C) 2012, Michael Pruett <michael@68k.org>
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the
+	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+	Boston, MA  02110-1301  USA
+*/
+
+#ifndef TEST_UTILITIES_H
+#define TEST_UTILITIES_H
+
+#include <audiofile.h>
+
+#ifdef __cplusplus
+
+#include <string>
+
+bool createTemporaryFile(const std::string &prefix, std::string *path);
+
+class IgnoreErrors
+{
+public:
+	IgnoreErrors()
+	{
+		m_oldErrorHandler = afSetErrorHandler(NULL);
+	}
+	~IgnoreErrors()
+	{
+		afSetErrorHandler(m_oldErrorHandler);
+	}
+
+private:
+	AFerrfunc m_oldErrorHandler;
+};
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+bool createTemporaryFile(const char *prefix, char **path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/VirtualFile.cpp b/test/VirtualFile.cpp
new file mode 100644
index 0000000..e5b5e4e
--- /dev/null
+++ b/test/VirtualFile.cpp
@@ -0,0 +1,184 @@
+/*
+	Copyright (C) 2011, Michael Pruett. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions
+	are met:
+
+	1. Redistributions of source code must retain the above copyright
+	notice, this list of conditions and the following disclaimer.
+
+	2. Redistributions in binary form must reproduce the above copyright
+	notice, this list of conditions and the following disclaimer in the
+	documentation and/or other materials provided with the distribution.
+
+	3. The name of the author may not be used to endorse or promote products
+	derived from this software without specific prior written permission.
+
+	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#include <af_vfs.h>
+#include <audiofile.h>
+#include <gtest/gtest.h>
+#include <limits>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+TEST(VirtualFile, Basic)
+{
+	ASSERT_GE(sizeof (off_t), 8) << "Size of off_t must be at least 8 bytes.";
+}
+
+static ssize_t vf_read(AFvirtualfile *vf, void *data, size_t nbytes)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	return fread(data, 1, nbytes, fp);
+}
+
+static AFfileoffset vf_length(AFvirtualfile *vf)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	off_t current = ftello(fp);
+	fseeko(fp, 0, SEEK_END);
+	off_t length = ftello(fp);
+	fseeko(fp, current, SEEK_SET);
+	return length;
+}
+
+static ssize_t vf_write(AFvirtualfile *vf, const void *data, size_t nbytes)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	return fwrite(data, 1, nbytes, fp);
+}
+
+static void vf_close(AFvirtualfile *vf)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	fclose(fp);
+}
+
+static AFfileoffset vf_seek(AFvirtualfile *vf, AFfileoffset offset, int is_relative)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	fseeko(fp, offset, is_relative ? SEEK_CUR : SEEK_SET);
+	return ftello(fp);
+}
+
+static AFfileoffset vf_tell(AFvirtualfile *vf)
+{
+	FILE *fp = static_cast<FILE *>(vf->closure);
+	return ftello(fp);
+}
+
+static AFvirtualfile *vf_create(FILE *fp)
+{
+	AFvirtualfile *vf = af_virtual_file_new();
+	vf->read = vf_read;
+	vf->length = vf_length;
+	vf->write = vf_write;
+	vf->destroy = vf_close;
+	vf->seek = vf_seek;
+	vf->tell = vf_tell;
+	vf->closure = fp;
+	return vf;
+}
+
+TEST(VirtualFile, ReadVirtual)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("VirtualFile", &testFileName));
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
+	ASSERT_TRUE(file) << "Could not open virtual file";
+
+	afFreeFileSetup(setup);
+
+	const int16_t samples[] = { 1, 1, 2, 3, 5, 8, 13 };
+	const int numSamples = sizeof (samples) / sizeof (int16_t);
+	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numSamples),
+		numSamples) << "Incorrect number of samples written";
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing virtual file";
+
+	FILE *fp = fopen(testFileName.c_str(), "r");
+	AFvirtualfile *vf = vf_create(fp);
+
+	file = afOpenVirtualFile(vf, "r", NULL);
+	ASSERT_TRUE(file) << "Could not open file";
+
+	int16_t readSamples[numSamples];
+	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, readSamples, numSamples),
+		numSamples) << "Incorrect number of samples read";
+
+	for (int i=0; i<numSamples; i++)
+		ASSERT_EQ(samples[i], readSamples[i]);
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+TEST(VirtualFile, WriteVirtual)
+{
+	std::string testFileName;
+	ASSERT_TRUE(createTemporaryFile("VirtualFile", &testFileName));
+
+	FILE *fp = fopen(testFileName.c_str(), "w");
+	AFvirtualfile *vf = vf_create(fp);
+
+	AFfilesetup setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFF);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	AFfilehandle file = afOpenVirtualFile(vf, "w", setup);
+	ASSERT_TRUE(file) << "Could not open virtual file";
+
+	afFreeFileSetup(setup);
+
+	const int16_t samples[] = { 1, 1, 2, 3, 5, 8, 13 };
+	const int numSamples = sizeof (samples) / sizeof (int16_t);
+	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numSamples),
+		numSamples) << "Incorrect number of samples written";
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing virtual file";
+
+	file = afOpenFile(testFileName.c_str(), "r", NULL);
+	ASSERT_TRUE(file) << "Could not open file";
+
+	int16_t readSamples[numSamples];
+	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, readSamples, numSamples),
+		numSamples) << "Incorrect number of samples read";
+
+	for (int i=0; i<numSamples; i++)
+		ASSERT_EQ(samples[i], readSamples[i]);
+
+	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";
+
+	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
+}
+
+int main(int argc, char **argv)
+{
+	::testing::InitGoogleTest(&argc, argv);
+	return RUN_ALL_TESTS();
+}
diff --git a/test/floatto24.c b/test/floatto24.c
new file mode 100644
index 0000000..8acc06f
--- /dev/null
+++ b/test/floatto24.c
@@ -0,0 +1,188 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	floatto24.c
+
+	This program creates a BICSF floating-point sound file and then
+	reads the sample data back as 24-bit data (i.e. 32-bit integers
+	with the high 8 bits equal to the sign extension of the lower
+	24 bits).
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+
+#include "TestUtilities.h"
+
+/*
+	When converted to samples with width 24 bits, the samples
+	should have the following values:
+*/
+
+const float samples[] =
+{
+	0,
+	0.5,
+	-0.5,
+	1,
+	-1,
+	-0.25,
+	0.25,
+	0.75,
+	-0.75
+};
+
+const int referenceConvertedSamples[] =
+{
+	0,
+	4194304,	// = 2^23 * 0.5
+	-4194304,	// = 2^23 * -0.5
+	8388607,	// = 2^23 - 1
+	-8388608,	// = 2^23 * -1
+	-2097152,	// = 2^23 * -0.25
+	2097152,	// = 2^23 * 0.25
+	6291456,	// = 2^23 * 0.75
+	-6291456	// = 2^23 * -0.75
+};
+
+const int frameCount = sizeof (samples) / sizeof (samples[0]);
+
+int main (int argc, char **argv)
+{
+	AFfilesetup	setup;
+	if ((setup = afNewFileSetup()) == AF_NULL_FILESETUP)
+	{
+		fprintf(stderr, "Could not allocate file setup.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	afInitFileFormat(setup, AF_FILE_IRCAM);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
+
+	char *testFileName;
+	if (!createTemporaryFile("floatto24", &testFileName))
+	{
+		fprintf(stderr, "Could not create temporary file.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	AFfilehandle file = afOpenFile(testFileName, "w", setup);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		printf("could not open file for writing\n");
+		exit(EXIT_FAILURE);
+	}
+
+	afFreeFileSetup(setup);
+
+	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		frameCount);
+
+	if (framesWritten != frameCount)
+	{
+		fprintf(stderr, "Wrong number of frames read.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (afCloseFile(file) != 0)
+	{
+		fprintf(stderr, "Closing file returned non-zero status.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "Could not open file for writing.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
+		AF_SAMPFMT_TWOSCOMP, 24) != 0)
+	{
+		fprintf(stderr, "afSetVirtualSampleFormat returned non-zero status.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	int readSamples[frameCount];
+	for (int i=0; i<frameCount; i++)
+		readSamples[i] = -1000 - i;
+	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readSamples,
+		frameCount);
+
+	if (framesRead != frameCount)
+	{
+		fprintf(stderr, "Wrong number of frames read.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	for (int i=0; i<framesRead; i++)
+	{
+#ifdef DEBUG
+		printf("[%d] = %d\n", i, readSamples[i]);
+#endif
+
+		if (readSamples[i] == -1000 - i)
+		{
+			fprintf(stderr, "Data in destination array untouched.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/*
+			Ensure that the high-order 8 bits represent
+			sign extension: only 0x00 (+) or 0xff (-) is
+			valid.
+		*/
+		if ((readSamples[i] & 0xff000000) != 0x000000 &&
+			(readSamples[i] & 0xff000000) != 0xff000000)
+		{
+			fprintf(stderr, "Data is not within range of "
+				"{-2^23, ..., 2^23-1}.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (readSamples[i] != referenceConvertedSamples[i])
+		{
+			fprintf(stderr, "Data doesn't match reference data.\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (afCloseFile(file) != 0)
+	{
+		fprintf(stderr, "Closing file returned non-zero status.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	unlink(testFileName);
+	free(testFileName);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/test/instparamtest.c b/test/instparamtest.c
new file mode 100644
index 0000000..da6184c
--- /dev/null
+++ b/test/instparamtest.c
@@ -0,0 +1,78 @@
+/*
+	Audio File Library
+
+	Copyright 1998, Michael Pruett <michael@68k.org>
+	Copyright 2000, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <audiofile.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	long		result;
+	int		count, instids;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: %s filename\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(argv[1], "r", NULL);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file '%s'\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	count = afGetInstIDs(file, &instids);
+	printf("%ld instruments in file '%s'\n", count, argv[1]);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
+	printf("MIDI base note: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
+	printf("detune in cents: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
+	printf("MIDI low note: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
+	printf("MIDI high note: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
+	printf("MIDI low velocity: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
+	printf("MIDI high velocity: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
+	printf("gain in decibels: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_SUSLOOPID);
+	printf("sustain loop id: %ld\n", result);
+
+	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_RELLOOPID);
+	printf("release loop id: %ld\n", result);
+
+	afCloseFile(file);
+
+	return 0;
+}
diff --git a/test/instparamwrite.c b/test/instparamwrite.c
new file mode 100644
index 0000000..be7a806
--- /dev/null
+++ b/test/instparamwrite.c
@@ -0,0 +1,56 @@
+/*
+	Audio File Library
+
+	Copyright 2000, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <stdio.h>
+
+#include <audiofile.h>
+
+int main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	AUpvlist	list;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: instparamwrite filename\n");
+	}
+
+	setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_AIFFC);
+
+	file = afOpenFile(argv[1], "w", setup);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file %s for writing", argv[1]);
+	}
+
+	afFreeFileSetup(setup);
+
+	/* Set the base note to a 'D.' */
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE, 50);
+
+	/* Detune down by 30 cents. */
+	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE, -30);
+
+	afCloseFile(file);
+
+	return 0;
+}
diff --git a/test/printmarkers.c b/test/printmarkers.c
new file mode 100644
index 0000000..e1086d9
--- /dev/null
+++ b/test/printmarkers.c
@@ -0,0 +1,126 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2002, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	printmarkers
+
+	This program lists the markers in an audio file.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <audiofile.h>
+
+void printtime (AFframecount position, double rate)
+{
+	double	time_in_seconds;
+
+	time_in_seconds = (double) position / rate;
+
+	/* Handle hours. */
+	if (time_in_seconds > 3600)
+	{
+		printf("%d:", (int) (time_in_seconds / 3600));
+		time_in_seconds = fmod(time_in_seconds, 3600);
+	}
+
+	/* Handle minutes. */
+	if (time_in_seconds > 60)
+	{
+		printf("%02d:", (int) (time_in_seconds / 60));
+		time_in_seconds = fmod(time_in_seconds, 60);
+	}
+
+	/* Handle seconds and milliseconds. */
+	printf("%02.3f", time_in_seconds);
+}
+
+int main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	double		rate;
+	int		markcount;
+	int		*markids;
+	int		i;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: %s filename\n", argv[0]);
+		fprintf(stderr, "where filename is the name of an audio file containing markers\n");
+		exit(0);
+	}
+
+	file = afOpenFile(argv[1], "r", NULL);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "Could not open file '%s' for reading.", argv[1]);
+		exit(0);
+	}
+
+	markcount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
+	if (markcount <= 0)
+	{
+		fprintf(stderr, "The file '%s' does not contain any markers.", argv[1]);
+		exit(0);
+	}
+
+	markids = calloc(markcount, sizeof (int));
+	if (markids == NULL)
+	{
+		fprintf(stderr, "Could not allocate enough memory for markers.");
+		exit(0);
+	}
+
+	afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);
+
+	rate = afGetRate(file, AF_DEFAULT_TRACK);
+
+	for (i=0; i<markcount; i++)
+	{
+		AFframecount	position;
+		const char	*name, *comment;
+
+		position = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]);
+
+		name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
+		comment = afGetMarkComment(file, AF_DEFAULT_TRACK, markids[i]);
+
+		printf("marker %d, position %lld, time ", markids[i], position);
+
+		printtime(position, rate);
+
+		printf("\n");
+
+		if (name != NULL)
+			printf("\tname: %s\n", name);
+		if (comment != NULL)
+			printf("\tcomment: %s\n", comment);
+	}
+
+	afCloseFile(file);
+
+	return EXIT_SUCCESS;
+}
diff --git a/test/query2.c b/test/query2.c
new file mode 100644
index 0000000..215ab4c
--- /dev/null
+++ b/test/query2.c
@@ -0,0 +1,171 @@
+/*
+	Audio File Library
+
+	Copyright 1998-2000, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#include <dmedia/audioutil.h>
+#else
+#include <audiofile.h>
+#include <aupvlist.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+const char *paramtypename (int paramtype);
+void printinstparams (int format);
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DEBG printf
+#else
+#define DEBG
+#endif
+
+int main (int ac, char **av)
+{
+	AUpvlist	formatlist;
+	int		*flist;
+	long		lvalue;
+	int		i, formatcount;
+
+	formatlist = afQuery(AF_QUERYTYPE_FILEFMT, AF_QUERY_IDS, 0, 0, 0);
+	formatcount = afQueryLong(AF_QUERYTYPE_FILEFMT, AF_QUERY_ID_COUNT, 0, 0, 0);
+
+	DEBG("formatcount = %d\n", formatcount);
+
+	AUpvgetval(formatlist, 0, &flist);
+	AUpvfree(formatlist);
+
+	for (i=0; i<formatcount; i++)
+	{
+		int	format;
+		char	*formatstring;
+
+		format = flist[i];
+		DEBG("format = %d\n", format);
+		formatstring = afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_NAME,
+			format, 0, 0);
+		DEBG("format = %s\n", formatstring);
+
+		lvalue = afQueryLong(AF_QUERYTYPE_INST, AF_QUERY_SUPPORTED,
+			format, 0, 0);
+		DEBG("instrument query: supported: %ld\n", lvalue);
+
+		lvalue = afQueryLong(AF_QUERYTYPE_INST, AF_QUERY_MAX_NUMBER,
+			format, 0, 0);
+		DEBG("instrument query: maximum number: %ld\n", lvalue);
+
+		lvalue = afQueryLong(AF_QUERYTYPE_INSTPARAM, AF_QUERY_SUPPORTED,
+			format, 0, 0);
+		DEBG("instrument parameter query: supported: %ld\n", lvalue);
+
+		/*
+			Print instrument parameter information only if
+			instrument parameters are supported.
+		*/
+		if (lvalue)
+			printinstparams(format);
+	}
+	free(flist);
+
+	return 0;
+}
+
+void printinstparams (int format)
+{
+	int	i, *iarray;
+	long	instParamCount;
+
+	instParamCount = afQueryLong(AF_QUERYTYPE_INSTPARAM, AF_QUERY_ID_COUNT,
+		format, 0, 0);
+	DEBG("instrument parameter query: id count: %ld\n", instParamCount);
+
+	iarray = afQueryPointer(AF_QUERYTYPE_INSTPARAM, AF_QUERY_IDS,
+		format, 0, 0);
+
+	if (iarray == NULL)
+		printf("AF_QUERYTYPE_INSTPARAM failed for format %d\n", format);
+
+	for (i=0; i<instParamCount; i++)
+	{
+		int		paramType;
+		AUpvlist	defaultValue;
+
+		DEBG("instrument parameter query: id: %d\n", iarray[i]);
+		paramType = afQueryLong(AF_QUERYTYPE_INSTPARAM,
+			AF_QUERY_TYPE, format, iarray[i], 0);
+
+		DEBG("\ttype of parameter: %s\n", paramtypename(paramType));
+		DEBG("\tname of parameter: %s\n",
+			(char *) afQueryPointer(AF_QUERYTYPE_INSTPARAM,
+				AF_QUERY_NAME, format, iarray[i], 0));
+
+		defaultValue = afQuery(AF_QUERYTYPE_INSTPARAM, AF_QUERY_DEFAULT,
+			format, iarray[i], 0);
+
+		if (paramType == AU_PVTYPE_LONG)
+		{
+			long	ldefault;
+			AUpvgetval(defaultValue, 0, &ldefault);
+			DEBG("\tdefault value: %ld\n", ldefault);
+		}
+		else if (paramType == AU_PVTYPE_DOUBLE)
+		{
+			double	ddefault;
+			AUpvgetval(defaultValue, 0, &ddefault);
+			DEBG("\tdefault value: %f\n", ddefault);
+		}
+		else if (paramType == AU_PVTYPE_PTR)
+		{
+			void	*vdefault;
+			AUpvgetval(defaultValue, 0, &vdefault);
+			DEBG("\tdefault value: %p\n", vdefault);
+		}
+
+		AUpvfree(defaultValue);
+	}
+
+	free(iarray);
+}
+
+const char *paramtypename (int paramtype)
+{
+	static const char	*longname = "long";
+	static const char	*doublename = "double";
+	static const char	*pointername = "pointer";
+
+	switch (paramtype)
+	{
+		case AU_PVTYPE_LONG:
+			return longname;
+		case AU_PVTYPE_DOUBLE:
+			return doublename;
+		case AU_PVTYPE_PTR:
+			return pointername;
+	}
+
+	return NULL;
+}
diff --git a/test/sixteen-to-eight.c b/test/sixteen-to-eight.c
new file mode 100644
index 0000000..3791d86
--- /dev/null
+++ b/test/sixteen-to-eight.c
@@ -0,0 +1,119 @@
+/*
+	Audio File Library
+
+	Copyright 2000, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	sixteen-to-eight.c
+
+	This program tests the conversion from 16-bit integers to 8-bit
+	integers.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+int main (int argc, char **argv)
+{
+	AFfilehandle file;
+	AFfilesetup setup;
+	int16_t frames16[] = {14298, 392, 3923, -683, 958, -1921};
+	int8_t frames8[] = {55, 1, 15, -3, 3, -8};
+	int i, frameCount = 6;
+	int8_t byte;
+	AFframecount result;
+
+	setup = afNewFileSetup();
+
+	afInitFileFormat(setup, AF_FILE_WAVE);
+
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_UNSIGNED, 8);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	char *testFileName;
+	if (!createTemporaryFile("sixteen-to-eight", &testFileName))
+	{
+		fprintf(stderr, "Could not create temporary file.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(testFileName, "w", setup);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file for writing\n");
+		exit(EXIT_FAILURE);
+	}
+
+	afFreeFileSetup(setup);
+
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	afWriteFrames(file, AF_DEFAULT_TRACK, frames16, frameCount);
+
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file for reading\n");
+		exit(EXIT_FAILURE);
+	}
+
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 8);
+
+	for (i=0; i<frameCount; i++)
+	{
+		/* Read one frame. */
+		result = afReadFrames(file, AF_DEFAULT_TRACK, &byte, 1);
+
+		if (result != 1)
+			break;
+
+		/* Compare the byte read with its precalculated value. */
+		if (memcmp(&byte, &frames8[i], 1) != 0)
+		{
+			printf("error\n");
+			printf("expected %d, got %d\n", frames8[i], byte);
+			exit(EXIT_FAILURE);
+		}
+		else
+		{
+#ifdef DEBUG
+			printf("got what was expected: %d\n", byte);
+#endif
+		}
+	}
+
+	afCloseFile(file);
+	unlink(testFileName);
+	free(testFileName);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/test/testaupv.c b/test/testaupv.c
new file mode 100644
index 0000000..f042813
--- /dev/null
+++ b/test/testaupv.c
@@ -0,0 +1,79 @@
+/*
+	Audio File Library
+
+	Copyright 1998, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	testaupv.c
+
+	This is a program to test the AUpvlist commands.
+*/
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/dm_audioutil.h>
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#include <aupvlist.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+	AUpvlist		list;
+	int				size;
+	AFfilehandle	file;
+
+	long	fuck = 99;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: testaupv filename\n");
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(argv[1], "r", NULL);
+
+	list = AUpvnew(4);
+	size = AUpvgetmaxitems(list);
+
+	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 0, AF_INST_MIDI_BASENOTE));
+	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 1, AF_INST_MIDI_LONOTE));
+	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 2, AF_INST_SUSLOOPID));
+	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 3, AF_INST_RELLOOPID));
+
+	afGetInstParams(file, AF_DEFAULT_INST, list, 4);
+
+	AUpvgetval(list, 0, &fuck);
+	printf("AUpvgetval: %ld\n", fuck);
+
+	AUpvgetval(list, 1, &fuck);
+	printf("AUpvgetval: %ld\n", fuck);
+
+	AUpvgetval(list, 2, &fuck);
+	printf("AUpvgetval: %ld\n", fuck);
+
+	AUpvgetval(list, 3, &fuck);
+	printf("AUpvgetval: %ld\n", fuck);
+
+	afCloseFile(file);
+
+	return 0;
+}
diff --git a/test/testchannelmatrix.c b/test/testchannelmatrix.c
new file mode 100644
index 0000000..fdba076
--- /dev/null
+++ b/test/testchannelmatrix.c
@@ -0,0 +1,133 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2003, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	testchannelmatrix.c
+
+	This program tests the channel matrix functionality of virtual
+	sample format conversion in the Audio File Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+const short samples[] = {300, -300, 515, -515, 2315, -2315, 9154, -9154};
+#define SAMPLE_COUNT (sizeof (samples) / sizeof (short))
+#define CHANNEL_COUNT 2
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+		unlink(sTestFileName);
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (void)
+{
+	AFfilesetup	setup;
+	AFfilehandle	file;
+	int		framesWritten, framesRead;
+	const int 	frameCount = SAMPLE_COUNT / CHANNEL_COUNT;
+	short		readsamples[SAMPLE_COUNT];
+	int		i;
+	int		sampleFormat, sampleWidth;
+
+	setup = afNewFileSetup();
+
+	afInitChannels(setup, AF_DEFAULT_TRACK, CHANNEL_COUNT);
+	afInitFileFormat(setup, AF_FILE_AIFFC);
+
+	/* Write stereo data to test file. */
+	ensure(createTemporaryFile("testchannelmatrix", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");
+
+	afFreeFileSetup(setup);
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		frameCount);
+	ensure(framesWritten == frameCount,
+		"number of frames written doesn't match "
+		"number of frames requested");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	/*
+		Open the test file and read stereo data mixed down to a
+		single channel.  The default channel matrix for one
+		file channel and two virtual channels is {0.5, 0.5},
+		and since each odd sample is the inverse of the
+		corresponding even sample, the data read should be all
+		zeros.
+	*/
+	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
+		"file doesn't have exactly two channels");
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ensure(sampleFormat == AF_SAMPFMT_TWOSCOMP && sampleWidth == 16,
+		"file doesn't contain 16-bit two's complement data");
+	ensure(afGetFileFormat(file, NULL) == AF_FILE_AIFFC,
+		"file format doesn't match format requested");
+
+	afSetVirtualChannels(file, AF_DEFAULT_TRACK, 1);
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
+		frameCount);
+	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");
+
+	for (i=0; i<SAMPLE_COUNT/CHANNEL_COUNT; i++)
+	{
+		ensure(readsamples[i] == 0,
+			"data written to file is not as expected");
+	}
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+	exit(EXIT_SUCCESS);
+}
diff --git a/test/testdouble.c b/test/testdouble.c
new file mode 100644
index 0000000..e6821bd
--- /dev/null
+++ b/test/testdouble.c
@@ -0,0 +1,140 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	testdouble.c
+
+	This program tests double-precision floating-point reading and
+	writing for the AIFF-C, WAVE, and NeXT .snd file formats.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+const double samples[] =
+	{1.0, 0.6, -0.3, 0.95, 0.2, -0.6, 0.9, 0.4, -0.22, 0.125, 0.1, -0.4};
+const int SAMPLE_COUNT = sizeof (samples) / sizeof (samples[0]);
+
+void testdouble (int fileFormat);
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+		unlink(sTestFileName);
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (int argc, char **argv)
+{
+	/* These file formats support double-precision floating-point audio data. */
+	const int fileFormats[] =
+		{ AF_FILE_AIFFC, AF_FILE_WAVE, AF_FILE_NEXTSND };
+	const int fileFormatCount = sizeof (fileFormats) / sizeof (fileFormats[0]);
+	int	i;
+
+	for (i=0; i<fileFormatCount; i++)
+	{
+		printf("testdouble: testing %s\n",
+			(char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_NAME, fileFormats[i], 0, 0));
+		testdouble(fileFormats[i]);
+	}
+
+	printf("testdouble passed\n");
+	exit(EXIT_SUCCESS);
+}
+
+void testdouble (int fileFormat)
+{
+	AFfilesetup	setup;
+	AFfilehandle	file;
+	int		framesWritten, framesRead;
+	const int 	frameCount = SAMPLE_COUNT/2;
+	double		readsamples[SAMPLE_COUNT];
+	int		i;
+	int		sampleFormat, sampleWidth;
+
+	setup = afNewFileSetup();
+
+	afInitFileFormat(setup, fileFormat);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_DOUBLE, 64);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
+
+	ensure(createTemporaryFile("testdouble", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");
+
+	afFreeFileSetup(setup);
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		frameCount);
+	ensure(framesWritten == frameCount, "number of frames written does not match number of frames requested");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
+		"file doesn't have exactly two channels");
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ensure(sampleFormat == AF_SAMPFMT_DOUBLE && sampleWidth == 64,
+		"file doesn't contain 64-bit floating-point data");
+	ensure(afGetFileFormat(file, NULL) == fileFormat,
+		"file format doesn't match format requested");
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
+		frameCount);
+	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");
+
+	for (i=0; i<SAMPLE_COUNT; i++)
+	{
+		ensure(readsamples[i] == samples[i],
+			"data written to file doesn't match data read");
+	}
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+}
diff --git a/test/testfloat.c b/test/testfloat.c
new file mode 100644
index 0000000..75e906b
--- /dev/null
+++ b/test/testfloat.c
@@ -0,0 +1,140 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	testfloat.c
+
+	This program tests floating-point reading and writing for
+	the AIFF-C, WAVE, NeXT .snd, and IRCAM file formats.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+const float samples[] =
+	{1.0, 0.6, -0.3, 0.95, 0.2, -0.6, 0.9, 0.4, -0.22, 0.125, 0.1, -0.4};
+#define SAMPLE_COUNT (sizeof (samples) / sizeof (float))
+
+void testfloat (int fileFormat);
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+		unlink(sTestFileName);
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (int argc, char **argv)
+{
+	/* These file formats support floating-point audio data. */
+	int	fileFormatCount = 4;
+	int	fileFormats[] =
+		{AF_FILE_AIFFC, AF_FILE_WAVE, AF_FILE_NEXTSND, AF_FILE_IRCAM};
+	char	*formatNames[] = {"AIFF-C", "WAVE", "NeXT .snd", "IRCAM"};
+	int	i;
+
+	for (i=0; i<fileFormatCount; i++)
+	{
+		printf("testfloat: testing %s\n", formatNames[i]);
+		testfloat(fileFormats[i]);
+	}
+
+	printf("testfloat passed\n");
+	exit(EXIT_SUCCESS);
+}
+
+void testfloat (int fileFormat)
+{
+	AFfilesetup	setup;
+	AFfilehandle	file;
+	int		framesWritten, framesRead;
+	const int 	frameCount = SAMPLE_COUNT/2;
+	float		readsamples[SAMPLE_COUNT];
+	int		i;
+	int		sampleFormat, sampleWidth;
+
+	setup = afNewFileSetup();
+
+	afInitFileFormat(setup, fileFormat);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
+
+	ensure(createTemporaryFile("testfloat", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");
+
+	afFreeFileSetup(setup);
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		frameCount);
+	ensure(framesWritten == frameCount, "number of frames written does not match number of frames requested");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
+	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
+		"file doesn't have exactly two channels");
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ensure(sampleFormat == AF_SAMPFMT_FLOAT && sampleWidth == 32,
+		"file doesn't contain 32-bit floating-point data");
+	ensure(afGetFileFormat(file, NULL) == fileFormat,
+		"file format doesn't match format requested");
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
+		frameCount);
+	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");
+
+	for (i=0; i<SAMPLE_COUNT; i++)
+	{
+		ensure(readsamples[i] == samples[i],
+			"data written to file doesn't match data read");
+	}
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+}
diff --git a/test/testmarkers.c b/test/testmarkers.c
new file mode 100644
index 0000000..463393f
--- /dev/null
+++ b/test/testmarkers.c
@@ -0,0 +1,144 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2002, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+#define FRAME_COUNT 200
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+#ifndef DEBUG
+		unlink(sTestFileName);
+#endif
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int testmarkers (int fileformat)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	int		markids[] = {1, 2, 3, 4};
+	AFframecount	markpositions[] = {14, 54, 23, 101};
+	const char	*marknames[] = {"one", "two", "three", "four"};
+	short		frames[FRAME_COUNT * 2] = {0};
+	int		readmarkcount;
+	int		readmarkids[4];
+	AFframecount	frameswritten;
+
+	setup = afNewFileSetup();
+	ensure(setup != AF_NULL_FILESETUP, "Could not create file setup");
+
+	afInitFileFormat(setup, fileformat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
+
+	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markids, 4);
+
+	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[0], marknames[0]);
+	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[1], marknames[1]);
+	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[2], marknames[2]);
+	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[3], marknames[3]);
+
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "Could not open file for writing");
+
+	afFreeFileSetup(setup);
+
+	frameswritten = afWriteFrames(file, AF_DEFAULT_TRACK, frames, FRAME_COUNT);
+	ensure(frameswritten == FRAME_COUNT, "Error writing audio data");
+
+	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[0], markpositions[0]);
+	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[1], markpositions[1]);
+	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[2], markpositions[2]);
+	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[3], markpositions[3]);
+
+	afCloseFile(file);
+
+	file = afOpenFile(sTestFileName, "r", NULL);
+	ensure(file != AF_NULL_FILEHANDLE, "Could not open file for reading");
+
+	readmarkcount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
+	ensure(readmarkcount == 4, "Number of markers is not correct");
+
+	afGetMarkIDs(file, AF_DEFAULT_TRACK, readmarkids);
+
+	for (int i=0; i<readmarkcount; i++)
+		ensure(readmarkids[i] = markids[i],
+			"Marker identification numbers do not match");
+
+	for (int i=0; i<readmarkcount; i++)
+	{
+		AFframecount	readmarkposition;
+		const char	*readmarkname;
+
+		readmarkposition = afGetMarkPosition(file, AF_DEFAULT_TRACK, readmarkids[i]);
+
+		readmarkname = afGetMarkName(file, AF_DEFAULT_TRACK, readmarkids[i]);
+
+		ensure(readmarkposition == markpositions[i],
+			"Marker positions do not match");
+		ensure(strcmp(readmarkname, marknames[i]) == 0,
+			"Marker names do not match");
+	}
+
+	afCloseFile(file);
+
+	return EXIT_SUCCESS;
+}
+
+int main (void)
+{
+	ensure(createTemporaryFile("testmarkers", &sTestFileName),
+		"could not create temporary file");
+
+	testmarkers(AF_FILE_AIFF);
+	testmarkers(AF_FILE_AIFFC);
+	testmarkers(AF_FILE_WAVE);
+
+	cleanup();
+
+	return EXIT_SUCCESS;
+}
diff --git a/test/twentyfour.c b/test/twentyfour.c
new file mode 100644
index 0000000..1efa2a6
--- /dev/null
+++ b/test/twentyfour.c
@@ -0,0 +1,245 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2001, Silicon Graphics, Inc.
+	Michael Pruett <mpruett@sgi.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	twentyfour.c
+
+	This program tests the conversion between 24-bit signed integer
+	data in a file and 32-bit signed integer data in memory.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+#define FRAME_COUNT 6
+
+int main (int argc, char **argv)
+{
+	AFfilehandle file;
+	AFfilesetup setup;
+	/* All elements in frames32 must be in the range -2^23 to 2^23 - 1. */
+	const int32_t frames32[FRAME_COUNT] =
+		{4314298, -49392, 3923, -143683, 43, -992129};
+	const uint8_t frames24[FRAME_COUNT*3] =
+		{
+			0x41, 0xd4, 0xba,	/* 4314298 */
+			0xff, 0x3f, 0x10,	/* -49392 */
+			0x00, 0x0f, 0x53,	/* 3923 */
+			0xfd, 0xce, 0xbd,	/* -143683 */
+			0x00, 0x00, 0x2b,	/* 43 */
+			0xf0, 0xdc, 0x7f	/* -992129 */
+		};
+	int32_t readframes32[FRAME_COUNT];
+	int i;
+
+	setup = afNewFileSetup();
+	assert(setup);
+
+	afInitFileFormat(setup, AF_FILE_AIFF);
+
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	char *testFileName;
+	if (!createTemporaryFile("twentyfour", &testFileName))
+	{
+		fprintf(stderr, "could not create temporary file\n");
+		exit(EXIT_FAILURE);
+	}
+
+	file = afOpenFile(testFileName, "w", setup);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file for writing\n");
+		exit(EXIT_FAILURE);
+	}
+
+	afFreeFileSetup(setup);
+
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
+	afWriteFrames(file, AF_DEFAULT_TRACK, frames32, FRAME_COUNT);
+
+	afCloseFile(file);
+
+	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
+	if (file == AF_NULL_FILEHANDLE)
+	{
+		fprintf(stderr, "could not open file for reading\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Test virtual sample width of 24 bits. */
+#ifdef DEBUG
+	fprintf(stderr, "Testing virtual sample width of 24 bits.\n");
+#endif
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
+
+	for (i=0; i<FRAME_COUNT; i++)
+	{
+		uint8_t	x[4];
+		uint8_t	y[4];
+		uint8_t	z[4];
+
+		if ((frames32[i] & 0x800000) != 0)
+			x[0] = 0xff;
+		else
+			x[0] = 0;
+		x[1] = (frames32[i] >> 16) & 0xff;
+		x[2] = (frames32[i] >> 8) & 0xff;
+		x[3] = (frames32[i]) & 0xff;
+
+		/*
+			Check to see that the precomputed values match
+			what we've just computed.
+		*/
+		if (x[1] != frames24[3*i] ||
+			x[2] != frames24[3*i + 1] ||
+			x[3] != frames24[3*i + 2])
+		{
+			fprintf(stderr, "Data doesn't match pre-computed values.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (afReadFrames(file, AF_DEFAULT_TRACK, y, 1) != 1)
+		{
+			fprintf(stderr, "Could not read from test file.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/*
+			x is in big-endian byte order; make z a
+			native-endian copy of x.
+		*/
+#ifdef WORDS_BIGENDIAN
+		memcpy(z, x, 4);
+#else
+		z[0] = x[3];
+		z[1] = x[2];
+		z[2] = x[1];
+		z[3] = x[0];
+#endif
+
+#ifdef DEBUG
+		printf("x = %02x %02x %02x %02x\n", x[0], x[1], x[2], x[3]);
+		printf("y = %02x %02x %02x %02x\n", y[0], y[1], y[2], y[3]);
+		printf("z = %02x %02x %02x %02x\n", z[0], z[1], z[2], z[3]);
+#endif
+
+		/*
+			Check to see that the data read from the file
+			matches computed value.
+		*/
+		if (memcmp(y, z, 4) != 0)
+		{
+			fprintf(stderr, "Data read from file is incorrect.\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* Test virtual sample width of 32 bits. */
+#ifdef DEBUG
+	fprintf(stderr, "Testing virtual sample width of 32 bits.\n");
+#endif
+	afSeekFrame(file, AF_DEFAULT_TRACK, 0);
+	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 32);
+
+	for (i=0; i<FRAME_COUNT; i++)
+	{
+		uint8_t	x[4];
+		uint8_t	y[4];
+		uint8_t	z[4];
+
+		x[0] = (frames32[i] >> 16) & 0xff;
+		x[1] = (frames32[i] >> 8) & 0xff;
+		x[2] = (frames32[i]) & 0xff;
+		x[3] = 0;
+
+		/*
+			Check to see that the precomputed values match
+			what we've just computed.
+		*/
+		if (x[0] != frames24[3*i] ||
+			x[1] != frames24[3*i + 1] ||
+			x[2] != frames24[3*i + 2])
+		{
+			fprintf(stderr, "Data doesn't match pre-computed values.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (afReadFrames(file, AF_DEFAULT_TRACK, y, 1) != 1)
+		{
+			fprintf(stderr, "Could not read from test file.\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/*
+			x is in big-endian byte order; make z a
+			native-endian copy of x.
+		*/
+#ifdef WORDS_BIGENDIAN
+		memcpy(z, x, 4);
+#else
+		z[0] = x[3];
+		z[1] = x[2];
+		z[2] = x[1];
+		z[3] = x[0];
+#endif
+
+#ifdef DEBUG
+		printf("x = %02x %02x %02x %02x\n", x[0], x[1], x[2], x[3]);
+		printf("y = %02x %02x %02x %02x\n", y[0], y[1], y[2], y[3]);
+		printf("z = %02x %02x %02x %02x\n", z[0], z[1], z[2], z[3]);
+#endif
+
+		/*
+			Check to see that the data read from the file
+			matches computed value.
+		*/
+		if (memcmp(y, z, 4) != 0)
+		{
+			fprintf(stderr, "Data read from file is incorrect.\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (afCloseFile(file) != 0)
+	{
+		fprintf(stderr, "Error closing file.\n");
+		exit(EXIT_FAILURE);
+	}
+	unlink(testFileName);
+	free(testFileName);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/test/twentyfour2.c b/test/twentyfour2.c
new file mode 100644
index 0000000..236f00a
--- /dev/null
+++ b/test/twentyfour2.c
@@ -0,0 +1,142 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2003, Michael Pruett <michael@68k.org>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	twentyfour2.c
+
+	This program checks reading and writing a large amount of 24-bit
+	audio data to an AIFF file.
+
+	This program serves as a regression test for a bug in the Audio
+	File Library in which requesting more than _AF_ATOMIC_NVFRAMES
+	(1024 frames) from afReadFrames when reading a 24-bit audio file
+	would result in corrupted audio data.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <audiofile.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+#define FRAME_COUNT 10000
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+#ifndef DEBUG
+		unlink(sTestFileName);
+#endif
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (void)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	int32_t		*buffer, *readbuffer;
+	int		i;
+	AFframecount	frameswritten, framesread;
+
+	setup = afNewFileSetup();
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
+
+	ensure(createTemporaryFile("twentyfour2", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != NULL, "could not open test file for writing");
+
+	afFreeFileSetup(setup);
+
+	buffer = malloc(sizeof (int32_t) * FRAME_COUNT);
+	ensure(buffer != NULL, "could not allocate buffer for audio data");
+
+	readbuffer = malloc(sizeof (int32_t) * FRAME_COUNT);
+	ensure(readbuffer != NULL, "could not allocate buffer for audio data");
+
+	for (i=0; i<FRAME_COUNT; i++)
+	{
+		if ((i%3) == 0)
+			buffer[i] = -i;
+		else
+			buffer[i] = i;
+	}
+
+	frameswritten = afWriteFrames(file, AF_DEFAULT_TRACK, buffer, FRAME_COUNT);
+	ensure(frameswritten == FRAME_COUNT, "incorrect number of frames written");
+
+	afCloseFile(file);
+
+	/*
+		Now open file for reading and ensure that the data read
+		is equal to the data written.
+	*/
+	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
+	ensure(file != NULL, "could not open test file for reading");
+
+	framesread = afReadFrames(file, AF_DEFAULT_TRACK, readbuffer, FRAME_COUNT);
+	ensure(framesread == FRAME_COUNT, "incorrect number of frames read");
+
+#ifdef DEBUG
+	for (i=0; i<FRAME_COUNT; i++)
+	{
+		if (buffer[i] != readbuffer[i])
+		{
+			printf("buffer[%d] = %d, readbuffer[%d] = %d\n",
+				i, buffer[i], i, readbuffer[i]);
+		}
+	}
+#endif
+
+	ensure(!memcmp(buffer, readbuffer, sizeof (int32_t) * FRAME_COUNT),
+		"data read does not match data written");
+
+	afCloseFile(file);
+
+	free(buffer);
+	free(readbuffer);
+
+	cleanup();
+	return 0;
+}
diff --git a/test/writealaw.c b/test/writealaw.c
new file mode 100644
index 0000000..0e39ec6
--- /dev/null
+++ b/test/writealaw.c
@@ -0,0 +1,181 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	writealaw.c
+
+	The writealaw program performs sanity testing on the Audio File
+	Library's G.711 A-law compression by writing and then reading
+	back known data to a file to make sure the two sets of data agree.
+
+	This program writes a set of data which is invariant under G.711
+	A-law compression to a file and then reads that set of data back.
+
+	The data read from that file should match the data written
+	exactly.
+
+	If this test fails, something in the Audio File Library is broken.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+#define FRAME_COUNT 16
+#define SAMPLE_COUNT FRAME_COUNT
+
+void testalaw (int fileFormat);
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+#ifndef DEBUG
+		unlink(sTestFileName);
+#endif
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (int argc, char **argv)
+{
+	printf("writealaw: testing NeXT .snd.\n");
+	testalaw(AF_FILE_NEXTSND);
+	printf("writealaw: testing AIFF-C.\n");
+	testalaw(AF_FILE_AIFFC);
+	printf("writealaw: testing WAVE.\n");
+	testalaw(AF_FILE_WAVE);
+	printf("writealaw: testing IRCAM.\n");
+	testalaw(AF_FILE_IRCAM);
+	printf("writealaw: testing VOC.\n");
+	testalaw(AF_FILE_VOC);
+	printf("writealaw: testing CAF.\n");
+	testalaw(AF_FILE_CAF);
+
+	printf("writealaw test passed.\n");
+
+	exit(0);
+}
+
+void testalaw (int fileFormat)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	uint16_t	samples[] = {8, 24, 88, 120, 184, 784, 912, 976,
+                        1120, 1440, 1888, 8960, 9984, 16128, 19968, 32256};
+	uint16_t	readsamples[SAMPLE_COUNT];
+	AFframecount	framesWritten, framesRead;
+	int		i;
+
+	setup = afNewFileSetup();
+
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_G711_ALAW);
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	ensure(createTemporaryFile("writealaw", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	afFreeFileSetup(setup);
+
+	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
+		AF_COMPRESSION_G711_ALAW,
+		"test file not created with G.711 A-law compression");
+
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		FRAME_COUNT);
+
+	ensure(framesWritten == FRAME_COUNT,
+		"number of frames requested does not match number of frames written");
+	afCloseFile(file);
+
+	/* Open the file for reading and verify the data. */
+	file = afOpenFile(sTestFileName, "r", NULL);
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");
+
+	ensure(afGetFileFormat(file, NULL) == fileFormat,
+		"test file format incorrect");
+
+	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
+		AF_COMPRESSION_G711_ALAW,
+		"test file not opened with G.711 A-law compression");
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
+		FRAME_COUNT);
+
+	ensure(framesRead == FRAME_COUNT,
+		"number of frames read does not match number of frames requested");
+
+#ifdef DEBUG
+	for (i=0; i<SAMPLE_COUNT; i++)
+		printf("readsamples[%d]: %d\n", i, readsamples[i]);
+	for (i=0; i<SAMPLE_COUNT; i++)
+		printf("samples[%d]: %d\n", i, samples[i]);
+#endif
+
+	for (i=0; i<SAMPLE_COUNT; i++)
+	{
+		ensure(samples[i] == readsamples[i],
+			"data written does not match data read");
+	}
+
+	/* G.711 compression uses one byte per sample. */
+	ensure(afGetTrackBytes(file, AF_DEFAULT_TRACK) == SAMPLE_COUNT,
+		"track byte count is incorrect");
+
+	ensure(afGetFrameCount(file, AF_DEFAULT_TRACK) == FRAME_COUNT,
+		"frame count is incorrect");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
+		"channel count is incorrect");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+}
diff --git a/test/writeraw.c b/test/writeraw.c
new file mode 100644
index 0000000..e12c4fc
--- /dev/null
+++ b/test/writeraw.c
@@ -0,0 +1,140 @@
+/*
+	Audio File Library
+
+	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+	Copyright (C) 2002, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	writeraw.c
+
+	This program tests the validity of the AIFF file reading and writing
+	code.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+#ifndef DEBUG
+		unlink(sTestFileName);
+#endif
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (int argc, char **argv)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	uint16_t	samples[] = {11, 51, 101, 501, 1001, 5001, 10001, 50001};
+	int		i;
+	int		sampleFormat, sampleWidth;
+	int		framesRead, framesWritten;
+	int		nativeByteOrder;
+
+#ifdef WORDS_BIGENDIAN
+	nativeByteOrder = AF_BYTEORDER_BIGENDIAN;
+#else
+	nativeByteOrder = AF_BYTEORDER_LITTLEENDIAN;
+#endif
+
+	setup = afNewFileSetup();
+	afInitFileFormat(setup, AF_FILE_RAWDATA);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+
+	ensure(createTemporaryFile("writeraw", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples, 8);
+	ensure(framesWritten == 8,
+		"number of frames written does not match number of frames requested");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	file = afOpenFile(sTestFileName, "r", setup);
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");
+	afFreeFileSetup(setup);
+
+	ensure(afGetFileFormat(file, NULL) == AF_FILE_RAWDATA,
+		"test file not created as raw audio data file");
+
+	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
+	ensure(sampleFormat == AF_SAMPFMT_TWOSCOMP,
+		"test file not two's complement");
+	ensure(sampleWidth == 16,
+		"test file sample format is not 16-bit");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
+		"test file doesn't have exactly one channel");
+
+	ensure(afGetByteOrder(file, AF_DEFAULT_TRACK) == nativeByteOrder,
+		"test file not in native byte order");
+
+	for (i=0; i<8; i++)
+	{
+		uint16_t	temporary;
+
+		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, &temporary, 1);
+		ensure(framesRead == 1,
+			"number of frames read does not match number of frames requested");
+
+		ensure(temporary == samples[i],
+			"data written to file doesn't match data read from file");
+	}
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+
+	printf("writeraw test passed.\n");
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/test/writeulaw.c b/test/writeulaw.c
new file mode 100644
index 0000000..79d19f6
--- /dev/null
+++ b/test/writeulaw.c
@@ -0,0 +1,181 @@
+/*
+	Audio File Library
+
+	Copyright (C) 2000, Michael Pruett <michael@68k.org>
+	Copyright (C) 2001, Silicon Graphics, Inc.
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+	writeulaw.c
+
+	The writeulaw program performs sanity testing on the Audio File
+	Library's G.711 u-law compression by writing and then reading
+	back known data to a file to make sure the two sets of data agree.
+
+	This program writes a set of data which is invariant under G.711
+	u-law compression to a file and then reads that set of data back.
+
+	The data read from that file should match the data written
+	exactly.
+
+	If this test fails, something in the Audio File Library is broken.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __USE_SGI_HEADERS__
+#include <dmedia/audiofile.h>
+#else
+#include <audiofile.h>
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "TestUtilities.h"
+
+static char *sTestFileName;
+
+#define FRAME_COUNT 16
+#define SAMPLE_COUNT FRAME_COUNT
+
+void testulaw (int fileFormat);
+
+void cleanup (void)
+{
+	if (sTestFileName)
+	{
+#ifndef DEBUG
+		unlink(sTestFileName);
+#endif
+		free(sTestFileName);
+	}
+}
+
+void ensure (int condition, const char *message)
+{
+	if (!condition)
+	{
+		printf("%s.\n", message);
+		cleanup();
+		exit(EXIT_FAILURE);
+	}
+}
+
+int main (int argc, char **argv)
+{
+	printf("writeulaw: testing NeXT .snd.\n");
+	testulaw(AF_FILE_NEXTSND);
+	printf("writeulaw: testing AIFF-C.\n");
+	testulaw(AF_FILE_AIFFC);
+	printf("writeulaw: testing WAVE.\n");
+	testulaw(AF_FILE_WAVE);
+	printf("writeulaw: testing IRCAM.\n");
+	testulaw(AF_FILE_IRCAM);
+	printf("writeulaw: testing VOC.\n");
+	testulaw(AF_FILE_VOC);
+	printf("writeulaw: testing CAF.\n");
+	testulaw(AF_FILE_CAF);
+
+	printf("writeulaw test passed.\n");
+
+	exit(0);
+}
+
+void testulaw (int fileFormat)
+{
+	AFfilehandle	file;
+	AFfilesetup	setup;
+	uint16_t	samples[] = {8, 16, 80, 120, 180, 780, 924, 988,
+			1116, 1436, 1884, 8828, 9852, 15996, 19836, 32124};
+	uint16_t	readsamples[SAMPLE_COUNT];
+	AFframecount	framesWritten, framesRead;
+	int		i;
+
+	setup = afNewFileSetup();
+
+	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_G711_ULAW);
+	afInitFileFormat(setup, fileFormat);
+	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
+
+	ensure(createTemporaryFile("writeulaw", &sTestFileName),
+		"could not create temporary file");
+	file = afOpenFile(sTestFileName, "w", setup);
+	afFreeFileSetup(setup);
+
+	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
+		AF_COMPRESSION_G711_ULAW,
+		"test file not created with G.711 u-law compression");
+
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");
+
+	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
+		FRAME_COUNT);
+
+	ensure(framesWritten == FRAME_COUNT,
+		"number of frames requested does not match number of frames written");
+	afCloseFile(file);
+
+	/* Open the file for reading and verify the data. */
+	file = afOpenFile(sTestFileName, "r", NULL);
+	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");
+
+	ensure(afGetFileFormat(file, NULL) == fileFormat,
+		"test file format incorrect");
+
+	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
+		AF_COMPRESSION_G711_ULAW,
+		"test file not opened with G.711 u-law compression");
+
+	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
+		FRAME_COUNT);
+
+	ensure(framesRead == FRAME_COUNT,
+		"number of frames read does not match number of frames requested");
+
+#ifdef DEBUG
+	for (i=0; i<SAMPLE_COUNT; i++)
+		printf("readsamples[%d]: %d\n", i, readsamples[i]);
+	for (i=0; i<SAMPLE_COUNT; i++)
+		printf("samples[%d]: %d\n", i, samples[i]);
+#endif
+
+	for (i=0; i<SAMPLE_COUNT; i++)
+	{
+		ensure(samples[i] == readsamples[i],
+			"data written does not match data read");
+	}
+
+	/* G.711 compression uses one byte per sample. */
+	ensure(afGetTrackBytes(file, AF_DEFAULT_TRACK) == SAMPLE_COUNT,
+		"track byte count is incorrect");
+
+	ensure(afGetFrameCount(file, AF_DEFAULT_TRACK) == FRAME_COUNT,
+		"frame count is incorrect");
+
+	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
+		"channel count is incorrect");
+
+	ensure(afCloseFile(file) == 0, "error closing file");
+
+	cleanup();
+}

Fixed code: *.a
*.gcda
*.gcno
*.la
*.lo
*.log
*.o
*.trs
.DS_Store
.deps
.libs
ABOUT-NLS
COPYING
Makefile
Makefile.in
aclocal.m4
audiofile-uninstalled.pc
audiofile.pc
audiofile.spec
autom4te.cache
compile
config.cache
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
install-sh
intl
libtool
ltconfig
ltmain.sh
missing
mkinstalldirs
so_locations
stamp-h
stamp-h.in
stamp-h1
test-driver
version.h
Thanks to all who have contributed patches for the Audio File Library:
* Jason Allen
* Julien Boulnois
* Davy Durham
* Bruce Forsberg
* Fabrizio Gennari
* Simon Kagedal
* Thomas Klausner
* Daniel Kobras
* Michael Krause
* Wim Lewis
* Eric Mitchell
* Cristian Morales Vega
* Mark Murnane
* Michael Palimaka
* Jean-Francois Panisset
* Axel Roebel
* Matthias Rumpke
* Chris Wolf

Thanks to Douglas Scott of SGI for helping me understand the tricky parts
of the Audio File Library API.  Thanks to Chris Pirazzi and Scott Porter
of SGI for creating the Audio File Library in the first place.

Thanks also to all who have reported bugs.
Audio File Library Authors

Michael Pruett <michael@68k.org>

Chris Pirazzi, Scott Porter, and Doug Scott
                  GNU LESSER GENERAL PUBLIC LICENSE
                       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
not price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

                  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.

  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

                            NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

                     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!
                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
2016-08-29  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/SimpleModule.h:
	Fix undefined behavior in sign conversion.

2016-07-05  Joerg Krause <joerg.krause@embedded.rocks>

	* audiofile.pc.in:
	Link with FLAC for static builds.

2016-07-05  Michael Pruett <michael@68k.org>

	* test/Identify.cpp,
	test/Instrument.cpp,
	test/Loop.cpp,
	test/Lossless.h,
	test/NeXT.cpp,
	test/SampleFormat.cpp:
	Fix warnings in tests comparing integers to enums.

2016-07-05  Michael Pruett <michael@68k.org>

	* test/Identify.cpp,
	test/NeXT.cpp:
	Fix type of test data arrays.

2016-07-04  Nik Reiman <nik.reiman@gmail.com>

	* libaudiofile/modules/FLAC.cpp:
	Include <algorithm> in FLAC.cpp.

2016-07-04  Michael Pruett <michael@68k.org>

	* test/.gitignore,
	test/FormatWithChannels.cpp,
	test/Makefile.am:
	Add test for changing both sample format and channel count.

2016-07-04  Fabrizio Gennari <fabrizio.ge@tiscali.it>

	* libaudiofile/modules/ModuleState.cpp:
	Fix data corruption when changing both sample format and channel count.

2016-07-04  Nik Reiman <nik.reiman@gmail.com>

	* .gitignore:
	Add compile to .gitignore.

2016-07-04  Daniel Verkamp <daniel@drv.nu>

	* libaudiofile/CAF.cpp:
	Replace bzero() with memset().

2016-07-04  Christoph J. Thompson <cjsthompson@gmail.com>

	* Makefile.am,
	configure.ac:
	Allow configuring pkg-config installation directory.

2016-07-04  Michael Pruett <michael@68k.org>

	* autogen.sh:
	Replace custom configuration script with autoreconf.

2014-07-04  Michael Pruett <michael@68k.org>

	* libaudiofile/AVR.cpp,
	libaudiofile/IRCAM.cpp,
	libaudiofile/NIST.cpp,
	libaudiofile/Raw.cpp:
	Remove redundant initialization.

2014-05-26  Michael Pruett <michael@68k.org>

	* examples/Makefile.am,
	libaudiofile/modules/Makefile.am,
	sfcommands/Makefile.am,
	test/Makefile.am:
	Change INCLUDES to AM_CPPFLAGS.

2014-05-26  Michael Pruett <michael@68k.org>

	* configure.ac:
	Remove arguments to AM_INIT_AUTOMAKE.

2014-05-26  Michael Pruett <michael@68k.org>

	* gtest/*:
	Update Google Test framework to version 1.7.0.

2014-05-26  Michael Pruett <michael@68k.org>

	* docs/Makefile.am,
	docs/afIdentifyFD.3.txt,
	test/Identify.cpp,
	test/Makefile.am:
	Add tests and documentation for afIdentifyFD() and afIdentifyNamedFD().

2014-02-05  Michael Pruett <michael@68k.org>

	* libaudiofile/CAF.cpp,
	libaudiofile/FLACFile.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/VOC.cpp,
	test/Miscellaneous.cpp:
	Prohibit creating files with miscellaneous data for incapable file formats.

2014-02-05  Michael Pruett <michael@68k.org>

	* test/Miscellaneous.cpp:
	Refactor test for reading and writing miscellaneous data.

2014-02-05  Michael Pruett <michael@68k.org>

	* libaudiofile/CAF.cpp,
	libaudiofile/FLACFile.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/VOC.cpp,
	test/Instrument.cpp:
	Prohibit creating files with instruments for incapable file formats.

2013-03-12  Antoine Jacoutot <ajacoutot@bsdfrog.org>

	* configure.ac:
	Fix sanitization of FLAC_CFLAGS.

2013-03-10  Pino Toscano <toscano.pino@tiscali.it>

	* test/TestUtilities.cpp,
	test/TestUtilities.h,
	test/floatto24.c,
	test/sixteen-to-eight.c,
	test/testchannelmatrix.c,
	test/testdouble.c,
	test/testfloat.c,
	test/testmarkers.c,
	test/twentyfour.c,
	test/twentyfour2.c,
	test/writealaw.c,
	test/writeraw.c,
	test/writeulaw.c:
	Remove the usage of PATH_MAX in tests.

	Replace static PATH_MAX-sized buffers with dynamically allocated strings.

2013-03-07  Michael Pruett <michael@68k.org>

	* libaudiofile/g711.c:
	Fix compiler warning regarding discarding const qualification.

2013-03-07  Michael Pruett <michael@68k.org>

	* libaudiofile/g711.c:
	Remove unused G.711 tables.

2013-03-07  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/CAF.cpp,
	libaudiofile/FLACFile.cpp,
	libaudiofile/IFF.cpp,
	libaudiofile/IRCAM.cpp,
	libaudiofile/NIST.cpp,
	libaudiofile/Raw.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/VOC.cpp,
	libaudiofile/WAVE.cpp:
	Refactor accessing track setup from file setup.

2013-03-06  Michael Pruett <michael@68k.org>

	Release version 0.3.6 of the Audio File Library.

2013-03-06  Michael Pruett <michael@68k.org>

	* libaudiofile/alac/ALACDecoder.cpp,
	libaudiofile/alac/ag_enc.c:
	Fix unaligned memory accesses in ALAC.

	Thanks to Erik de Castro Lopo for pointing out this problem.

2013-03-05  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/WAVE.cpp,
	test/.gitignore,
	test/Instrument.cpp,
	test/Makefile.am:
	Fix instrument parameter validation.

2013-03-03  Michael Pruett <michael@68k.org>

	* libaudiofile/alac/ALACAudioTypes.h,
	libaudiofile/alac/EndianPortable.c:
	Fix byte order detection for ALAC.

2013-03-03  Michael Pruett <michael@68k.org>

	* libaudiofile/alac/EndianPortable.c,
	libaudiofile/alac/ag_dec.c,
	libaudiofile/alac/ag_enc.c:
	Eliminate unnecessary header inclusion in ALAC source files.

2013-03-03  Michael Pruett <michael@68k.org>

	* libaudiofile/alac/ALACEncoder.cpp:
	Write ALAC channel layout tag in big-endian byte order.

2013-03-03  Michael Pruett <michael@68k.org>

	* libaudiofile/alac/ALACEncoder.cpp:
	Remove superfluous debugging print statements in ALAC encoder.

2013-02-27  Michael Pruett <michael@68k.org>

	Update address for Free Software Foundation.

2013-02-26  Michael Pruett <michael@68k.org>

	Update license to LGPL 2.1.

2013-02-21  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am:
	Add support for running unit tests under Valgrind.

2013-02-20  Cristian Morales Vega <reddwarf@opensuse.org>

	* configure.ac:
	Add option for building without example programs.

2013-02-20  Michael Pruett <michael@68k.org>

	* README,
	configure.ac,
	docs/afInitCompression.3.txt,
	docs/sfconvert.1.txt,
	libaudiofile/Buffer.cpp,
	libaudiofile/Buffer.h,
	libaudiofile/CAF.cpp,
	libaudiofile/CAF.h,
	libaudiofile/Makefile.am,
	libaudiofile/PacketTable.cpp,
	libaudiofile/PacketTable.h,
	libaudiofile/Track.cpp,
	libaudiofile/Track.h,
	libaudiofile/afinternal.h,
	libaudiofile/alac/ALACAudioTypes.h,
	libaudiofile/alac/ALACBitUtilities.c,
	libaudiofile/alac/ALACBitUtilities.h,
	libaudiofile/alac/ALACDecoder.cpp,
	libaudiofile/alac/ALACDecoder.h,
	libaudiofile/alac/ALACEncoder.cpp,
	libaudiofile/alac/ALACEncoder.h,
	libaudiofile/alac/EndianPortable.c,
	libaudiofile/alac/EndianPortable.h,
	libaudiofile/alac/Makefile.am,
	libaudiofile/alac/ag_dec.c,
	libaudiofile/alac/ag_enc.c,
	libaudiofile/alac/aglib.h,
	libaudiofile/alac/dp_dec.c,
	libaudiofile/alac/dp_enc.c,
	libaudiofile/alac/dplib.h,
	libaudiofile/alac/matrix_dec.c,
	libaudiofile/alac/matrix_enc.c,
	libaudiofile/alac/matrixlib.h,
	libaudiofile/audiofile.h,
	libaudiofile/modules/ALAC.cpp,
	libaudiofile/modules/ALAC.h,
	libaudiofile/modules/Makefile.am,
	libaudiofile/modules/ModuleState.cpp,
	libaudiofile/units.cpp,
	libaudiofile/units.h,
	sfcommands/sfconvert.c,
	test/.gitignore,
	test/ALAC.cpp,
	test/Makefile.am:
	Add support for ALAC.

2013-02-19  Michael Pruett <michael@68k.org>

	* README,
	configure.ac,
	docs/afInitCompression.3.txt,
	docs/sfconvert.1.txt,
	libaudiofile/FLACFile.cpp,
	libaudiofile/FLACFile.h,
	libaudiofile/Features.h,
	libaudiofile/FileHandle.cpp,
	libaudiofile/Makefile.am,
	libaudiofile/audiofile.h,
	libaudiofile/data.cpp,
	libaudiofile/modules/FLAC.cpp,
	libaudiofile/modules/FLAC.h,
	libaudiofile/modules/FileModule.cpp,
	libaudiofile/modules/FileModule.h,
	libaudiofile/modules/G711.cpp,
	libaudiofile/modules/G711.h,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/IMA.h,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/MSADPCM.h,
	libaudiofile/modules/Makefile.am,
	libaudiofile/modules/ModuleState.cpp,
	libaudiofile/modules/ModuleState.h,
	libaudiofile/modules/PCM.cpp,
	libaudiofile/modules/PCM.h,
	libaudiofile/units.cpp,
	libaudiofile/units.h,
	sfcommands/sfconvert.c,
	test/.gitignore,
	test/FLAC.cpp,
	test/Lossless.h,
	test/Makefile.am:
	Add support for FLAC.

2013-02-10  Michael Pruett <michael@68k.org>

	* libaudiofile/FileHandle.cpp,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/SimpleModule.h:
	Fix uninitialized fields in constructors.

2013-02-09  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/BlockCodec.cpp,
	libaudiofile/modules/BlockCodec.h,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/Makefile.am:
	Factor out fixed-size block codec functionality common to IMA and MS ADPCM.

2013-02-09  Michael Pruett <michael@68k.org>

	* test/InvalidCompressionFormat.cpp,
	test/InvalidSampleFormat.cpp,
	test/Query.cpp:
	Ignore errors in tests for which errors are expected.

2013-02-09  Michael Pruett <michael@68k.org>

	* test/PCMData.cpp:
	Update PCMData test to validate PCM mappings.

2013-02-09  Michael Pruett <michael@68k.org>

	* libaudiofile/CAF.cpp,
	libaudiofile/IFF.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/VOC.cpp,
	test/AES.cpp:
	Ensure that initializing AES data fails on unsupported file formats.

2013-02-05  Michael Pruett <michael@68k.org>

	* Release version 0.3.5 of the Audio File Library.

2013-02-04  Michael Pruett <michael@68k.org>

	* gtest/Makefile.am,
	libaudiofile/Makefile.am,
	test/Makefile.am:
	Disable exceptions and RTTI when building Google Test framework.

2013-02-04  Michael Pruett <michael@68k.org>

	* libaudiofile/File.cpp,
	libaudiofile/File.h:
	Fix resource leak in File destructor.

2013-02-02  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am,
	libaudiofile/modules/Makefile.am:
	Remove test coverage files when cleaning.

2013-02-02  Michael Pruett <michael@68k.org>

	* libaudiofile/IRCAM.cpp:
	Fix calculation of IRCAM frame size.

2013-02-02  Michael Pruett <michael@68k.org>

	* test/PCMData.cpp:
	Update PCMData test to create multi-channel audio files.

2013-01-31  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/CAF.cpp:
	Report error when attempting to open a file with invalid sample width.

2013-01-31  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/CAF.cpp,
	libaudiofile/NeXT.cpp,
	libaudiofile/VOC.cpp,
	libaudiofile/WAVE.cpp:
	Report error when attempting to open a file with zero channels.

2013-01-31  Michael Pruett <michael@68k.org>

	* test/NeXT.cpp:
	Add test for opening a NeXT sound file with zero channels.

2013-01-30  Michael Pruett <michael@68k.org>

	* libaudiofile/NIST.cpp:
	Remove unnecessary check for positive channel count.

	This check is already performed in afInitChannels().

2013-01-30  Michael Pruett <michael@68k.org>

	* libaudiofile/SampleVision.cpp:
	Set compression type before initializing sample format.

2013-01-30  Michael Pruett <michael@68k.org>

	* test/TestUtilities.cpp:
	Include <unistd.h> to provide declaration of close().

2013-01-30  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.h,
	libaudiofile/AVR.h,
	libaudiofile/CAF.h,
	libaudiofile/Compiler.h,
	libaudiofile/IFF.h,
	libaudiofile/IRCAM.h,
	libaudiofile/NIST.h,
	libaudiofile/NeXT.h,
	libaudiofile/SampleVision.h,
	libaudiofile/VOC.h,
	libaudiofile/WAVE.h,
	libaudiofile/modules/G711.cpp,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/PCM.cpp,
	libaudiofile/modules/RebufferModule.h,
	libaudiofile/modules/SimpleModule.h:
	Use C++11 override keyword with compilers that support it.

2013-01-19  Michael Pruett <michael@68k.org>

	* libaudiofile/CAF.cpp,
	libaudiofile/util.cpp:
	Fix conversion specifications in error messages.

2013-01-19  Michael Pruett <michael@68k.org>

	* libaudiofile/format.cpp,
	test/Makefile.am,
	test/SampleFormat.cpp:
	Fix null checks in afGetSampleFormat() and afGetVirtualSampleFormat().

	Thanks to David Lassonde for pointing out this problem.

2013-01-19  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/AudioFormat.h,
	libaudiofile/CAF.cpp,
	libaudiofile/NeXT.cpp,
	libaudiofile/VOC.cpp,
	libaudiofile/WAVE.cpp,
	libaudiofile/modules/G711.cpp,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/ModuleState.cpp,
	test/InvalidCompressionFormat.cpp:
	Validate compressed audio formats.

2012-11-13  Michael Pruett <michael@68k.org>

	* configure.ac, docs/Makefile.am:
	Add support for building without documentation.

2012-11-12  Michael Pruett <michael@68k.org>

	* libaudiofile/File.cpp:
	Open files in binary mode on Windows.

	Thanks to Fabrizio Gennari for proposing this change.

2012-10-13  Michael Pruett <michael@68k.org>

	* test/*:
	Use unique filenames for temporary files in tests.

	Thanks to Giovanni Mascellani for pointing out this problem.

	http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=687405

2012-09-12  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/AVR.cpp,
	libaudiofile/AudioFormat.cpp,
	libaudiofile/AudioFormat.h,
	libaudiofile/CAF.cpp,
	libaudiofile/CAF.h,
	libaudiofile/IFF.cpp,
	libaudiofile/IRCAM.cpp,
	libaudiofile/NIST.cpp,
	libaudiofile/NeXT.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/Track.cpp,
	libaudiofile/Track.h,
	libaudiofile/VOC.cpp,
	libaudiofile/WAVE.cpp:
	Refactor calculation of frame count from audio data size.

2012-09-06  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am, libaudiofile/modules/Makefile.am:
	Reorganize build.

2012-09-06  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp,
	libaudiofile/AIFF.h,
	libaudiofile/CAF.cpp,
	libaudiofile/SampleVision.cpp,
	libaudiofile/VOC.cpp,
	libaudiofile/WAVE.cpp,
	libaudiofile/WAVE.h,
	libaudiofile/util.cpp,
	libaudiofile/util.h,
	test/Makefile.am,
	test/Marker.cpp:
	Refactor marker writing. Record marker comments in WAVE files.

2012-07-31  Michael Pruett <michael@68k.org>

	* libaudiofile/Setup.cpp:
	Fix array overrun in afInitFileFormat().

2012-07-31  Michael Pruett <michael@68k.org>

	* libaudiofile/query.cpp, test/Makefile.am, test/Query.cpp:
	Fix handling of queries for unimplemented compression formats.

2012-07-31  Michael Pruett <michael@68k.org>

	* libaudiofile/AudioFormat.cpp, libaudiofile/compression.cpp,
	libaudiofile/compression.h, libaudiofile/debug.cpp,
	libaudiofile/modules/ModuleState.cpp, libaudiofile/query.cpp,
	libaudiofile/util.cpp:
	Refactor accessing compression units by compression type.

2012-07-31  Michael Pruett <michael@68k.org>

	* libaudiofile/compression.cpp, libaudiofile/format.cpp,
	libaudiofile/modules/ModuleState.cpp, libaudiofile/openclose.cpp,
	libaudiofile/query.cpp, libaudiofile/units.cpp,
	libaudiofile/units.h:
	Remove leading underscores from _Unit and _CompressionUnit types.

2012-07-31  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/ModuleState.cpp:
	Improve error handling in ModuleState::arrange().

2012-07-26  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp, libaudiofile/NeXT.cpp,
	libaudiofile/Setup.cpp, libaudiofile/WAVE.cpp,
	libaudiofile/format.cpp, libaudiofile/modules/G711.cpp,
	libaudiofile/modules/IMA.cpp, libaudiofile/modules/PCM.cpp:
	Remove unnecessary debugging print statements.

2012-07-21  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/RebufferModule.cpp,
	libaudiofile/modules/UT_RebufferModule.cpp:
	Fix error in rebuffer module when buffering after pulling a short chunk.

2012-07-14  Michael Pruett <michael@68k.org>

	* libaudiofile/SampleVision.cpp, libaudiofile/compression.cpp:
	Report an error when initializing a file with an invalid compression format.

2012-07-14  Michael Pruett <michael@68k.org>

	* test/InvalidCompressionFormat.cpp, test/Makefile.am:
	Add test for creating audio files with invalid compression formats.

2012-07-14  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp, libaudiofile/AIFF.h:
	Refactor discrimination between AIFF and AIFF-C.

2012-07-14  Michael Pruett <michael@68k.org>

	* Prefix member variables with 'm_'.

2012-07-14  Michael Pruett <michael@68k.org>

	* Mark default file setup structures as constant.

2012-07-14  Michael Pruett <michael@68k.org>

	* Refactor file handle initialization.

2012-07-05  Michael Pruett <michael@68k.org>

	* docs/sfconvert.1.txt, sfcommands/sfconvert.c:
	Add support for compression to sfconvert.

2012-07-05  Michael Pruett <michael@68k.org>

	* docs/afInitCompression.3.txt,
	libaudiofile/WAVE.cpp,
	libaudiofile/WAVE.h,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/MSADPCM.h,
	libaudiofile/units.cpp,
	test/ADPCM.cpp:
	Implement Microsoft ADPCM encoding for WAVE files.

2012-07-05  Michael Pruett <michael@68k.org>

	* docs/afInitCompression.3.txt,
	libaudiofile/AIFF.cpp,
	libaudiofile/AIFF.h,
	libaudiofile/CAF.cpp,
	libaudiofile/CAF.h,
	libaudiofile/WAVE.cpp,
	libaudiofile/WAVE.h,
	libaudiofile/afinternal.h,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/IMA.h,
	libaudiofile/modules/Makefile.am,
	libaudiofile/units.cpp,
	test/ADPCM.cpp,
	test/Makefile.am:
	Implement IMA ADPCM encoding and decoding for AIFF-C, CAF, and WAVE files.

2012-07-05  Michael Pruett <michael@68k.org>

	* libaudiofile/AudioFormat.h,
	libaudiofile/WAVE.cpp,
	libaudiofile/afinternal.h,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp:
	Add framesPerPacket and bytesPerPacket fields to AudioFormat.

2012-07-05  Michael Pruett <michael@68k.org>

	* libaudiofile/data.cpp, libaudiofile/modules/Module.h:
	Fix mismatched deallocation of temporary buffer in afReadFrames.

2012-07-01  Michael Pruett <michael@68k.org>

	* sfcommands/sfconvert.c: Improve error handling in sfconvert.

2012-07-01  Michael Pruett <michael@68k.org>

	* sfcommands/Makefile.am, sfcommands/sfconvert.c:
	Clean up sfconvert.

2012-07-01  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/FileModule.cpp,
	libaudiofile/modules/FileModule.h,
	libaudiofile/modules/G711.cpp,
	libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp,
	libaudiofile/modules/PCM.cpp:
	Refactor error reporting in file modules.

2012-06-21  Michael Pruett <michael@68k.org>

	* libaudiofile/SampleVision.cpp: Fix comparisons between signed
	and unsigned integers.

2012-06-21  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp, libaudiofile/IFF.cpp,
	libaudiofile/WAVE.cpp, libaudiofile/modules/MSADPCM.cpp:
	Remove unused variables.

2012-06-21  Michael Pruett <michael@68k.org>

	* libaudiofile/AVR.cpp, libaudiofile/Marker.cpp,
	libaudiofile/NIST.cpp, libaudiofile/NeXT.cpp,
	libaudiofile/Setup.cpp, libaudiofile/error.h,
	libaudiofile/modules/G711.cpp, libaudiofile/modules/IMA.cpp,
	libaudiofile/modules/MSADPCM.cpp, libaudiofile/modules/PCM.cpp:
	Fix conversion specifications in error messages.

2012-06-21  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/ModuleState.cpp,
	libaudiofile/modules/RebufferModule.cpp,
	libaudiofile/modules/RebufferModule.h
	libaudiofile/modules/UT_RebufferModule.cpp:
	Refactor rebuffer module.

2012-05-20  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/RebufferModule.cpp: Fix error in rebuffering
	when pulling multiple blocks at once.

2012-05-20  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am,
	libaudiofile/modules/UT_RebufferModule.cpp: Add unit test for
	rebuffer module.

2012-05-20  Michael Pruett <michael@68k.org>

	* Move Google Test framework to top of source tree.

2012-05-20  Michael Pruett <michael@68k.org>

	* Reorganize code coverage build configuration.

2012-05-10  Michael Pruett <michael@68k.org>

	* docs/*: Update documentation.

2012-05-06  Michael Pruett <michael@68k.org>

	* docs/sfconvert.1.txt, sfcommands/sfconvert.c: Add support for
	Sample Vision to sfconvert.

2012-05-06  Michael Pruett <michael@68k.org>

	* Update documentation to include support for Sample Vision.

2012-05-06  Michael Pruett <michael@68k.org>

	* libaudiofile/VOC.cpp: Report an error when initializing a VOC file
	with an invalid sample format.

2012-05-06  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/InvalidSampleFormat.cpp: Add test for
	creating audio files with invalid sample formats.

2012-05-06  Michael Pruett <michael@68k.org>

	* Reorganize tests.

2012-04-30  Michael Pruett <michael@68k.org>

	* Release version 0.3.4 of the Audio File Library.

2012-04-29  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/pipe.cpp: Add test for reading and writing
	with non-seekable file handles.

2012-04-29  Michael Pruett <michael@68k.org>

	* Add support for SampleVision format.

2012-04-29  Michael Pruett <michael@68k.org>

	* sfcommands/printinfo.c: Fix field width for sample rate when
	printing short information.

2012-04-29  Michael Pruett <michael@68k.org>

	* examples/alsaplay.cpp: Update alsaplay to wait for samples to
	finish playing before closing.

2012-04-18  Michael Pruett <michael@68k.org>

	* Use hidden visibility for internal symbols.

	Previously all symbols had default visibility, leading to possible symbol
	conflicts. Thanks to Thomas Eschenbacher for pointing out this problem.

2012-01-17  Michael Pruett <michael@68k.org>

	* libaudiofile/extended.c: Update license for extended-precision
	floating-point conversion routines.

2012-01-11  Michael Pruett <michael@68k.org>

	* Release version 0.3.3 of the Audio File Library.

2012-01-11  Michael Pruett <michael@68k.org>

	* configure.ac: Update library's soname version.

	Changing the definitions of AFframecount and AFfileoffset breaks
	backwards binary compatibility and requires incrementing the
	soname version.

2012-01-11  Michael <kensington@astralcloak.net>

	* examples/Makefile.am, test/Makefile.am: Link examples/power
	and test/printmarkers explicitly against libm.

2012-01-11  Matthias Rampke <matthias@rampke.de>

	* libaudiofile/Makefile.am: Link against libm.

2011-12-04  Michael Pruett <michael@68k.org>

	* Refactor file handle and track creation and destruction.

2001-11-30  Thomas Klausner <wiz@NetBSD.org>

	* configure.ac: Replace nonstandard '==' operator with '=' in test
	expressions.

2011-11-29  Michael Pruett <michael@68k.org>

	* Release version 0.3.2 of the Audio File Library.

2011-11-28  Michael Pruett <michael@68k.org>

	* libaudiofile/VOC.cpp: Fix initialization of byte order in
	Creative Voice File format.

2011-10-20  Michael Pruett <michael@68k.org>

	* libaudiofile/NIST.cpp: Fix calculation of frame count in NIST
	SPHERE sound files.

2011-10-20  Michael Pruett <michael@68k.org>

	* libaudiofile/byteorder.h: Remove unused byte-swapping macros.

2011-10-20  Michael Pruett <michael@68k.org>

	* Simplify calculation of track data size.

2011-10-11  Michael Pruett <michael@68k.org>

	* libaudiofile/af_vfs.h: Remove duplicate definition of AFvirtualfile.

2011-09-19  Michael Pruett <michael@68k.org>

	* Don't treat compiler warnings as errors by default.

2011-09-18  Michael Pruett <michael@68k.org>

	* Released version 0.3.1 of the Audio File Library.

2011-09-17  Michael Pruett <michael@68k.org>

	* Support u-law and A-law compression in Core Audio Format files.

2011-09-17  Michael Pruett <michael@68k.org>

	* Add support for Creative Voice File format.

2011-09-14  Michael Pruett <michael@68k.org>

	* docs/Makefile.am: Fix installation of man pages.

2011-09-14  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/channelmatrix.cpp: Add test for channel
	matrix.

2011-09-12  Michael Pruett <michael@68k.org>

	* Released version 0.3.0 of the Audio File Library.

2011-09-11  Michael Pruett <michael@68k.org>

	* Define AFframecount and AFfileoffset as 64-bit signed integers.

	Previously these types were defined using off_t, whose size can vary
	depending upon whether large file support is enabled. Now the library
	is built with large file support and the API uses 64-bit frame counts
	and file offsets.

2011-08-20  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/aes.cpp: Add test for reading and writing
	AES channel data.

2011-08-20  Michael Pruett <michael@68k.org>

	* libaudiofile/AIFF.cpp, libaudiofile/Instrument.cpp,
	libaudiofile/Instrument.h, libaudiofile/Loop.cpp,
	libaudiofile/Setup.cpp, libaudiofile/Setup.h, test/Makefile.am,
	test/loop.cpp: Fix initialization of loop data.

2011-08-16  Michael Pruett <michael@68k.org>

	* win32: Remove obsolete Windows project files.

2011-05-07  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am,  libaudiofile/WAVE.{cpp,h},
	libaudiofile/UUID.{cpp,h}: Add support for extensible WAVE format.

2011-04-16  Michael Pruett <michael@68k.org>

	* Refactor file parsing and writing. Update VFS interface.

2011-04-11  Michael Pruett <michael@68k.org>

	* Reorganize source files.

2011-04-11  Michael Pruett <michael@68k.org>

	* Support more sample formats in IRCAM sound files.

2011-04-04  Michael Pruett <michael@68k.org>

	* Add support for Core Audio Format.

2011-04-04  Michael Pruett <michael@68k.org>

	* libaudiofile/IRCAM.cpp, libaudiofile/IRCAM.h,
	libaudiofile/IRCAMWrite.cpp: Handle byte-swapped IRCAM sound files.

2011-04-04  Michael Pruett <michael@68k.org>

	* test/pcmdata.cpp, test/Makefile.am: Test reading and writing
	PCM data formats supported by each file format.

2011-03-29  Michael Pruett <michael@68k.org>

	* test/large.cpp, test/seek.cpp, test/Makefile.am: Convert large
	and seek test cases to use Google Test framework.

2011-03-27  Michael Pruett <michael@68k.org>

	* docs/*: Update documentation and convert to AsciiDoc format.

2011-03-27  Michael Pruett <michael@68k.org>

	* sfcommands/sfconvert.c: Update help message for sfconvert to
	include NIST SPHERE format.

2011-03-27  Michael Pruett <michael@68k.org>

	* sfcommands/sfconvert.c, sfcommands/sfinfo.c,
	sfcommands/printinfo.[ch]: Add --short and --reporterror options
	to sfinfo. Add --help and --version options to sfconvert and
	sfinfo.

2011-03-27  Michael Pruett <michael@68k.org>

	* libaudiofile/NeXT.cpp, test/Makefile.am, test/next.cpp: Fix handling
	of NeXT sound files with unspecified or inconsistent length.

2011-01-16  Michael Pruett <michael@68k.org>

	* libaudiofile/audiofile.h, libaudiofile/Loop.cpp,
	libaudiofile/Marker.cpp, libaudiofile/Miscellaneous.cpp,
	libaudiofile/Track.cpp, libaudiofile/util.cpp, libaudiofile/util.h:
	Change type of id arrays in initialization functions from int *
	to const int *.

2011-01-16  Michael Pruett <michael@68k.org>

	* Refactor file parsing and writing.

2011-01-12  Stefano Magni <stefano.magni@akerue.it>

	* libaudiofile/openclose.cpp: Fix leak of miscellaneous data buffers.

2011-01-12  Michael Pruett <michael@68k.org>

	* libaudiofile/IFF.cpp: Allow writing miscellaneous data in IFF/8SVX files.

2011-01-12  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/miscellaneous.cpp: Add test for reading and
	writing miscellaneous data.

2011-01-12  Michael Pruett <michael@68k.org>

	* libaudiofile/audiofile.h, libaudiofile/Miscellaneous.cpp: Change
	type of buffer parameter of afWriteMisc() from void * to const void *.

2011-01-09  Michael Pruett <michael@68k.org>

	* configure.ac, test/Makefile.am: Support running tests under Valgrind.

2011-01-01  Michael Pruett <michael@68k.org>

	Convert library implementation to C++; refactor file parsing and writing.

2010-12-02  Michael Pruett <michael@68k.org>

	Use local copy of Google Test framework.

2010-11-29  Michael Pruett <michael@68k.org>

	Refactor rebuffering module.

2010-11-14  Michael Pruett <michael@68k.org>

	Refactor audio conversion.

2010-11-14  Michael Pruett <michael@68k.org>

	Refactor file I/O.

	Eliminate VFS interface since it cannot support large files or provide
	context for handling error conditions.

2010-10-30  Michael Pruett <michael@68k.org>

	* examples/Makefile.am, examples/alsaplay.cpp: Add example
	program demonstrating audio file playback using ALSA.

2010-10-30  Michael Pruett <michael@68k.org>

	* test/floattoint.cpp, test/inttofloat.cpp, test/pcmmapping.cpp,
	test/sign.cpp: Add tests for converting between integer and
	floating-point audio data, between signed and unsigned integer
	audio data, and between audio data with different PCM mappings.

2010-09-20  Michael Pruett <michael@68k.org>

	* libaudiofile/pcm.h, test/floatto24.c: Update default mapping
	between floating-point and integer audio data.

	Map N-bit integer audio data to [-1, 1) rather than the previous
	range of [-1 - 1/(2^N - 1), 1].

2010-09-11  Michael Pruett <michael@68k.org>

	* configure.ac, Makefile.am, libaudiofile/Makefile.am,
	libaudiofile/modules/Makefile.am, test/Makefile.am: Enable code
	coverage reporting with lcov.

2010-09-11  Michael Pruett <michael@68k.org>

	* audiofile-config.in, audiofile.m4: Remove configuration files
	superseded by pkg-config.

2010-04-14  Brian Cameron <brian.cameron@oracle.com>

	* audiofile-uninstalled.pc.in, configure.ac: Add uninstalled
	pkg-config file.

2010-03-29  Michael Pruett <michael@68k.org>

	* libaudiofile/af_vfs.h: Specify C linkage.

2010-03-25  Daniel Kobras <kobras@debian.org>

	* libaudiofile/af_vfs.h: Include <audiofile.h>.

2010-03-25  Daniel Kobras <kobras@debian.org>

	* audiofile.pc.in: Link against libm only for static builds.

2010-03-21  Michael Pruett <michael@68k.org>

	* Released version 0.2.7 of the Audio File Library.

2010-03-21  Michael Pruett <michael@68k.org>

	* libaudiofile/wavewrite.c: Write fact chunk in WAVE files
	with floating-point audio data.

2010-03-21  Michael Pruett <michael@68k.org>

	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
	libaudiofile/iff.c, libaudiofile/iffwrite.c,
	libaudiofile/util.c, libaudiofile/util.h, libaudiofile/wave.c,
	libaudiofile/wavewrite.c: Add convenience functions for reading
	and writing bytes and Pascal strings.

2010-03-18  Michael Pruett <michael@68k.org>

	* libaudiofile/wave.c, libaudiofile/wavewrite.c: Add support
	for writing double-precision floating-point WAVE files.

	* test/Makefile.am, test/testdouble.c: Add test for reading and
	writing double-precision floating-point audio files.

2010-03-18  Michael Pruett <michael@68k.org>

	* libaudiofile/aiffwrite.c, libaudiofile/avr.c, libaudiofile/ircam.c,
	libaudiofile/next.c, libaudiofile/raw.c, libaudiofile/wave.c,
	libaudiofile/wavewrite.c: Fix handling of audio files with more than
	2^24 frames.

	* test/Makefile.am, test/large.c: Add test for reading and writing
	audio files with more than 2^24 frames.

2010-03-17  Michael Pruett <michael@68k.org>

	* Mark module function tables as constant.

2010-03-17  Jason Allen <lorddut@gmail.com>

	* Mark data as constant in order to minimize unshared data.

2010-03-16  Michael Pruett <michael@68k.org>

	* Use C99 bool type.

2010-03-16  Michael Pruett <michael@68k.org>

	* libaudiofile/afinternal.h, libaudiofile/modules/adpcm.c,
	libaudiofile/modules/adpcm.h, libaudiofile/modules/ima.c,
	libaudiofile/modules/msadpcm.c, libaudiofile/wave.c: Fix decoding
	of multi-channel ADPCM audio files.

2010-03-15  Michael Pruett <michael@68k.org>

	* Use C99 integer types.

2010-03-12  Wim Lewis <wiml@omnigroup.com>

	* libaudiofile/debug.c, libaudiofile/modules/msadpcm.c,
	libaudiofile/modules/ima.c, libaudiofile/wavewrite.c,
	libaudiofile/query.c: Remove unused variables and fix warnings.

2004-11-14  Michael Pruett <michael@68k.org>

	* libaudiofile/aiff.c: Add support for reading more nonstandard
	uncompressed two's complement AIFF-C files created by Mac OS X.

2004-09-14  Michael Pruett <michael@68k.org>

	* libaudiofile/aiff.c: Add support for reading nonstandard
	uncompressed AIFF-C files created by Mac OS X.

2004-07-21  Michael Pruett <michael@68k.org>

	* examples/power.c: Change invocations of 'abs' to 'fabs' since
	arguments are doubles.

	* sfcommands/sfconvert.c: Add support for converting to the NIST
	SPHERE file format.

2004-06-26  Michael Pruett <michael@68k.org>

	* libaudiofile/aiff.c, libaudiofile/aiff.h, libaudiofile/aiffwrite.c,
	libaudiofile/next.c, libaudiofile/nextwrite.c, libaudiofile/wave.c,
	libaudiofile/wavewrite.c: Clean up AIFF, WAVE, and NeXT file parsing
	and writing code by using af_{read,write}_uint{16,32}_{be,le} where
	appropriate.

2004-04-14  Michael Pruett <michael@68k.org>

	* configure.in: Update configure.in to conform to current
	autoconf conventions.

	Thanks to Nico Roeser for this patch.

2004-03-29  Michael Pruett <michael@68k.org>

	* docs/*: Update documentation.

2004-03-11  Michael Pruett <michael@68k.org>

	* audiofile.m4: Quote AM_PATH_AUDIOFILE in order to fix
	automake warning.

	* libaudiofile/Makefile.am: Prepend audiofile.exports with
	$(srcdir) in order to allow building from another directory.

	Thanks to Frederic L. W. Meunier for these fixes.

	* libaudiofile/audiofile.exports: Add VFS functions to list of
	exported symbols.

	Thanks to Daniel Kobras for pointing out this omission.

2004-03-05  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am, libaudiofile/audiofile.exports:
	Export only public entry points.

	* Released version 0.2.6 of the Audio File Library.

2004-02-19  Michael Pruett <michael@68k.org>

	* libaudiofile/audiofile.h: Update comments to reflect the fact
	that AVR and IFF/8SVX file formats are now implemented.

2004-02-18  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/writeavr.c. test/writeiff.c,
	test/writenist.c: Add regression tests for AVR, IFF/8SVX, and
	NIST SPHERE file formats.

2004-02-14  Michael Pruett <michael@68k.org>

	* configure.in, examples/Makefile.am, examples/osxplay.c: Add
	example program for Mac OS X demonstrating audio file playback
	using the Audio File Library and Core Audio.

2004-02-09  Michael Pruett <michael@68k.org>

	Fabrizio Gennari has contributed several Windows-related fixes:

	* libaudiofile/openclose.c, win32/config.h: Open files with
	binary translation mode under MinGW and Cygwin.
	* win32/sfinfo.dsp: Link against non-debug version of libaudiofile
	when building non-debug version of sfinfo.
	* win32/*: Sychronize MSVC project files with latest source code.

2004-01-27  Michael Pruett <michael@68k.org>

	* libaudiofile/afinternal.h, libaudiofile/openclose.c: Store
	file name in AFfilehandle structure.

	* libaudiofile/Makefile.am, libaudiofile/avr.c,
	libaudiofile/avr.h, libaudiofile/avrwrite.c,
	libaudiofile/units.c: Add support for reading and writing AVR
	files.

2004-01-22  Michael Pruett <michael@68k.org>

	* libaudiofile/util.[ch]: Add functions for reading and writing
	16-bit and 32-bit integers with specified byte order.

	* libaudiofile/Makefile.am, libaudiofile/iff.c,
	libaudiofile/iff.h, libaudiofile/iffwrite.c,
	libaudiofile/units.c: Add support for reading and writing
	IFF/8SVX files.

2004-01-15  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am, libaudiofile/nist.c,
	libaudiofile/nist.h, libaudiofile/nistwrite.c: Add support for
	reading and writing NIST SPHERE files.

	* libaudiofile/audiofile.h: Add constants for new file
	formats.

	* libaudiofile/units.c, libaudiofile/units.h: Define units for
	new file formats.

2004-01-12  Michael Pruett <michael@68k.org>

	* libaudiofile/Makefile.am, libaudiofile/util.[ch],
	libaudiofile/debug.[ch]: Move debugging routines into a
	separate file.

	* libaudiofile/modules.c: Include "debug.h" for debugging
	routines.

2004-01-06  Michael Pruett <michael@68k.org>

	* libaudiofile/afinternal.h, libaudiofile/aiff.h,
	libaudiofile/aiffwrite.c: Eliminate duplicate definition of
	AIFC_VERSION_1 constant.

2003-12-21  Michael Pruett <michael@68k.org>

	* Released version 0.2.5 of the Audio File Library.

2003-12-20  Michael Pruett <michael@68k.org>

	* test/seek.c: Delete temporary file before exiting.

2003-12-17  Michael Pruett <michael@68k.org>

	* libaudiofile/aiff.c: When reading an AIFF-C file with an
	unknown compression type, return an error.

	* libaudiofile/aiff.c: Skip zero-length miscellaneous chunks.

	* libaudiofile/aiff.c: Add support for reading AIFF-C files with
	little-endian audio data.

2003-12-17  Michael Pruett <michael@68k.org>

	Fix two bugs related to processing 24-bit audio data.

	* libaudiofile/data.c: Fix calculation of bytes per virtual frame
	in the case of 24-bit audio data.  Previously, requesting more
	than _AF_ATOMIC_NVFRAMES from afReadFrames when reading a 24-bit
	audio file would result in corrupted audio data since the audio
	data pointer would be incremented using a sample size of 3 bytes
	rather than 4 bytes.

	* libaudiofile/openclose.c: Set virtual sample width by default to
	the same value as file sample width.  Previously for 24-bit audio
	data, the virtual sample width would be incorrectly set to 32.

	* test/twentyfour2.c: Add new test which checks reading and
	writing a large amount of 24-bit audio data.  This program
	serves as a regression test for a bug in the Audio File Library
	in which requesting more than 1024 frames (_AF_ATOMIC_NVFRAMES)
	from afReadFrames when reading a 24-bit audio file would result
	in corrupted audio data.

2003-12-08  Michael Pruett <michael@68k.org>

	* examples/*, test/*: Add examples subdirectory. Separate
	example programs from regression test programs. Remove obsolete
	test programs.

2003-12-03  Michael Pruett <michael@68k.org>

	* sfcommands/sfconvert.c: Fix argument parsing in sfconvert.
	* sfcommands/printinfo.c: Fix format strings to handle different
	sizes of off_t when printing track byte count, data offset,
	and frame count.

2003-10-01  Michael Pruett <michael@68k.org>

	* sfcommands/printinfo.c: Change printfileinfo to display duration
	with millisecond accuracy.

2003-09-29  Michael Pruett <michael@68k.org>

	* test/seek.c: Include <string.h> for memcmp.  Thanks to Christian
	Weisgerber for catching this omission.

2003-09-25  Michael Pruett <michael@68k.org>

	* Released version 0.2.4 of the Audio File Library.

2003-09-24  Michael Pruett <michael@68k.org>

	* libaudiofile/afinternal.h: Remove unused structure definitions.
	* libaudiofile/audiofile.h: Correct return type of afTellFrame
	to be AFframecount rather than AFfileoffset.

2003-09-23  Michael Pruett <michael@68k.org>

	* libaudiofile/modules/ima.c: Include <config.h>.

2003-09-16  Michael Pruett <michael@68k.org>

	* libaudiofile/audiofile.h: Define LIBAUDIOFILE_MICRO_VERSION.

2003-09-15  Michael Pruett <michael@68k.org>

	* test/Makefile.am, test/seek.c: Add test case for seeking within
	an audio file.

2003-09-11  Michael Pruett <michael@68k.org>

	* test/*.c: Update tests to use exit(EXIT_FAILURE) upon abnormal
	termination.

2003-09-11  Michael Pruett <michael@68k.org>

	* libaudiofile/wave.c, libaudiofile/wavewrite.c: Add support
	for miscellaneous data in WAVE files.  Thanks to Davy Durham
	for this patch.

	* test/{misc.sh,miscread.c,miscwrite.c}: Update miscellaneous
	data tests to support WAVE as well as AIFF.

2003-09-11  Michael Pruett <michael@68k.org>

	* libaudiofile/*.c: Replace use of off_t with AFfileoffset and
	AFframecount, as appropriate.
	* configure.in: Add AC_SYS_LARGEFILE in order to support large
	files.

2003-09-09  Michael Pruett <michael@68k.org>

	* libaudiofile/*.c: Include <config.h> as necessary.

2003-09-08  Michael Pruett <michael@68k.org>

	* test/*.c: Update test programs to include <config.h> as necessary.

2003-09-04  Michael Pruett <michael@68k.org>

	* configure.in, libaudiofile/{aiff.c,aiff.h,aiffwrite.c},
	libaudiofile/{ircam.c,ircamwrite.c}, libaudiofile/modules.h,
	libaudiofile/{next.c,nextwrite.c}, libaudiofile/nist.c,
	libaudiofile/{wave.c,wavewrite.c}, libaudiofile/modules/adpcm.h,
	test/{pipe.c,sixteen-to-eight.c,twentyfour.c}: Check for
	<inttypes.h> and include it if available.

	Thanks to Daniel Bergstrom for proposing this change.

2003-08-21  Michael Pruett <mpruett@sgi.com>

	* configure.in, Makefile.am, win32/Makefile.am: Include win32
	directory in distribution.

2003-07-02  Michael Pruett <mpruett@sgi.com>

	* test/testchannelmatrix.c, test/Makefile.am: Add regression
	test for channel matrix functionality.

2003-07-01  Michael Pruett <mpruett@sgi.com>

	Applying a patch from Masahiro Sakai to enable building as a
	DLL under Cygwin.

	* configure.in: Add AC_LIBTOOL_WIN32_DLL and call
	AM_PROG_LIBTOOL after AC_PROG_CC.
	* libaudiofile/Makefile.am: Add -no-undefined to
	libaudiofile_la_LDFLAGS.

2003-06-10  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/format.c: Fix error in channel matrix
	initialization.  Thanks to Jasmin Frenette for reporting this
	problem.

2002-09-11  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/raw.c: Account for data offset when calculating
	frame count on raw audio data files.

	Thanks to Davy Durham for reporting this problem.

	* test/writeraw.c, test/Makefile.am: Add a regression test for
	raw audio data files.

2002-05-17  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/wave.c: Add support for reading names of markers
	in WAVE files.  Locations of WAVE markers are now assumed to be
	in units of frames as is the case with Sound Forge.
	* libaudiofile/wavewrite.c, libaudiofile/wave.h: Add support
	for writing markers in WAVE files.

	Thanks to Davy Durham for the above patches.

	* libaudiofile/marker.[ch]: Change static function findMarkByID
	to non-static _af_mark_find_by_id for use by WAVE file marker
	code.

	* test/testmarkers.c: Add a regression test for markers.
	* test/printmarkers.c: Add a utility for printing marker
	information.
	* test/Makefile.am: Add testmarkers and printmarkers.

2002-05-16  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/wave.c: Compute the frame count of uncompressed
	WAVE files using double-precision floating-point arithmetic.

2002-05-16  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/openclose.c: Implement afOpenVirtualFile.

2002-03-24  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/marker.c: afInitMarkerComment was corrupting the
	marker's name because it would free and allocate the marker's
	name but write to its comment.  Thanks to Daniel Kobras and
	Davy Durham for noticing and fixing this problem.

2002-02-20  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/*: Eliminate unnecessary global symbols.  Thanks
	to Daniel Kobras for fixing this problem.

2002-02-04  Michael Pruett <mpruett@sgi.com>

	* audiofile.spec.in: Add /usr/lib/libaudiofile.la and
	/usr/lib/pkgconfig/audiofile.pc to the RPM spec file.

2001-10-25  Michael Pruett <mpruett@sgi.com>

	* test/irixread.c: Improve error handling.  Use proper
	conversion specifications in printf statements.

	* Makefile.am, configure.in, audiofile.pc.in: Add pkgconfig file.

	* Released version 0.2.3 of the Audio File Library.

2001-10-10  Michael Pruett <mpruett@sgi.com>

	* test/error.c: Expanded the error test to include several more
	library functions.

	* libaudiofile/format.c: Improve error checking and add comments.

2001-09-20  Michael Pruett <mpruett@sgi.com>

	* test/irixread.c, test/irixtestloop.c, test/linuxtest.c:
	Always use virtual audio format in calculations regarding audio
	data in memory.

2001-09-18  Michael Pruett <mpruett@sgi.com>

	* configure.in: Bump version to 0.2.3 in anticipation of the
	upcoming release.

2001-09-08  Michael Pruett <mpruett@sgi.com>

	* test/sgi.c: Replace fixed-point shift with a call to the more
	elegant alDoubleToFixed.

2001-08-29  Michael Pruett <mpruett@sgi.com>

	* test/pipe.{c,sh}: Added simple test of Audio File Library
	operation on non-seekable file handles.

2001-08-28  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/openclose.c: Applied Chris Wolf's patch invoking
	the macro SETBINARYMODE on all file pointers before handing
	them off to the AF VFS.  This macro does nothing on non-Windows
	systems.

2001-08-27  Michael Pruett <mpruett@sgi.com>

	* win32/*: Added Chris Wolf's Windows port of the Audio File Library.

2001-08-24  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/error.c: Include <config.h>.

	* libaudiofile/modules.c: Replacing null macro arguments with
	the token NULLMODULEPARAM so that the module macros will work
	with bad preprocessors.

2001-08-23  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/openclose.c: Include <unistd.h> only if the
	system has this header file.

	* libaudiofile/modules/rebuffer.c: Don't define min and max if
	they've been defined already.

2001-08-23  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/modules/Makefile.am, libaudiofile/units.[ch]:
	Added IMA and MS ADPCM compression modules.

	* libaudiofile/modules/msadpcm.[ch]: Checked in MS ADPCM
	compression module.

	* libaudiofile/modules/{ima,adpcm}.[ch]: Checked in IMA
	compression module and Stichting Mathematisch Centrum's IMA
	reference codec.

	* libaudiofile/afinternal.h: Declared new internal tokens for
	compression parameters in PV lists.

	* libaudiofile/audiofile.h: Declared constants for DV and MS
	ADPCM compression formats.

	* libaudiofile/wave.[ch]: Handle IMA and MS ADPCM compression
	in WAVE files.

	* libaudiofile/openclose.c: If a track has compression
	parameters, deallocate them before closing the file.

	* sfcommands/printinfo.c: Added support for compressed audio
	data to sound commands.

2001-08-07  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/query.c: Added support for
	AF_QUERYTYPE_COMPRESSION.

2001-08-04  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/util.c, libaudiofile/util.h: Add utility
	routines _af_pv_getlong, _af_pv_getdouble, and _af_pv_getptr.

2001-07-19  Michael Pruett <mpruett@sgi.com>

	* Released version 0.2.2 of the Audio File Library.

2001-07-19  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/format.c: Add afSetChannelMatrix and
	afGetVirtualChannels.

	* libaudiofile/openclose.c: Add afIdentifyFD, afIdentifyNamedFD,
	afOpenFD, and afOpenNamedFD.

2001-07-18  Michael Pruett <mpruett@sgi.com>

	* sfcommands/sfconvert.c: Use a fixed-size buffer for reading
	and writing audio data, thus reducing memory usage when
	converting large sound files.  Add float, integer, and channels
	keywords to sfconvert.

	* docs/sfconvert: Updated documentation to reflect new
	keywords.

	* libaudiofile/setup.c: Change the default file format for
	big-endian systems from AIFF to AIFF-C.

	* libaudiofile/{data.c,audiofile.h}: Change the type of the
	buffer parameter of afWriteFrames from void * to const void *.

2001-07-12  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/{aiffwrite.c,wavewrite.c}: Since
	_af_format_frame_size takes compression into account, compute
	the extent of compressed and uncompressed audio data using
	_af_format_frame_size.

	* libaudiofile/wave.c: Add support for double-precision
	floating-point WAVE files.

2001-07-10  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/util.[ch]: Make _af_format_sample_size and
	_af_format_frame_size consider compression.

2001-07-09  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/aiffwrite.c: Make AIFF code handle compressed
	data formats more cleanly.

	* libaudiofile/{wave.h,wave.c,wavewrite.c}: Make WAVE code
	handle compressed data formats more cleanly.

	* test/query2.c: Print default value of instrument parameters
	if instrument parameters are supported.

	* test/{writeulaw.c,writealaw.c}: Update writeulaw and
	writealaw to test G.711 compression in AIFF-C and WAVE files in
	addition to NeXT .snd.

2001-07-08  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/{aiff.c,aiffwrite.c}: Add support for
	floating-point AIFF-C files.

	* test/testfloat.c: Add a test for reading and writing
	floating-point audio files.

	* libaudiofile/af_vfs.[ch]: Change the virtual file read and
	write operations to use size_t and ssize_t as read(2) and
	write(2) do.

2001-07-07  Michael Pruett <mpruett@sgi.com>

	* configure.in, test/Makefile.am: Link against libaudio.so only
	for programs which use it.

2001-07-04  Michael Pruett <mpruett@sgi.com>

	* test/floatto24.c: Added program to test virtual sample format
	conversion from float to 24-bit signed integer.

2001-06-28  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/pcm.c: Added afInitPCMMapping(),
	afGetPCMMapping(), and afGetVirtualPCMMapping().

2001-06-28  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/{wave.c,wavewrite.c}: Improved support for
	floating-point WAVE files.

	* libaudiofile/wave.c: Made error messages more informative for
	currently unsupported data formats such as ADPCM and MPEG
	audio.

	* libaudiofile/wave.h: Declared additional WAVE format tag
	constants.

2001-06-28  Mark Murnane <mark.murnane@sun.com>

	* libaudiofile/{openclose.c,track.c}: Included string.h to
	ensure proper declaration of memset().

	* libaudiofile/util.c: Ditto for memset(), strlen() and strcpy().

	* libaudiofile/modules/g711.c: Ditto for strerror().

	* sfcommands/sfconvert.c: Ditto for strcmp().

2001-06-19  Michael Pruett <mpruett@sgi.com>

	* test/power.c: Adding a new example program which calculates
	the power and peak amplitudes of an audio file.  This program
	is based on Chris Vaill's normalize.

2001-06-06  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/modules.c: Fix conversion between 24-bit and
	32-bit data formats on little-endian systems.  Thanks to Axel
	Roebel for pointing out this problem.

	* libaudiofile/aiffwrite.c:  Don't write a MARK chunk unless
	markers are present.  Don't confuse the big-endian marker id
	used for writing to the file with its native-endian value used
	in calls to afGetMark*.

	* test/twentyfour.c: Add a new program to test the conversion
	between 24-bit signed integer data in a file and 32-bit signed
	integer data in memory.

2001-06-05  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/af_vfs.c: Prevent division by zero in af_fread
	and af_fwrite when size is zero.

	* libaudiofile/aiff.c: Check that the number of markers in a
	MARK chunk is positive before allocating markers.

	Thanks to Axel Roebel for pointing out both of these problems.

2001-05-19  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/nist.[ch]: Checked in support for recognizing
	NIST SPHERE files.

2001-05-16  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/query.c: Backing out last change.  The file
	format and instrument parameter selectors once again return
	arrays of type 'int' rather than arrays of type 'long'.

	Although the AUpv structure uses only long integers, the Audio
	File Library's API uses 'int' and not 'long' when describing
	file formats and instrument parameters.  Furthermore all
	existing applications expect the affected query calls to return
	arrays of int.

	* test/query2.c: Expect arrays of int rather than arrays of
	long when querying on file formats and instrument parameters.

2001-05-09  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/aiffwrite.c: Fix a memory leak in WriteMARK, and
	make WriteMARK use the afGetMark* calls rather than accessing
	track->markers directly.

	* libaudiofile/util.[ch]: Add _af_print_pvlist for debugging.

2001-05-04  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/ircam.[ch]: Make a first pass at supporting the
	IRCAM file format.

2001-04-25  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/query.c: Although the documentation states that
	certain selectors return an array of integers, the AUpv structure
	uses only long integers.  I'm resolving the ambiguity in the
	documentation by making such selectors return an array of long
	integers.

	This change has no impact on platforms where sizeof (int) ==
	sizeof (long), but it makes the query system consistent on
	platforms where the above is not the case.

2001-04-23  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/wavewrite.c: Fixed a bug seen on 64-bit systems
	in which WAVE files would be created with zero-length RIFF and
	data chunks.  (Thanks to Wayne Price for bringing this bug to
	my attention.)

2001-04-19  Michael Pruett <mpruett@sgi.com>

	* sfcommands/sfconvert.c: Make sfconvert use the sample rate of
	the input file.

2001-04-09  Michael Pruett <mpruett@sgi.com>

	* Include <string.h> in source files which use string functions.
	(Thanks to Michael Madore for pointing out this omission.)
	* Fix calculation of file position for G.711 compression.
	(Thanks to Bruce Forsberg for pointing out this bug.)
	* configure.in: Check for int{8,16,32}_t and define them
	appropriately if they are missing.

2001-02-20  Michael Pruett <mpruett@sgi.com>

	* Released version 0.2.1.
	* Removed -release flag on library build.
	* libaudiofile/*: Added some lint-style comments to clean up
	some warnings pointed out by Jean-Francois Panisset.

2000-12-15  Michael Pruett <mpruett@sgi.com>

	* Released version 0.2.

2000-11-01  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/*: Finished integrating the modules code.

2000-10-26  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/raw.[ch]: Added support for raw file reading and
	writing.

2000-10-24  Michael Pruett <mpruett@sgi.com>

	* libaudiofile/*: Cleaned up the Audio File Library and improved
	error handling.

2000-10-09  Michael Pruett <michael@68k.org>

	* libaudiofile/wave*.[ch]: WAVE format chunks can occur in any
	order.  Processing of WAVE chunks now acts accordingly.
	(Thanks to Michael Krause for pointing out shortcomings in the
	previous implementation.)
	* libaudiofile/*.[ch]: The VFS layer doesn't handle SEEK_END
	as a valid mode for fseek; we must use af_flength instead.
	* Removed query from the test suite as it did not handle
	values of AU_NULL_PVLIST returned from afQuery.  (It even
	crashes under IRIX.)

2000-10-04  Michael Pruett <michael@68k.org>

	* libaudiofile/*.c: Added better error handling.
	* libaudiofile/*.c: Added the file format unit structure,
	updated querying accordingly.  All queries except compression
	types are implemented.
	* Added query and query2 to the test suite.

2000-09-13  Michael Pruett <michael@68k.org>

	* libaudiofile/*.c: Added support for G.711 a-law, thanks to
	Bruce Forsberg.

1999-11-20  Michael Pruett <michael@68k.org>

	* libaudiofile/*.c: Cleaning up, added afOpenFD.

1999-08-21  Kjartan Maraas  <kmaraas@online.no>

	* */*c: Even more warning fixes - initialize vars, add 'int' as return
	type of a function, and include headers.
	
1999-08-20 Elliot Lee <sopwith@redhat.com>
	* */*.c: More warning fixes - remove unused variables, add 'int' as return type
	of main(), and include some more header files.

1999-08-18 Anders Carlsson  <anders.carlsson@tordata.se>

	* Fixed compiler warnings.

1999-08-16 Elliot Lee <sopwith@redhat.com>
	* libaudiofile/af_vfs.[ch]: Virtualize file access.
	* libaudiofile/*.[ch]: Use the new virtualized file access routines.

1999-05-09  Michael Pruett  <michael@68k.org>

	* bread.c, ulaw.c: If more sample frames are requested than
	remain in the file, limit the number of sample frames that can
	be returned.  This bug was brought to my attention by Scott
	Heavner.
	* test/sgi.[ch]: These files contain SGI Audio Library routines
	used in SGI-specific test programs.
	* test/irixread.c, test/irixtest.c, test/irixtestloop.c: These
	programs now use the routines contained in sgi.[ch] and are more
	robust.

1999-05-23  Raja R Harinath  <harinath@cs.umn.edu>

	* test/miscread.c: Include <config.h>.
	* test/miscwrite.c: Likewise.
	* test/writeaiff.c: Likewise.
	* test/writenext.c: Likewise.
	* test/writeulaw.c: Likewise.
	* test/writewave.c: Likewise.
 	  
1999-05-09  Michael Pruett  <michael@68k.org>

	* Merge in Audio File Library version 0.1.7.

	* aiff.c: Fixed an obscure bug in AIFF parsing in the
	instrument chunk parsing code.  Made AIFF parsing slightly
	cleaner by replacing multiple-character constant comparisons
	with memcmp and strings.

	* compression.[ch]: Added support for compressed audio.

	* au.c, auwrite.c, ulaw.c, g711.[ch]: Incorporated support for
	G.711 mu-law encoding.  Currently this encoding is only available
	for NeXT/Sun .snd/.au format files.

	* audiofile.c: Virtual byte order is now set properly.

	* aiff.c, audiofile.c, auwrite.c, bread.c, bwrite.c,
	compression.c, instrument.c, loop.c, marker.c, misc.c,
	query.c, ulaw.c: Added more error checking.

	* docs/*: Documentation has been improved.

	* test/*: Several simple test programs have been added as a
	test suite.

	* sfcommands/*: Fix hard-coded virtual byte order since it's
	now set by the library.

	* configure.in: Fixed platform-specific tests and detect byte
	order at configuration time.

1999-04-11  James Henstridge  <james@daa.com.au>

	* audiofile.spec.in: added %{prefix}/share/aclocal/* to files
	list for the devel package.

1999-02-24  Martin Baulig  <martin@home-of-linux.org>

	* configure.in (BUILD_STATIC_LIBS): New automake conditional.

	* sfcommands/Makefile.am, test/Makefile.am: Only link statically
	if we build static libraries.

1999-02-22  Raja R Harinath  <harinath@cs.umn.edu>

	* libaudiofile/audiofile.h (extern "C"): Remove duplicated
	__cplusplus guards.

1999-02-22  Michael Fulbright <drmike@redhat.com>
	* Fixed spec file to be autogenerated

1999-02-22  Michael Pruett  <michael@68k.org>
	    Elliot Lee  <sopwith@redhat.com>

	* */*: Merge in audiofile 0.1.6.
	
1999-01-20  Jeff Garzik  <jgarzik@pobox.com>

	* libaudiofile/wave.c:
	Fix newly-uncovered bug caught by Mike Bond <mike.bond@template.com>.

1999-01-17  Jeff Garzik  <jgarzik@pobox.com>

	* aiff.c, wave.c:
	Replaced some [int == '1234'] comparisons with memcmp.

	* aiff.h:
	Replaced large enum value with 'const unsigned long' instead, to
	silence ANSI C compiler warning.

	* ulaw.c:
	Converted function declarations from K&R to ANSI C, silencing a
	(big surprise) ANSI C compiler warning.

	* libaudiofile/Makefile.am:
	Remove non-existent instrument.h, loop.h, marker.h

	* sfcommands/Makefile.am:
	Add README to EXTRA_DIST.

	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
	  libaudiofile/audiofile.c, libaudiofile/auwrite.c,
	  libaudiofile/bread.c, libaudiofile/bwrite.c,
	  libaudiofile/byteorder.c, libaudiofile/byteorder.h,
	  libaudiofile/extended.c, libaudiofile/extended.h,
	  libaudiofile/instrument.c, libaudiofile/loop.c,
	  libaudiofile/marker.c, libaudiofile/misc.c,
	  libaudiofile/swapblock.c, libaudiofile/swapblock.h,
	  libaudiofile/ulaw.c, libaudiofile/ulaw.h:
	More namespace cleanups.  Made a few functions static, several
	more renamed to add "_af_" prefix.

	* libaudiofile/instrument.h, libaudiofile/loop.h,
	  libaudiofile/marker.h:
	Removed because they only contained prototypes of static funcs,
	and were included only by their implementation modules.

1999-01-16  Jeff Garzik  <jgarzik@pobox.com>

	* test/transparency.c:
	Change to unsigned short to avoid Sun CC warning.

	* libaudiofile/swapblock.c:
	Changed const long to a #define, Sun CC choked on the const.
	The definition of u_int16_t may be interfering with array
	definitions like this one, b/c u_int16_t is a macro instead of a
	typedef on Solaris platforms.

	* acconfig.h:
	Protected against multiple inclusion, using @TOP@ and @BOTTOM@.

	* libaudiofile/afinternal.h:
	Include config.h for u_int8_t and friends.

	* libaudiofile/audiofile.h, libaudiofile/aupvlist.h:
	Mark as extern 'c' if C++ compile.

	* libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
	  libaudiofile/au.c, libaudiofile/audiofile.c,
	  libaudiofile/auwrite.c, libaudiofile/bread.c,
	  libaudiofile/bwrite.c, libaudiofile/byteorder.c,
	  libaudiofile/swapblock.c, libaudiofile/util.c,
	  libaudiofile/wave.c, libaudiofile/wavewrite.c,
	  test/miscread.c, test/miscwrite.c:
	s/#if HAVE_CONFIG_H/#ifdef HAVE_CONFIG_H/

1999-01-16  Jeff Garzik  <jgarzik@pobox.com>

	* libaudiofile/afinternal.h, libaudiofile/aiff.c,
	  libaudiofile/aiffwrite.c, libaudiofile/au.c,
	  libaudiofile/audiofile.c, libaudiofile/auwrite.c,
	  libaudiofile/bread.c, libaudiofile/bwrite.c,
	  libaudiofile/error.c, libaudiofile/error.h,
	  libaudiofile/instrument.c, libaudiofile/loop.c,
	  libaudiofile/marker.c, libaudiofile/misc.c,
	  libaudiofile/util.c, libaudiofile/util.h,
	  libaudiofile/wave.c, libaudiofile/wavewrite.c:
	Major namespace cleanups:
	Made several functions static as warranted.
	Renamed a some exported private functions to _af_funcname
	to prevent collision.

1999-01-16  Jeff Garzik  <jgarzik@pobox.com>

	* autogen.sh configure.in acconfig.h:
	Added AM_CONFIG_HEADER and requisite support for it.

	* libaudiofile/aiff.c libaudiofile/aiffwrite.c libaudiofile/au.c
	  libaudiofile/audiofile.c libaudiofile/auwrite.c
	  libaudiofile/bread.c libaudiofile/bwrite.c
	  libaudiofile/byteorder.c libaudiofile/swapblock.c
	  libaudiofile/util.c libaudiofile/wave.c
	  libaudiofile/wavewrite.c test/miscread.c test/miscwrite.c:
	Conditionally include config.h.

1999-01-16  Raja R Harinath  <harinath@cs.umn.edu>

	* libaudiofile/error.c (afSetErrorHandler): Provide a better
	implementation which agrees with the semantics of the variable
	names, and usual "set_error_handler" type of functions.  (Modifies
	a "fix" in commit: "1999-01-16  Jeff Garzik  <jgarzik@pobox.com>").

1999-01-16  Jeff Garzik  <jgarzik@pobox.com>

	* libaudiofile/aes.c, libaudiofile/aiff.c, libaudiofile/aiffwrite.c,
	  libaudiofile/au.c, libaudiofile/audiofile.c, libaudiofile/aupv.c,
	  libaudiofile/auwrite.c, libaudiofile/bread.c, libaudiofile/bwrite.c,
	  libaudiofile/error.c, libaudiofile/loop.c, libaudiofile/misc.c,
	  libaudiofile/swapblock.c, libaudiofile/util.c, libaudiofile/wave.c,
	  libaudiofile/wavewrite.c, sfcommands/printinfo.c,
	  sfcommands/sfconvert.c, sfcommands/sfinfo.c:
	Corrected missing-default-case, unused-var, no-return-value,
	implicit-declaration, other gcc warnings.  Fixing those warnings
	also fixed many bugs.

	* test/adddcoffset.c, test/copy.c, test/linuxtest.c, test/miscread.c,
	  test/miscwrite.c, test/results.c, test/transparency.c:
	Changed main() declaration to standard one, fixed warnings.

1999-01-01  Jeff Garzik  <jgarzik@pobox.com>

	* libaudiofile/audiofile.h:
	Corrected comma-in-final-element warnings.

1998-12-10  Jeff Garzik  <jgarzik@pobox.com>

	* tests/miscwrite.c:
	include string.h to silence warning about strlen

Tue Dec  8 21:38:08 PST 1998 Manish Singh <yosh@gimp.org>

	* auto* fixes for make dist

1998-12-07  Jeff Garzik  <jgarzik@pobox.com>

	* LICENSE:
	Removed.  Automake automatically adds the file COPYING to the
	distribution, so this file is redundant.

1998-12-01  Yo Ric Dude  <ricdude@ix.netcom.com>

	* libaudiofile/Makefile.am, au.c, audiofile.c, audiofile.h,
	bread.c, teach libaudiofile how to handle u-law encoded .au
	files. NOTE: only added routines for reading files.

	* libaudiofile/ulaw.c, libaudiofile/ulaw.h: u-law algorithms from 
	http://www.itl.atr.co.jp/comp.speech/Section2/Q2.7.html.

1998-10-21 Bertrand Guiheneuf <Bertrand.Guiheneuf@inria.fr>
	* added an audiofile-config and an audiofile.m4
	
1998-10-17  Raja R Harinath  <harinath@cs.umn.edu>

	* configure.in (u_int_{8,16,32}_t): Define these to some "natural"
	C types if the typedefs are missing.

	* libaudiofile/Makefile.am (include_HEADERS): 
	Remove spurious empty line.

Wed Oct  7 02:13:34 PDT 1998 Manish Singh <yosh@gimp.org>

	* auto* stuff fixes

Wed Oct  7 02:08:30 CDT 1998   Frank Belew   <frb@umr.edu>
	
	* added support for automake, and libtool

1998-07-16  Michael Pruett  <michael@68k.org>

	* Changes for the Audio File Library version 0.1.4.

	AES data functions are now implemented.  They're only effective
	whenusing the AIFF/AIFF-C formats.

	Miscellaneous data functions are now implemented for the
	AIFF/AIFF-C file formats.

	The Audio File Library now uses GNU autoconf.

	The Audio File Library now builds shared libraries.

	Some rudimentary documentation is now included.

1998-06-22  Michael Pruett  <michael@68k.org>

	* Changes for the Audio File Library version 0.1.3

	The Linux-specific test programs should work on all Linux
	platforms which support audio.  (I believe this includes just
	Linux/i386, Linux/PowerPC, and Linux/Alpha.  I may be wrong.)

	The function afReadFrames now returns the proper value.

	The afGetInstParams, afSetInstParams, afGetInstParamLong, and
	afSetInstParamLong calls are now implemented to the same extent
	that SGI's versions are.

	Instrument, marker, and loop data functions are now fully
	implemented.  I'll eventually get around to the miscellaneous data
	functions.

	The AUpvlist functions have been implemented and tested.  The
	afQuery calls are on my list of things to implement.

	A few minor bugs have been fixed.
Basic Installation
==================

   These are generic installation instructions.

   The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation.  It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions.  Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').

   If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release.  If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.

   The file `configure.in' is used to create `configure' by a program
called `autoconf'.  You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.

The simplest way to compile this package is:

  1. `cd' to the directory containing the package's source code and type
     `./configure' to configure the package for your system.  If you're
     using `csh' on an old version of System V, you might need to type
     `sh ./configure' instead to prevent `csh' from trying to execute
     `configure' itself.

     Running `configure' takes awhile.  While running, it prints some
     messages telling which features it is checking for.

  2. Type `make' to compile the package.

  3. Optionally, type `make check' to run any self-tests that come with
     the package.

  4. Type `make install' to install the programs and any data files and
     documentation.

  5. You can remove the program binaries and object files from the
     source code directory by typing `make clean'.  To also remove the
     files that `configure' created (so you can compile the package for
     a different kind of computer), type `make distclean'.  There is
     also a `make maintainer-clean' target, but that is intended mainly
     for the package's developers.  If you use it, you may have to get
     all sorts of other programs in order to regenerate files that came
     with the distribution.

Compilers and Options
=====================

   Some systems require unusual options for compilation or linking that
the `configure' script does not know about.  You can give `configure'
initial values for variables by setting them in the environment.  Using
a Bourne-compatible shell, you can do that on the command line like
this:
     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure

Or on systems that have the `env' program, you can do it like this:
     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure

Compiling For Multiple Architectures
====================================

   You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory.  To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'.  `cd' to the
directory where you want the object files and executables to go and run
the `configure' script.  `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.

   If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory.  After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.

Installation Names
==================

   By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc.  You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.

   You can specify separate installation prefixes for
architecture-specific files and architecture-independent files.  If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.

   In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files.  Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.

   If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.

Optional Features
=================

   Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System).  The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.

   For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.

Specifying the System Type
==========================

   There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on.  Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option.  TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
     CPU-COMPANY-SYSTEM

See the file `config.sub' for the possible values of each field.  If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.

   If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.

Sharing Defaults
================

   If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists.  Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.

Operation Controls
==================

   `configure' recognizes the following options to control how it
operates.

`--cache-file=FILE'
     Use and save the results of the tests in FILE instead of
     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
     debugging `configure'.

`--help'
     Print a summary of the options to `configure', and exit.

`--quiet'
`--silent'
`-q'
     Do not print messages saying which checks are being made.  To
     suppress all normal output, redirect it to `/dev/null' (any error
     messages will still be shown).

`--srcdir=DIR'
     Look for the package's source code in directory DIR.  Usually
     `configure' can determine that directory automatically.

`--version'
     Print the version of Autoconf used to generate the `configure'
     script, and exit.

`configure' also accepts some other, not widely useful, options.
## Process this file with automake to produce Makefile.in

SUBDIRS = gtest libaudiofile sfcommands test examples docs

EXTRA_DIST = \
	ACKNOWLEDGEMENTS \
	NOTES \
	README \
	TODO \
	COPYING.GPL \
	configure configure.ac \
	audiofile.spec.in \
	audiofile.pc.in \
	audiofile-uninstalled.pc.in

pkgconfig_DATA = audiofile.pc

dist-hook: audiofile.spec
	cp audiofile.spec $(distdir)

if ENABLE_COVERAGE
coverage:
	$(MAKE) coverage-reset
	$(MAKE) check
	$(MAKE) coverage-report

coverage-reset:
	$(LCOV) --base-directory=@top_srcdir@ --directory @top_srcdir@/libaudiofile --zerocounters

coverage-report:
	$(LCOV) --directory @top_srcdir@/libaudiofile \
		--capture \
		--output-file @top_builddir@/lcov.info

	$(LCOV) --directory @top_srcdir@/libaudiofile \
		--output-file @top_builddir@/lcov.info \
		--remove @top_builddir@/lcov.info \
		"/usr/include/*" "gtest/*" "*/UT_*"

	$(mkdir_p) @top_builddir@/coverage
	git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`; \
	$(GENHTML) --title "@PACKAGE@ @VERSION@ $$git_commit" \
		--output-directory @top_builddir@/coverage @top_builddir@/lcov.info
	@echo
	@echo 'lcov report can be found here:'
	@echo 'file://@abs_top_builddir@/coverage/index.html'
	@echo

clean-local:
	-rm -rf coverage

.PHONY: coverage-reset coverage coverage-report
else
coverage:
	@echo "Code coverage is not enabled."
	@exit 1
endif
Changes for Audio File Library version 0.3.6:

* Implement FLAC and ALAC encoding and decoding.
* Update license to LGPL 2.1.

Changes for Audio File Library version 0.3.5:

* Implement IMA ADPCM encoding and decoding for AIFF-C, CAF, and WAVE files.
* Implement Microsoft ADPCM encoding for WAVE files.
* Fix calculation of IRCAM frame size.
* Record marker comments in WAVE files.
* Improve validation of compressed audio formats.
* Add support for building without documentation.

Changes for Audio File Library version 0.3.4:

* Use hidden visibility for internal symbols.
* Add support for Sample Vision format.
* Update license for extended-precision floating-point conversion routines.

Changes for Audio File Library version 0.3.3:

* Update library's soname version.
* Link against libm.

Changes for Audio File Library version 0.3.2:

* Fix initialization of byte order in Creative Voice File format.
* Fix calculation of frame count in NIST SPHERE sound files.
* Remove duplicate definition of AFvirtualfile.
* Don't treat compiler warnings as errors by default.

Changes for Audio File Library version 0.3.1:

* Fix installation of man pages.
* Add support for Creative Voice File format.
* Support u-law and A-law compression in Core Audio Format files.

Changes for Audio File Library version 0.3.0:

* Define AFframecount and AFfileoffset as 64-bit integers regardless of
  whether system specifies off_t as 64 bits.
* Added support for Core Audio Format.
* Added support for extensible WAVE format files.
* Fixed leak of miscellaneous data buffers. (Thanks to Stefano Magni
  for finding and fixing this problem.)
* Fixed default mapping between integer and floating-point audio data.
* Fix handling of NeXT sound files with unspecified or inconsistent length.
* Added support for miscellaneous data in IFF/8SVX files.
* Added support for byte-swapped IRCAM sound files.
* Refactored file parsing and writing.
* Refactored audio conversion.
* Updated and expanded documentation.
Audio File Library 0.3.6
Development Notes
Michael Pruett <michael@68k.org>

----

Large file support is now enabled by default on all systems.  This change
has no effect on systems where off_t is always 64 bits (e.g. IRIX,
FreeBSD, NetBSD, OpenBSD, Mac OS X).

Many compressed data formats are not supported.  This is currently the
most important issue to address.

Error handling is at the present quite robust, but more work can always
be done in this area.

SGI's Audio File Library on IRIX implements the following formats which
this version of the library does not:

	MPEG1 audio bitstream
	Sound Designer II
	SoundFont2

I plan to implement some of these as time permits.  Sound Designer
II is out of the question because of its dependency upon Macintosh
resource forks.  Handling these files on Unix systems is simply not
worth the effort.

----

This version of the Audio File Library has been tested under the following
operating environments:

	i686-pc-linux-gnu / Ubuntu 12.10 (gcc 4.7.2)
	x86_64-pc-linux-gnu / Ubuntu 12.10 (gcc 4.7.2)
	x86_64-pc-linux-gnu / Ubuntu 12.10 (clang 3.0)
	armv6l-raspberrypi-linux-gnueabihf / Raspbian Wheezy (gcc 4.6.3)
	i386-apple-darwin10.8.0 / Mac OS X 10.6.8 (gcc 4.2.1)
	x86_64-apple-darwin10.8.0 / Mac OS X 10.6.8 (gcc 4.2.1)
	i386-pc-freebsd9.1 / FreeBSD 9.1 (gcc 4.2.1)
	sparc64-sun-freebsd9.1 / FreeBSD 9.1 (gcc 4.2.1)
Audio File Library
Version 0.3.6
Wednesday, 6 March 2013

Copyright (C) 1998-2000, 2003-2004, 2010-2013 Michael Pruett
Copyright (C) 2000-2001 Silicon Graphics, Inc.

michael@68k.org
http://audiofile.68k.org/

----

The Audio File Library handles reading and writing audio files in many
common formats.

Key goals of the Audio File Library are file format transparency and data
format transparency. The same calls for opening a file, accessing and
manipulating audio metadata (e.g. sample rate, sample format, textual
information, MIDI parameters), and reading and writing sample data will
work with any supported audio file format. Likewise, the format of the
audio data presented to the application need not be tied to the format
of the data contained in the file.

The following file formats are currently supported:
* AIFF/AIFF-C
* WAVE
* NeXT .snd/Sun .au
* Berkeley/IRCAM/CARL Sound File
* Audio Visual Research
* Amiga IFF/8SVX
* Sample Vision
* Creative Voice File
* NIST SPHERE
* Core Audio Format
* FLAC

The following compression formats are currently supported:
* G.711 mu-law and A-law
* IMA ADPCM
* Microsoft ADPCM
* FLAC
* Apple Lossless Audio Codec

The Audio File Library itself is available under the GNU Lesser General
Public License, and the programs in this package are available under the
GNU General Public License. The two licenses are included in the files
COPYING and COPYING.GPL, respectively.

----

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA  02110-1301  USA
Audio File Library
To Do List

Michael Pruett <michael@68k.org>

Short-term
----------

Handle more compressed data formats, most importantly Ogg Vorbis.
GSM 06.10 would also be nice.

Handle sample rate conversion.

More comprehensive tests should be developed to stress-test the
library.  Tests are needed most for the following sets of functions:
	* af{Get,Set}VirtualChannels/afSetChannelMatrix
	* afGetSampleFormat/af{Get,Set}VirtualSampleFormat
	* af{Get,Set}Loop{IDs,Mode,Count,Start,End,StartFrame,EndFrame,Track}

Support for auxiliary data in IRCAM files (maximum amplitude, comments,
etc.) should be added.

Long-term
---------

It would be nice to support some more file formats.

Add locale support for error messages.

Whenever a compression format is requested, the library should scan
through /usr/lib/audiofile/*.so to see if any DSOs support the requested
format.
Name: audiofile
Description: audiofile
Requires:
Version: @VERSION@
Libs: ${pc_top_builddir}/${pcfiledir}/libaudiofile/libaudiofile.la -lm
Cflags: -I${pc_top_builddir}/${pcfiledir}/libaudiofile
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: audiofile
Description: audiofile
Requires:
Version: @VERSION@
Libs: -L${libdir} -laudiofile
Libs.private: @FLAC_LIBS@ -lm
Cflags: -I${includedir}
%define  ver     @VERSION@
%define  RELEASE 1
%define  rel     %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE}
%define  prefix  /usr

Summary: A library to handle various audio file formats.
Name: audiofile
Version: %ver
Release: %rel
Copyright: LGPL
Group: Libraries/Sound
Source: ftp://ftp.gnome.org/pub/GNOME/sources/audiofile/audiofile-%{PACKAGE_VERSION}.tar.gz
URL: http://www.68k.org/~michael/audiofile/
BuildRoot:/var/tmp/audiofile-%{PACKAGE_VERSION}-root
Docdir: %{prefix}/doc
Obsoletes: libaudiofile

%description
The Audio File Library provides an elegant API for accessing a variety
of audio file formats, such as AIFF/AIFF-C, WAVE, and NeXT/Sun
.snd/.au, in a manner independent of file and data formats.

%package devel
Summary: Library, headers, etc. to develop with the Audio File Library.
Group: Libraries

%description devel
Library, header files, etc. for developing applications with the Audio
File Library.

%prep
%setup

%build
CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%prefix
make $MAKE_FLAGS

%install

rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT

#
# makefile is broken, sets exec_prefix explicitely.
#
make exec_prefix=$RPM_BUILD_ROOT/%{prefix} prefix=$RPM_BUILD_ROOT/%{prefix} install 

%clean
rm -rf $RPM_BUILD_ROOT

%changelog

* Fri Nov 20 1998 Michael Fulbright <drmike@redhat.com>
- First try at a spec file

%files
%defattr(-, root, root)
%doc COPYING TODO README ChangeLog docs
%{prefix}/bin/*
%{prefix}/lib/lib*.so.*

%files devel
%defattr(-, root, root)
%{prefix}/lib/lib*.so
%{prefix}/lib/*.a
%{prefix}/lib/*.la
%{prefix}/lib/pkgconfig/*.pc
%{prefix}/include/*
%{prefix}/share/aclocal/*
#!/bin/sh
# Run this to generate all the initial makefiles, etc.

test -n "$srcdir" || srcdir=`dirname $0`
test -n "$srcdir" || srcdir=.

AUTORECONF=`which autoreconf`
if test -z $AUTORECONF; then
	echo "autoreconf was not found; you must install automake, autoconf,"
	echo "and libtool to build libaudiofile."
	exit 1
fi

rootme=`pwd`
cd $srcdir
autoreconf --install --verbose || exit $?
cd $rootme

$srcdir/configure "$@"

echo 
echo "Now type 'make' to compile libaudiofile."
dnl Process this file with autoconf to produce a configure script.
AC_INIT([audiofile], [0.3.6])
AC_CONFIG_SRCDIR([libaudiofile/AIFF.cpp])

dnl Set libtool version information.
AUDIOFILE_VERSION_INFO=1:0:0
AUDIOFILE_VERSION=$PACKAGE_VERSION

AC_SUBST(AUDIOFILE_VERSION)
AC_SUBST(AUDIOFILE_VERSION_INFO)

AM_INIT_AUTOMAKE
AC_CONFIG_HEADER([config.h])

dnl Checks for programs.
AC_PROG_CC_C99
AC_PROG_CXX
AC_PROG_INSTALL
AM_PROG_LIBTOOL

dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h unistd.h)

dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_BIGENDIAN

dnl Enable large file support by default.
AC_SYS_LARGEFILE
AC_TYPE_OFF_T
AC_TYPE_SIZE_T

dnl Set up platform specific stuff
platform=none
AC_MSG_CHECKING([for platform specific tests to compile])
case "$host_os" in
  linux*)
    TEST_BIN="linuxtest alsaplay"
    platform=linux
    ;;
  irix5* | irix6*)
    TEST_BIN="irixread irixtestloop"
    platform=irix
    ;;
  darwin*)
    if test -e /System/Library/Frameworks/CoreAudio.framework; then
      TEST_BIN="osxplay"
      platform="Mac OS X"
    fi
    ;;
esac
AC_MSG_RESULT($platform)
AC_SUBST(TEST_BIN)

AC_ARG_ENABLE(werror,
	AS_HELP_STRING([--enable-werror], [treat compiler warnings as errors]),
	[enable_werror=$enableval],
	[enable_werror=no])
AM_CONDITIONAL(ENABLE_WERROR, [test "$enable_werror" = "yes"])

AS_IF([test "$enable_werror" = "yes"],
	[WERROR_CFLAGS="-Werror"
	AC_SUBST(WERROR_CFLAGS)])

AC_ARG_ENABLE(coverage,
	AS_HELP_STRING([--enable-coverage], [enable code coverage]),
	[enable_coverage=$enableval],
	[enable_coverage=no])
AM_CONDITIONAL(ENABLE_COVERAGE, [test "$enable_coverage" = "yes"])

AS_IF([test "$enable_coverage" = "yes"],
	[COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage"
	COVERAGE_LIBS="-lgcov"
	AC_SUBST(COVERAGE_CFLAGS)
	AC_SUBST(COVERAGE_LIBS)

	AC_PATH_PROG(LCOV, lcov, :)
	AC_PATH_PROG(GENHTML, genhtml, :)
	AC_SUBST(LCOV)
	AC_SUBST(GENHTML)
	AS_IF([test "$LCOV" = :],
		[AC_MSG_ERROR([lcov must be installed for code coverage: http://ltp.sourceforge.net/coverage/lcov.php])]
	)]
)

AC_ARG_ENABLE(valgrind,
	AS_HELP_STRING([--enable-valgrind], [enable testing with Valgrind]),
	[enable_valgrind=$enableval],
	[enable_valgrind=no])
AM_CONDITIONAL(ENABLE_VALGRIND, [test "$enable_valgrind" = "yes"])

AS_IF([test "$enable_valgrind" = "yes"],
	[AC_PATH_PROG(VALGRIND, valgrind, :)
	AC_SUBST(VALGRIND)
	AS_IF([test "$VALGRIND" = :],
		[AC_MSG_ERROR([Could not find Valgrind.])]
	)]
)

AC_ARG_ENABLE(docs,
	AS_HELP_STRING([--disable-docs], [disable documentation]),
	[enable_documentation=$enableval],
	[enable_documentation=yes])

AM_CONDITIONAL(ENABLE_DOCUMENTATION, [test "$enable_documentation" = "yes"])

AS_IF([test "$enable_documentation" = "yes"],
	[AC_PATH_PROG(A2X, a2x, :)
	AC_PATH_PROG(ASCIIDOC, asciidoc, :)
	AS_IF([test "$A2X" = :],
		[AC_MSG_WARN([Could not find a2x.])]
	)
	AS_IF([test "$ASCIIDOC" = :],
		[AC_MSG_WARN([Could not find asciidoc.])]
	)]
)

AC_ARG_ENABLE(examples,
	AS_HELP_STRING([--disable-examples], [disable examples]),
		[enable_examples=$enableval],
		[enable_examples=yes])
AS_IF([test "$enable_examples" != "yes"], [TEST_BIN=""])

AC_ARG_ENABLE(flac,
	AS_HELP_STRING([--disable-flac], [disable FLAC]),
	[enable_flac=$enableval],
	[enable_flac=yes])

PKG_PROG_PKG_CONFIG
PKG_INSTALLDIR

FLAC_CFLAGS=""
FLAC_LIBS=""

if test -n "$PKG_CONFIG" ; then
	if test "$enable_flac" = "yes" ; then
		PKG_CHECK_MODULES([FLAC], [flac >= 1.2.1], [ac_cv_flac=yes], [ac_cv_flac=no])
		FLAC_CFLAGS=`echo $FLAC_CFLAGS | $SED "s:include/FLAC:include:"`
		if test "$ac_cv_flac" = "no" ; then
			enable_flac=no
		fi
	fi
else
	enable_flac=no
fi

AC_SUBST(FLAC_CFLAGS)
AC_SUBST(FLAC_LIBS)

AM_CONDITIONAL(ENABLE_FLAC, [test "$enable_flac" = "yes"])
if test "$enable_flac" = "yes" ; then
	AC_DEFINE_UNQUOTED([ENABLE_FLAC], [1], [Whether FLAC is enabled.])
else
	AC_DEFINE_UNQUOTED([ENABLE_FLAC], [0], [Whether FLAC is enabled.])
fi

AC_CONFIG_FILES([
	audiofile.spec
	audiofile.pc
	audiofile-uninstalled.pc
	sfcommands/Makefile
	test/Makefile
	gtest/Makefile
	examples/Makefile
	libaudiofile/Makefile
	libaudiofile/alac/Makefile
	libaudiofile/modules/Makefile
	docs/Makefile
	Makefile])
AC_OUTPUT
*.[1-8]
*.html
*.xml
if ENABLE_DOCUMENTATION

DOCS_TXT_MAN1 = \
	sfconvert.1.txt \
	sfinfo.1.txt

DOCS_TXT_MAN3 = \
	afCloseFile.3.txt \
	afGetFrameCount.3.txt \
	afGetFrameSize.3.txt \
	afIdentifyFD.3.txt \
	afInitAESChannelDataTo.3.txt \
	afInitCompression.3.txt \
	afInitFileFormat.3.txt \
	afInitSampleFormat.3.txt \
	afNewFileSetup.3.txt \
	afOpenFile.3.txt \
	afQuery.3.txt \
	afReadFrames.3.txt \
	afReadMisc.3.txt \
	afSeekFrame.3.txt \
	afSetErrorHandler.3.txt \
	afSetVirtualSampleFormat.3.txt \
	afWriteFrames.3.txt

DOCS_TXT = $(DOCS_TXT_MAN1) $(DOCS_TXT_MAN3)

EXTRA_DIST = \
	$(DOCS_TXT) \
	asciidoc.conf

DOCS_MAN1 = $(DOCS_TXT_MAN1:.txt=)
DOCS_MAN3 = $(DOCS_TXT_MAN3:.txt=)
DOCS_MAN3_EXTRA = \
	afIdentifyNamedFD.3 \
	afInitAESChannelData.3 \
	afInitByteOrder.3 \
	afInitChannels.3 \
	afInitRate.3 \
	afGetDataOffset.3 \
	afGetTrackBytes.3 \
	afQueryLong.3 \
	afQueryDouble.3 \
	afQueryPointer.3 \
	afSeekMisc.3 \
	afSetVirtualByteOrder.3 \
	afSetVirtualChannels.3 \
	afSetVirtualPCMMapping.3 \
	afTellFrame.3 \
	afWriteMisc.3

DOCS_HTML = $(DOCS_TXT:.txt=.html)

dist_man1_MANS = $(DOCS_MAN1)
dist_man3_MANS = $(DOCS_MAN3) $(DOCS_MAN3_EXTRA)

ASCIIDOCFLAGS = -arevnumber=$(VERSION) -amansource="Audio File Library"
A2XFLAGS = $(ASCIIDOCFLAGS) -d manpage -f manpage

%.html: %.txt
	$(ASCIIDOC) $(ASCIIDOCFLAGS) -b html4 -d manpage -f asciidoc.conf $<

%.1: %.1.txt
	$(A2X) $(A2XFLAGS) --asciidoc-opts="-f asciidoc.conf" $<

%.3: %.3.txt
	$(A2X) $(A2XFLAGS) --asciidoc-opts="-f asciidoc.conf" $<

html: $(DOCS_HTML)

CLEANFILES = *.1 *.3 *.html

endif
afCloseFile(3)
==============

NAME
----
afCloseFile - close an open audio file

SYNOPSIS
--------
  #include <audiofile.h>

  int afCloseFile(AFfilehandle file);

PARAMETERS
----------
`file` is a valid file handle created by linkaf:afOpenFile[3].

DESCRIPTION
-----------
`afCloseFile` closes the audio file 'file', updating the file if it was
opened for writing.

RETURN VALUE
------------
`afCloseFile` returns 0 if the file was closed properly and -1 if an
error occurred while closing the file.

ERRORS
------
`afCloseFile` can generate these possible errors:

* `AF_BAD_FILEHANDLE`
* `AF_BAD_LSEEK`
* `AF_BAD_WRITE`

SEE ALSO
--------
linkaf:afOpenFile[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afGetFrameCount(3)
==================

NAME
----
afGetFrameCount, afGetTrackBytes, afGetDataOffset - get the total sample
frame count, length of audio track in bytes, offset of the audio track for a
track in an audio file


SYNOPSIS
--------
  #include <audiofile.h>

  AFframecount afGetFrameCount (AFfilehandle file, int track);

  AFfileoffset afGetTrackBytes (AFfilehandle file, int track);

  AFfileoffset afGetDataOffset (AFfilehandle file, int track);


PARAMETERS
----------
'file' is an audio file handle created by a previous call to
linkaf:afOpenFile[3].

'track' is an integer which specifies an audio track within 'file'.
All supported file formats contain exactly one audio track per file,
so the constant `AF_DEFAULT_TRACK` should always be used.


DESCRIPTION
-----------
`afGetFrameCount` returns the total number of sample frames contained
within the specified track of the specified file.

Each sample frame of audio consists of a fixed number of samples
(equal to the number of audio channels in the track. For monaural data,
a sample frame consists of one audio sample. For stereophonic data,
a sample frame consists of a stereo pair.

`afGetTrackBytes` returns the total number of bytes of raw audio data
(i.e., prior to decompression or conversion) in the track.

`afGetDataOffset` returns the offset in bytes of the start of the audio
data contained within the specified track of the specified file.


RETURN VALUE
------------
`afGetFrameCount` returns the total number of sample frames in 'track'.

`afGetTrackBytes` returns the total number of bytes of audio data
in 'track'.

`afGetDataOffset` returns the offset in bytes to the beginning of the
audio data in 'track'.

Each of these routines returns -1 in case of error.

AUTHOR
------
Michael Pruett <michael@68k.org>
afGetFrameSize(3)
=================

NAME
----
afGetFrameSize - calculate the frame size in bytes for an audio track

SYNOPSIS
--------
  #include <audiofile.h>

  float afGetFrameSize (AFfilehandle file, int track, int expand3to4);

PARAMETERS
----------
'file' is a valid AFfilehandle.

'track' is an integer which refers to a specific audio track in the
file.  At present no supported audio file format allows for more than
one audio track within a file, so track should always be
`AF_DEFAULT_TRACK`.

'expand3to4' is a boolean-valued integer indicating whether frame size
calculation will treat 24-bit data as having a size of 3 bytes or 4
bytes.

DESCRIPTION
-----------
`afGetFrameSize` returns the number of bytes in a frame in a given
audio track.

A sample frame consists of one or more samples.  For a monaural track,
a sample frame will always contain one sample.  For a stereophonic
track, a sample frame will always contain two samples, one for the left
channel and one for the right channel.

A non-zero value of 'expand3to4' should be used when calculating the
frame size for storage in memory (since 24-bit audio data is presented
in memory as a 4-byte sign-extended integer), while a value of zero
should be used for calculating storage on disk where no padding is added.
The parameter 'expand3to4' is ignored unless the specified audio track
contains 24-bit audio data.

AUTHOR
------
Michael Pruett <michael@68k.org>
afIdentifyFD(3)
===============

NAME
----
afIdentifyFD, afIdentifyNamedFD - identify the format of a file descriptor

SYNOPSIS
--------
  #include <audiofile.h>

  int afIdenfityFD(int fd);
  int afIdentifyNamedFD(int fd, const char *path, int *implemented);

PARAMETERS
----------
'fd' is a file descriptor to be examined.

'path' is the path to the file to be examined.

'implemented' is a pointer to an integer whose value will be set to 0 or 1
by `afIdentifyNamedFD`.

RETURN VALUE
------------
`afIdentifyFD` and `afIdentifyNamedFD` return an integer value indicating
the format of the specified file. If the format could not be identified
or if the file is not a valid audio file, the value `AF_FILE_UNKNOWN`
is returned.

DESCRIPTION
-----------
`afIdentifyFD` and `afIdentifyNamedFD` examine the given file descriptor
to determine the file's format.

ERRORS
------
`afIdentifyFD` and `afIdentifyNamedFD` can produce the following errors:

`AF_BAD_READ`:: A call to `read` failed
`AF_BAD_WRITE`:: A call to `write` failed.
`AF_BAD_LSEEK`:: A call to `lseek` failed.

SEE ALSO
--------
linkaf:afOpenFile[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afInitAESChannelDataTo(3)
=========================

NAME
----
afInitAESChannelDataTo, afInitAESChannelData - initialize AES non-audio
data in an audio file setup

SYNOPSIS
--------
  #include <audiofile.h>

  void afInitAESChannelDataTo(AFfilesetup setup, int track, int willHaveData);
  void afInitAESChannelData(AFfilesetup setup, int track);

PARAMETERS
----------
`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].

`track` specifies a track within the audio file setup. `track` is always
`AF_DEFAULT_TRACK` for all currently supported file formats.

`willHaveData` is a boolean-valued integer indicating whether AES
non-audio data will be present.

DESCRIPTION
-----------
Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3]
and a track identified by `track` (`AF_DEFAULT_TRACK` for all currently
supported file formats), `afInitAESChannelDataTo` initializes the track to
contain or not contain AES non-audio data. `afInitAESChannelData` behaves
similarly but always initializes the track to contain AES non-audio data.

Currently only AIFF and AIFF-C file formats can store AES non-audio data;
this data is ignored in all other file formats.

ERRORS
------
`afInitAESChannelDataTo` and `afInitAESChannelData` can produce the
following errors:

`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
`AF_BAD_TRACKID`:: `track` represents an invalid track identifier.

SEE ALSO
--------
linkaf:afNewFileSetup[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afInitByteOrder(3)
==================

NAME
----
afInitCompression - initialize compression for a track in an audio
file setup

SYNOPSIS
--------
  #include <audiofile.h>

  void afInitCompression(AFfilesetup setup, int track, int compression);

PARAMETERS
----------
`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].

`track` specifies a track within the audio file setup. `track` is always
`AF_DEFAULT_TRACK` for all currently supported file formats.

`compression` is an identifier specifying the compression type (such as
`AF_COMPRESSION_G711_ULAW`) to be used for audio data in the track.

DESCRIPTION
-----------
Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3]
and a track identified by `track` (`AF_DEFAULT_TRACK` for all currently
supported file formats), `afInitCompression` initializes the track to
the specified compression.

The following compression types are currently supported:

`AF_COMPRESSION_NONE`:: no compression
`AF_COMPRESSION_G711_ULAW`:: CCITT G.711 mu-law encoding
`AF_COMPRESSION_G711_ALAW`:: CCITT G.711 A-law encoding
`AF_COMPRESSION_IMA`:: IMA ADPCM encoding
`AF_COMPRESSION_MS_ADPCM`:: MS ADPCM encoding
`AF_COMPRESSION_FLAC`:: FLAC
`AF_COMPRESSION_ALAC`:: Apple Lossless Audio Codec

ERRORS
------
`afInitCompression` can produce the following errors:

`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
`AF_BAD_TRACKID`:: `track` represents an invalid track identifier.
`AF_BAD_COMPTYPE`:: `compression` represents an invalid compression type.

SEE ALSO
--------
linkaf:afNewFileSetup[3],
linkaf:afInitSampleFormat[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afInitFileFormat(3)
===================

NAME
----
afInitFileFormat - initialize file format of an audio file setup

SYNOPSIS
--------
  #include <audiofile.h>

  void afInitFileFormat(AFfilesetup setup, int fileFormat);

PARAMETERS
----------
`setup` is a valid file setup created by linkaf:afNewFileSetup[3].

`fileFormat` is an integer constant specifying a file format.

DESCRIPTION
-----------
Given an `AFfilesetup` structure created with linkaf:afNewFileSetup[3],
`afInitFileFormat` initializes the file format to that specified by
`fileFormat`.

The following file formats are currently supported:

`AF_FILE_RAWDATA`:: raw audio data
`AF_FILE_AIFF`:: Audio Interchange File Format
`AF_FILE_AIFFC`:: Audio Interchange File Format AIFF-C
`AF_FILE_NEXTSND`:: NeXT .snd/Sun .au
`AF_FILE_WAVE`:: Microsoft RIFF WAVE
`AF_FILE_BICSF`:: Berkeley/IRCAM/CARL Sound File
`AF_FILE_AVR`:: Audio Visual Research
`AF_FILE_IFF_8SVX`:: Amiga IFF/8SVX
`AF_FILE_SAMPLEVISION`:: Sample Vision
`AF_FILE_VOC`:: Creative Voice File
`AF_FILE_NIST_SPHERE`:: NIST SPHERE
`AF_FILE_CAF`:: Core Audio Format

ERRORS
------
`afInitFileFormat` can produce the following errors:

`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
`AF_BAD_FILEFMT`:: `fileFormat` represents an unknown file format.
`AF_BAD_NOT_IMPLEMENTED`:: `fileFormat` represents a file format which
is not currently implemented.

SEE ALSO
--------
linkaf:afNewFileSetup[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afInitSampleFormat(3)
=====================

NAME
----
afInitSampleFormat, afInitByteOrder, afInitChannels, afInitRate -
initialize audio data format for a track in an audio file setup

SYNOPSIS
--------
  #include <audiofile.h>

  void afInitSampleFormat(AFfilesetup setup, int track, int sampleFormat,
      int sampleWidth);
  void afInitByteOrder(AFfilesetup setup, int track, int byteOrder);
  void afInitChannels(AFfilesetup setup, int track, int channels);
  void afInitRate(AFfilesetup setup, int track, double rate);

PARAMETERS
----------
`setup` is a valid file setup returned by linkaf:afNewFileSetup[3].

`track` specifies a track within the audio file setup. `track` is always
`AF_DEFAULT_TRACK` for all currently supported file formats.

`sampleFormat` is a symbolic constant specifying the sample format
for the audio data in the track. `sampleFormat` must be one of
`AF_SAMPFMT_TWOSCOMP`, `AF_SAMPFMT_UNSIGNED`, `AF_SAMPFMT_FLOAT`, or
`AF_SAMPFMT_DOUBLE`.

`sampleWidth` is a positive integer specifying the number of bits for
each sample in the track.

`byteOrder` is a symbolic constant specifying the byte order of
the track. `byteOrder` must be one of `AF_BYTEORDER_BIGENDIAN` or
`AF_BYTEORDER_LITTLEENDIAN`.

`channels` is a positive integer specifying the number of channels in
the track.

`rate` is a positive double-precision floating-point number specifying
the sample rate of the track.

DESCRIPTION
-----------
`afInitSampleFormat` initializes the track to the specified sample format
and sample width.

`afInitByteOrder` initializes the track to the specified byte order.

`afInitChannels` initializes the track to the specified number of channels.

`afInitRate` initializes the track to the specified sample rate.

ERRORS
------
`afInitSampleFormat`, `afInitByteOrder`, `afInitChannels`, and
`afInitRate` can produce the following errors:

[horizontal]
`AF_BAD_FILESETUP`:: `setup` represents an invalid file setup.
`AF_BAD_TRACK`:: `track` represents an invalid track identifier.

`afInitSampleFormat` can also produce the following errors:

[horizontal]
`AF_BAD_SAMPFMT`:: `sampleFormat` does not represent a valid sample format.
`AF_BAD_WIDTH`:: `sampleWidth` is not a valid sample width.

`afInitByteOrder` can also produce the following error:

[horizontal]
`AF_BAD_BYTEORDER`:: `byteOrder` does not represent a valid byte order. 

`afInitChannels` can also produce the following error:

[horizontal]
`AF_BAD_CHANNELS`:: `channels` specifies an invalid number of channels.

`afInitRate` can also produce the following error:

[horizontal]
`AF_BAD_RATE`:: `rate` specifies an invalid sample rate.

SEE ALSO
--------
linkaf:afNewFileSetup[3],
linkaf:afInitFileFormat[3],
linkaf:afInitCompression[3],
linkaf:afOpenFile[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afNewFileSetup(3)
=================

NAME
----
afNewFileSetup - create and initialize a new AFfilesetup structure

SYNOPSIS
--------
  #include <audiofile.h>

  AFfilesetup afNewFileSetup(void);

RETURN VALUE
------------
`afNewFileSetup` returns, upon success, a valid AFfilesetup structure.

Upon failure, `afNewFileSetup` returns a null `AFfilesetup`. This case
should only occur when no memory is available.

DESCRIPTION
-----------
The opaque `AFfilesetup` structure returned by `afNewFileSetup` can
be used to specify parameters for a file to be opened for writing by
linkaf:afOpenFile[3].

SEE ALSO
--------
linkaf:afOpenFile[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afOpenFile(3)
=============

NAME
----
afOpenFile - open an audio file and create a file handle structure used
for subsequent calls to the Audio File Library

SYNOPSIS
--------
  #include <audiofile.h>

  AFfilehandle afOpenFile(const char *path, const char *mode,
      AFfilesetup setup);

PARAMETERS
----------
'path' is the path to the file to be opened.

'mode' specifies a mode for opening the file: `"r"` for reading or
`"w"` for writing.

'setup' is an AFfilesetup created by linkaf:afNewFileSetup[3]. This value
is ignored for files opened for reading except when the file format is
`AF_FILE_RAWDATA`.

RETURN VALUE
------------
Upon success, `afOpenFile` returns a valid `AFfilehandle` which can
be used in subsequent calls to the Audio File Library. Upon failure,
`afOpenFile` returns NULL and generates an error.

linkaf:afCloseFile[3] is used to close the file when it is no longer
needed.

ERRORS
------
`afOpenFile` can produce the following errors:

`AF_BAD_OPEN`:: A call to `open` failed.
`AF_BAD_READ`:: A call to `read` failed
`AF_BAD_WRITE`:: A call to `write` failed.
`AF_BAD_LSEEK`:: A call to `lseek` failed.
`AF_BAD_MALLOC`:: Memory allocation failed.
`AF_BAD_FILEFMT`:: `setup` specifies a file format which is unsupported for `mode`.
`AF_BAD_SAMPFMT`:: The file's sample format is not supported.
`AF_BAD_WIDTH`:: The file's sample width is not supported.
`AF_BAD_RATE`:: The file's sample rate is not supported.
`AF_BAD_CHANNELS`:: The number of channels in the file is not supported.
`AF_BAD_FILESETUP`:: `setup` specifies an invalid or unsupported configuration.

SEE ALSO
--------
linkaf:afCloseFile[3],
linkaf:afNewFileSetup[3],
linkaf:afInitFileFormat[3],
linkaf:afInitSampleFormat[3],
linkaf:afReadFrames[3],
linkaf:afWriteFrames[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afQuery(3)
==========

NAME
----
afQuery, afQueryLong, afQueryDouble, afQueryPointer - query the
capabilities of the Audio File Library

SYNOPSIS
--------
  #include <audiofile.h>

  AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);

  long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);

  double afQueryDouble (int querytype, int arg1, int arg2, int arg3,
      int arg4);

  void *afQueryPointer (int querytype, int arg1, int arg2, int arg3,
      int arg4);

PARAMETERS
----------
'querytype' can be one of the following:

* `AF_QUERYTYPE_FILEFMT`
* `AF_QUERYTYPE_INST`
* `AF_QUERYTYPE_INSTPARAM`
* `AF_QUERYTYPE_COMPRESSION`
* `AF_QUERYTYPE_COMPRESSIONPARAM`
* `AF_QUERYTYPE_MISC`
* `AF_QUERYTYPE_MARK`
* `AF_QUERYTYPE_LOOP`

'arg1', 'arg2', 'arg3', and 'arg4' are integer selectors whose
meaning depends upon 'querytype'.


RETURN VALUE
------------
Upon success, `afQuery` will return a non-null `AUpvlist` value.
Upon failure, `afQuery` will return null while `afQueryLong` and
`afQueryDouble` will return -1 and `afQueryPointer` will return
null.

Pointers representing character strings are owned by the Audio File
Library and must not be freed; all other pointer values must be
freed by the caller.

DESCRIPTION
-----------
For `AF_QUERYTYPE_FILEFMT`, the following selectors are valid values for 'arg1':

`AF_QUERY_LABEL`:: Request a short label string for the format (e.g., "aiff").

`AF_QUERY_NAME`:: Request a short name for the format (e.g., "MS RIFF WAVE").

`AF_QUERY_DESC`:: Request a descriptive name for the format (e.g., "Audio
Interchange File Format").

`AF_QUERY_IMPLEMENTED`:: Request a boolean value indicating whether the
format is implemented for reading and writing in the Audio File Library.

`AF_QUERY_ID_COUNT`:: Request the total number of formats implemented.

`AF_QUERY_IDS`:: Request an integer array of the id token values of all
implemented file formats.

`AF_QUERY_COMPRESSION_TYPES`:: Used with the selector AF_QUERY_VALUE_COUNT
in 'arg2', this will return a long integer containing the number of
compression schemes available for use within the format specified in 'arg3'.
Used with selector `AF_QUERY_VALUES`, it returns a pointer to an integer
array containing the compression id values of the compression schemes
supported by the format specified in 'arg3'.

`AF_QUERY_SAMPLE_FORMATS`:: Used with the selector AF_QUERY_DEFAULT in 'arg2',
this will return the default sample format for the file format specified in
'arg3'.

`AF_QUERY_SAMPLE_SIZES`:: Used with selector AF_QUERY_DEFAULT in 'arg2', this
will return the default sample width for the file format specified in 'arg3'.


For `AF_QUERYTYPE_INST`, the following selectors are valid for 'arg1':

`AF_QUERY_SUPPORTED`:: Request a boolean value indicating whether
the file format in 'arg2' supports instruments.

`AF_QUERY_MAX_NUMBER`:: Request an integer value indicating the
maximum number of instruments supported by the file format in 'arg2'.


For `AF_QUERYTYPE_INSTPARAM`, the following selectors are valid for 'arg1':

`AF_QUERY_SUPPORTED`:: Request a boolean value indicating whether
the file format in 'arg2' supports instrument parameters.

`AF_QUERY_ID_COUNT`:: Request an integer value indicating the number
of instrument parameters supported by the file format in 'arg2'.

`AF_QUERY_IDS`:: Request an integer array containing the instrument
parameter values for the file format in 'arg2'.

`AF_QUERY_TYPE`:: For the file format in 'arg2', request the type
of the instrument parameter in 'arg3'.

`AF_QUERY_NAME`:: For the file format in 'arg2', request the name
of the instrument parameter in 'arg3'.

`AF_QUERY_DEFAULT`:: For the file format in 'arg2', request the
default value of the instrument parameter in 'arg3'.


ERRORS
------
afQuery can produce the following errors:

`AF_BAD_QUERYTYPE`:: The query type is unsupported.
`AF_BAD_QUERY`:: The arguments to the query are bad.

AUTHOR
------
Michael Pruett <michael@68k.org>
afReadFrames(3)
===============

NAME
----
afReadFrames - read sample frames from a track in an audio file

SYNOPSIS
--------
  #include <audiofile.h>

  AFframecount afReadFrames(AFfilehandle file, int track, void *data,
      int count);

DESCRIPTION
-----------
`afReadFrames` attempts to read up to 'count' frames of audio data from
the audio file handle 'file' into the buffer at 'data'.

PARAMETERS
----------
'file' is a valid file handle returned by linkaf:afOpenFile[3].

'track' is always `AF_DEFAULT_TRACK` for all currently supported file formats.

'data' is a buffer of storing 'count' frames of audio sample data.

'count' is the number of sample frames to be read.

RETURN VALUE
------------
`afReadFrames` returns the number of frames successfully read from 'file'.

ERRORS
------
`afReadFrames` can produce these errors:

`AF_BAD_FILEHANDLE`:: the file handle was invalid
`AF_BAD_TRACKID`:: the track parameter is not `AF_DEFAULT_TRACK`
`AF_BAD_READ`:: reading audio data from the file failed
`AF_BAD_LSEEK`:: seeking within the file failed

SEE ALSO
--------
linkaf:afWriteFrames[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
afReadMisc(3)
=============

NAME
----
afReadMisc, afWriteMisc, afSeekMisc - access miscellaneous metadata in an audio file

SYNOPSIS
--------
  #include <audiofile.h>

  int afReadMisc (AFfilehandle file, int miscid, void *buffer, int nbytes);

  int afWriteMisc (AFfilehandle file, int miscid, const void *buffer, int nbytes);

  int afSeekMisc (AFfilehandle file, int miscid, int offbytes);

DESCRIPTION
-----------
`afReadMisc` reads up to 'nbytes' from the miscellaneous data chunk
identified by 'miscid' in 'file'.

`afWriteMisc` writes up to 'nbytes' to the miscellaneous data chunk
identified by 'miscid' in 'file'.

`afSeekMisc` changes the current offset within the miscellaneous data
chunk identified by 'miscid' to the offset 'offbytes'.

RETURN VALUE
------------
`afReadMisc` returns the number of bytes read from the specified
miscellaneous chunk into the buffer referred to by 'buffer'.

`afWriteMisc` returns the number of bytes written to the specified
miscellaneous chunk from the buffer referred to by 'buffer'.

`afSeekMisc` returns the new location of the logical data pointer as
measured as an offset in bytes from the beginning of the miscellaneous
chunk's data area.

ERRORS
------
`afReadMisc`, `afWriteMisc`, and `afSeekMisc` can produce the following
error codes:

* `AF_BAD_READ`
* `AF_BAD_WRITE`
* `AF_BAD_MISCSEEK`
* `AF_BAD_MISCID`
* `AF_BAD_TRACKID`
* `AF_BAD_FILEHANDLE`

AUTHOR
------
Michael Pruett <michael@68k.org>
afSeekFrame(3)
==============

NAME
----
afSeekFrame, afTellFrame - update or access the current sample frame
position for a track in an audio file

SYNOPSIS
--------
  #include <audiofile.h>

  AFframecount afSeekFrame(AFfilehandle file, int track,
      AFframecount frameOffset);

  AFframecount afTellFrame(AFfilehandle file, int track);

PARAMETERS
----------
'file' is a valid audio file handle created by linkaf:afOpenFile[3].

'track' identifies an audio track within the file. `track` is always
`AF_DEFAULT_TRACK` for all currently supported audio file formats.

'frameOffset' is a sample frame offset. Valid sample frame offsets must
be greater than or equal to zero and strictly less than the number of
sample frames contained within the specified audio track. The special
value `-1` is also allowed.

DESCRIPTION
-----------
`afSeekFrame` moves the logical file position for a specified audio
track to a desired sample frame location. If `frameOffset` is `-1`,
`afSeekFrame` will not modify the current file offset and will instead
return the current file position.

`afTellFrame` returns current file position in sample frames.

RETURN VALUE
------------
On success, `afSeekFrame` and `afTellFrame` will return the current file
position as measured in sample frames from the start of the audio
track. On failure, `afSeekFrame` and `afTellFrame` will return the value
`-1`.

ERRORS
------
The following errors can be generated by `afSeekFrame` or `afTellFrame`:

`AF_BAD_FILEHANDLE`:: `file` does not represent a valid file handle.
`AF_BAD_TRACK`:: `track` does not identify a valid track.
`AF_BAD_LSEEK`:: A call to `lseek` failed.

AUTHOR
------
Michael Pruett <michael@68k.org>
afSetErrorHandler(3)
====================

NAME
----
afSetErrorHandler - install a custom error handling routine

SYNOPSIS
--------
  #include <audiofile.h>

  AFerrfunc afSetErrorHandler (AFerrfunc errorFunction);

PARAMETERS
----------
'errorFunction' is a pointer to an error handling function.

DESCRIPTION
-----------
`afSetErrorHandler` allows the user to install an error handling function
overriding the default function.

RETURN VALUE
------------
The value returned from `afSetErrorHandler` is a pointer to the previous
error handling function.

AUTHOR
------
Michael Pruett <michael@68k.org>
afSetVirtualSampleFormat(3)
===========================

NAME
----
afSetVirtualByteOrder, afSetVirtualChannels, afSetVirtualPCMMapping,
afSetVirtualSampleFormat - set the virtual data format for a track in
an audio file

SYNOPSIS
--------
  #include <audiofile.h>

  int afSetVirtualByteOrder (AFfilehandle file, int track, int byteOrder);

  int afSetVirtualChannels (AFfilehandle file, int track, int channels);

  int afSetVirtualSampleFormat (AFfilehandle file, int track,
      int sampleFormat, int sampleWidth);

  int afSetVirtualPCMMapping (AFfilehandle file, int track,
      double slope, double intercept, double minclip, double maxclip);

PARAMETERS
----------
* 'file' is an AFfilehandle which refers to an open audio file and is
  usually created by afOpenFile.

* 'track' is an integer which identifies a particular track in an open
  audio file.  The only valid track is `AF_DEFAULT_TRACK` for all
  currently supported file formats.

* 'sampleFormat' is an integer which denotes a virtual sample format.
  Valid values are `AF_SAMPFMT_TWOSCOMP`, `AF_SAMPFMT_UNSIGNED`,
  `AF_SAMPFMT_FLOAT`, and `AF_SAMPFMT_DOUBLE`.

* 'sampleWidth' is a positive integer which specifies the number of bits
  in a sample.

* 'channels' is a positive integer which specifies the number of
  interleaved audio channels in the given audio track.

* 'byteOrder' is an integer which specifies the virtual byte order of
  samples in the given audio track.  'byteOrder' can be either
  `AF_BYTEORDER_BIGENDIAN` or `AF_BYTEORDER_LITTLEENDIAN`.

* 'slope' and 'intercept' are double-precision floating point values which
  indicate the audio data sample slope and zero-crossing value,
  respectively, for the given sample format.

* 'minclip' and 'maxclip' are double-precision floating point values
  which indicates the minimum or maximum sample values to be returned.
  Any values less than 'minclip' will be set to 'minclip', and any values
  greater than 'maxclip' will be set to 'maxclip'.

RETURN VALUE
------------
These functions return 0 for success and -1 for failure.

AUTHOR
------
Michael Pruett <michael@68k.org>
afWriteFrames(3)
================

NAME
----
afWriteFrames - write sample frames to a track in an audio file

SYNOPSIS
--------
  #include <audiofile.h>

  AFframecount afWriteFrames(AFfilehandle file, int track, const void *data,
      AFframecount count);

DESCRIPTION
-----------
`afWriteFrames` attempts to write up to 'count' frames of audio data
from the buffer 'data' to the audio file handle 'file'.

PARAMETERS
----------
'file' is a valid file handle returned by linkaf:afOpenFile[3].

'track' is always `AF_DEFAULT_TRACK` for all currently supported file formats.

'data' is a buffer of sample frames to be written to the file.

'count' is the number of sample frames to be written.

RETURN VALUE
------------
`afWriteFrames` returns the number of sample frames successfully written
to 'file'.

ERRORS
------
`afWriteFrames` can produce these errors:

`AF_BAD_FILEHANDLE`:: the file handle was invalid
`AF_BAD_TRACKID`:: the track is not `AF_DEFAULT_TRACK`
`AF_BAD_WRITE`:: writing audio data to the file failed
`AF_BAD_LSEEK`:: seeking within the file failed

SEE ALSO
--------
linkaf:afReadFrames[3]

AUTHOR
------
Michael Pruett <michael@68k.org>
#
# Usage: linkaf:command[manpage-section]
#
# Note, {0} is the manpage section, while {target} is the command.
#
# Show Audio File Library link as: <command>(<section>); if section is
# defined, else just show the command.

[macros]
(?su)[\\]?(?P<name>linkaf):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=

ifdef::backend-docbook[]
[linkaf-inlinemacro]
{0%{target}}
{0#<citerefentry>}
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
{0#</citerefentry>}
endif::backend-docbook[]

ifdef::backend-html4[]
[linkaf-inlinemacro]
<a href="{target}.{0}.html">{target}({0})</a>
endif::backend-html4[]
sfconvert(1)
============

NAME
----
sfconvert - convert audio files

SYNOPSIS
--------
*sfconvert* 'infile' 'outfile' ['output options']

DESCRIPTION
-----------
The `sfconvert` command converts an audio file to another file format or data format.

OPTIONS
-------
The following keywords specify the format of the output sound file:

`format` 'f'::
  Output file format. 'f' must be one of the following:
[horizontal]
    `aiff`::: Audio Interchange File Format
    `aifc`::: AIFF-C
    `next`::: NeXT/Sun .snd/.au Format
    `wave`::: MS RIFF WAVE
    `bicsf`::: Berkeley/IRCAM/CARL Sound File Format
    `smp`::: Sample Vision Format
    `voc`::: Creative Voice File Format
    `nist`::: NIST SPHERE Format
    `caf`::: Core Audio Format
    `flac`::: FLAC
`compression` 'c'::
[horizontal]
    `ulaw`::: G.711 mu-law
    `alaw`::: G.711 A-law
    `ima`::: IMA ADPCM
    `msadpcm`::: Microsoft ADPCM
    `flac`::: FLAC
    `alac`::: Apple Lossless Audio Codec
`byteorder` 'e'::
  Output byte order. 'e' may be either `big` or `little`.
`channels` 'n'::
  Number of output channels. 'n' is 1 for mono, and 2 for stereo.
`integer` 'n' 's'::
  Convert to integer audio data. 'n' indicates the output sample width
  in bits. 's' specifies the sample format and may be either `2scomp`
  for 2's complement signed data or `unsigned` for unsigned data.
`float` 'm'::
  Convert to floating-point audio data with a maximum amplitude of
  'm' (usually `1.0`). The `integer` and `float` options are mutually
  exclusive.

The following options take no additional arguments:

`--help`::
`-h`::
Print help message.

`--version`::
`-v`::
Print version information.

SEE ALSO
--------
linkaf:sfinfo[1]

AUTHOR
------
Michael Pruett <michael@68k.org>
sfinfo(1)
=========

NAME
----
sfinfo - display information about audio files

SYNOPSIS
--------
*sfinfo* ['options'] 'audio files'...

DESCRIPTION
-----------
`sfinfo` prints information about the specified audio files, including
file format, sample rate, duration, and audio data format.

By default `sfinfo` displays information in a longer, multi-line format;
specifying the --short or -s option produces a short, single-line summary.

Any files which are not recognized as valid audio files will be ignored
unless the --reporterror or -r option is given. The file formats
currently supported by `sfinfo` are AIFF, AIFF-C, NeXT/Sun .snd/.au,
WAVE, Berkeley/IRCAM/CARL Sound File, AVR, Amiga IFF/8SVX, Sample Vision,
Creative Voice File, NIST SPHERE, and Core Audio Format.

OPTIONS
-------

`--short`::
`-s`::
Print short single-line summary of each recognized audio file.

`--reporterror`::
`-r`::
Print an error message if any of the specified files are not recognized
as valid audio files.

`--help`::
`-h`::
Print help message.

`--version`::
`-v`::
Print version information.

EXAMPLES
--------
Display summary of an audio file:

----
% sfinfo drum.aiff
File Name      drum.aiff
File Format    Audio Interchange File Format (aiff)
Data Format    16-bit integer (2's complement, big endian)
Audio Data     1569972 bytes begins at offset 54 (36 hex)
               2 channels, 392493 frames
Sampling Rate  44100.00 Hz
Duration       8.900 seconds
----

List all recognized audio files in the current directory using
the short output format:

----
% sfinfo -s *
    9.60s 44100.00 aiff  1ch 16b -- bass.aiff
    8.90s 44100.00 aiff  2ch 16b -- drum.aiff
----

SEE ALSO
--------
linkaf:sfconvert[1]

AUTHOR
------
Michael Pruett <michael@68k.org>
adddcoffset
alsaplay
irixread
irixtestloop
linuxtest
osxplay
power
AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile

noinst_PROGRAMS = \
	adddcoffset \
	power \
	@TEST_BIN@

EXTRA_PROGRAMS = alsaplay irixread irixtestloop linuxtest osxplay

LIBAUDIOFILE = $(top_builddir)/libaudiofile/libaudiofile.la

alsaplay_SOURCES = alsaplay.cpp
alsaplay_LDADD = $(LIBAUDIOFILE) -lasound

irixread_SOURCES = irixread.c sgi.c sgi.h
irixread_LDADD = $(LIBAUDIOFILE) -laudio

irixtestloop_SOURCES = irixtestloop.c sgi.c sgi.h
irixtestloop_LDADD = $(LIBAUDIOFILE) -laudio

linuxtest_SOURCES = linuxtest.c

osxplay_SOURCES = osxplay.c
osxplay_LDFLAGS = -framework AudioUnit -framework CoreServices

power_SOURCES = power.c
power_LDADD = $(LIBAUDIOFILE) -lm

LDADD = $(LIBAUDIOFILE)

DEPENDENCIES = $(LIBAUDIOFILE)
/*
	Audio File Library

	Copyright 1998, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	adddcoffset.c

	This program adds a user-specified DC offset term to a sound file.
	It's not very useful.
*/

#include <stdio.h>
#include <stdlib.h>

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include "audiofile.h"
#endif

void adddcoffset (float offset, char *infilename, char *outfilename);
void usageerror (void);

int main (int ac, char **av)
{
	float	offset;

	if (ac != 4)
		usageerror();

	offset = atof(av[1]);
	adddcoffset(offset, av[2], av[3]);
	return 0;
}

void adddcoffset (float offset, char *infilename, char *outfilename)
{
	AFfilehandle	infile = afOpenFile(infilename, "r", NULL);
	int				channelCount, frameCount;
	short			*buffer;
	int				i;

	AFfilesetup		outfilesetup = afNewFileSetup();
	AFfilehandle	outfile;

	frameCount = afGetFrameCount(infile, AF_DEFAULT_TRACK);
	channelCount = afGetChannels(infile, AF_DEFAULT_TRACK);

	afInitFileFormat(outfilesetup, AF_FILE_AIFF);
	afInitByteOrder(outfilesetup, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN);
	afInitChannels(outfilesetup, AF_DEFAULT_TRACK, channelCount);
	afInitRate(outfilesetup, AF_DEFAULT_TRACK, 44100.0);
	afInitSampleFormat(outfilesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	outfile = afOpenFile(outfilename, "w", outfilesetup);

	if (infile == NULL)
	{
		printf("unable to open input file '%s'.\n", infilename);
		return;
	}

	printf("afGetFrameCount: %d\n", (int)afGetFrameCount(infile, AF_DEFAULT_TRACK));
	printf("afGetChannels: %d\n", afGetChannels(infile, AF_DEFAULT_TRACK));

	buffer = (short *) malloc(frameCount * channelCount * sizeof (short));
	afReadFrames(infile, AF_DEFAULT_TRACK, (void *) buffer, frameCount);

	for (i=0; i<frameCount; i++)
	{
		buffer[i] += offset;
	}

	afWriteFrames(outfile, AF_DEFAULT_TRACK, (void *) buffer, frameCount);
	afCloseFile(outfile);
}

void usageerror (void)
{
	fprintf(stderr, "usage: adddcoffset offset infile outfile\n");
	exit(EXIT_FAILURE);
}
/*
	Audio File Library

	Copyright (c) 2010, Michael Pruett.  All rights reserved.

	Redistribution and use in source and binary forms, with or
	without modification, are permitted provided that the following
	conditions are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above
	copyright notice, this list of conditions and the following
	disclaimer in the documentation and/or other materials provided
	with the distribution.

	3. The name of the author may not be used to endorse or promote
	products derived from this software without specific prior
	written permission.

	THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
	WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <alsa/asoundlib.h>
#include <audiofile.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
	if (argc != 2)
	{
		fprintf(stderr, "usage: %s filename\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	AFfilehandle file = afOpenFile(argv[1], "r", AF_NULL_FILESETUP);
	if (!file)
	{
		fprintf(stderr, "Could not open '%s'.\n", argv[1]);
		exit(EXIT_FAILURE);
	}

	int channels = afGetChannels(file, AF_DEFAULT_TRACK);
	double rate = afGetRate(file, AF_DEFAULT_TRACK);
	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	int err;
	snd_pcm_t *handle;
	if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
	{
		fprintf(stderr, "Could not open audio output: %s\n", snd_strerror(err));
		exit(EXIT_FAILURE);
	}

	if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16,
		SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 1, 500000)) < 0)
	{
		fprintf(stderr, "Could not set audio output parameters: %s\n", snd_strerror(err));
		exit(EXIT_FAILURE);
	}

	const int bufferFrames = 4096;
	int16_t *buffer = new int16_t[bufferFrames * channels];

	while (true)
	{
		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer, bufferFrames);
		if (framesRead <= 0)
			break;

		snd_pcm_sframes_t framesWritten = snd_pcm_writei(handle, buffer, bufferFrames);
		if (framesWritten < 0)
			framesWritten = snd_pcm_recover(handle, framesWritten, 0);
		if (framesWritten < 0)
		{
			fprintf(stderr, "Could not write audio data to output device: %s\n",
				snd_strerror(err));
			break;
		}
	}

	snd_pcm_drain(handle);
	snd_pcm_close(handle);
	delete [] buffer;

	afCloseFile(file);

	return 0;
}
/*
	Audio File Library

	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	irixread.c

	This program reads and plays a given audio file using Irix's
	default audio output device.  This file will not work on any
	operating system other than Irix.

	The only difference between this program and irixtest is that this
	program does not load the entire audio track into memory at once.
	Only a small number of frames are read into a buffer and then
	written to the audio port.  While there are more frames to be
	read, this process is repeated.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dmedia/audio.h>
#include <dmedia/audiofile.h>

#include "sgi.h"

const int BUFFERED_FRAME_COUNT = 65536;

void usage (void)
{
	fprintf(stderr, "usage: irixread filename\n");
	exit(EXIT_FAILURE);
}

main (int argc, char **argv)
{
	AFfilehandle	file;
	AFframecount	count, frameCount;
	int		channelCount, sampleFormat, sampleWidth;
	float		frameSize;
	void		*buffer;
	double		sampleRate;

	ALport		outport;
	ALconfig	outportconfig;

	if (argc < 2)
		usage();

	file = afOpenFile(argv[1], "r", NULL);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "Could not open file %s.\n", argv[1]);
		exit(EXIT_FAILURE);
	}

	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
	frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
	channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
	sampleRate = afGetRate(file, AF_DEFAULT_TRACK);
	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat,
		&sampleWidth);

	if (sampleFormat == AF_SAMPFMT_UNSIGNED)
	{
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
			AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}

	printf("frame count: %lld\n", frameCount);
	printf("frame size: %d bytes\n", (int) frameSize);
	printf("channel count: %d\n", channelCount);
	printf("sample rate: %.2f Hz\n", sampleRate);
	buffer = malloc(BUFFERED_FRAME_COUNT * frameSize);

	outportconfig = alNewConfig();
	setwidth(outportconfig, sampleWidth);
	setsampleformat(outportconfig, sampleFormat);
	alSetChannels(outportconfig, channelCount);

	count = afReadFrames(file, AF_DEFAULT_TRACK, buffer, BUFFERED_FRAME_COUNT);

	outport = alOpenPort("irixread", "w", outportconfig);
	setrate(outport, sampleRate);

	do
	{
		printf("count = %lld\n", count);
		alWriteFrames(outport, buffer, count);

		count = afReadFrames(file, AF_DEFAULT_TRACK, buffer,
			BUFFERED_FRAME_COUNT);
	} while (count > 0);

	waitport(outport);

	alClosePort(outport);
	alFreeConfig(outportconfig);

	afCloseFile(file);
}
/*
	Audio File Library

	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	irixtestloop.c

	This file reads the loop points from a file (presumably AIFF) and
	loops that part of the file several times.  Audio output is routed
	to IRIX's default audio output device.  This program will not
	compile on any platform other than IRIX.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dmedia/audio.h>
#include <dmedia/audiofile.h>

#include "sgi.h"

const int REPEAT_COUNT = 3;

void usage (void)
{
	printf("usage: irixtestloop file\n");
	printf("where file is of a format which contains a loop (e.g. AIFF)\n");
	exit(EXIT_FAILURE);
}

main (int argc, char **argv)
{
	AFfilehandle	file;
	void		*buffer;

	AFframecount	frameCount;
	int		sampleFormat, sampleWidth, channelCount;
	float		frameSize;
	double		sampleRate;

	int		*loopids, *markids;
	int		i, loopCount, markCount;
	int		startmarkid, endmarkid;
	AFframecount	startloop, endloop;

	ALport		outport;
	ALconfig	outportconfig;

	if (argc < 2)
		usage();

	file = afOpenFile(argv[1], "r", NULL);
	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
	frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
	channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	sampleRate = afGetRate(file, AF_DEFAULT_TRACK);

	/*
		If the file's sample format is unsigned integer data,
		change the virtual sample format to two's complement
		since the SGI Audio Library won't accept unsigned
		data.
	*/
	if (sampleFormat == AF_SAMPFMT_UNSIGNED)
	{
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
			AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}

	printf("frame count: %lld\n", frameCount);
	printf("frame size: %d bytes\n", frameSize);
	printf("channel count: %d\n", channelCount);
	printf("sample rate: %.2f Hz\n", sampleRate);

	buffer = malloc(frameCount * frameSize);
	afReadFrames(file, AF_DEFAULT_TRACK, buffer, frameCount);

	loopCount = afGetLoopIDs(file, AF_DEFAULT_INST, NULL);
	loopids = malloc(sizeof (int) * loopCount);
	afGetLoopIDs(file, AF_DEFAULT_INST, loopids);

	markCount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
	markids = malloc(sizeof (int) * markCount);
	afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);

	printf("loop ids:");
	for (i=0; i<loopCount; i++)
		printf(" %d", loopids[i]);
	printf("\n");

	printf("mark ids:");
	for (i=0; i<markCount; i++)
		printf(" %d", markids[i]);
	printf("\n");

	startmarkid = afGetLoopStart(file, AF_DEFAULT_INST, 1);
	endmarkid = afGetLoopEnd(file, AF_DEFAULT_INST, 1);
	startloop = afGetMarkPosition(file, AF_DEFAULT_TRACK, startmarkid);
	endloop = afGetMarkPosition(file, AF_DEFAULT_TRACK, endmarkid);

	afCloseFile(file);

	outportconfig = alNewConfig();
	setwidth(outportconfig, sampleWidth);
	setsampleformat(outportconfig, sampleFormat);
	alSetChannels(outportconfig, channelCount);

	outport = alOpenPort("irixtestloop", "w", outportconfig);
	setrate(outport, sampleRate);

	alWriteFrames(outport, buffer, startloop);
	for (i=0; i<REPEAT_COUNT; i++)
	{
		printf("iteration %d: start %lld, end %lld, length %lld\n",
			i, endloop, startloop, endloop - startloop);
		alWriteFrames(outport,
			(char *) buffer + (int) (startloop * frameSize),
			endloop - startloop);
	}

	waitport(outport);

	alClosePort(outport);
	alFreeConfig(outportconfig);

	free(buffer);
}
/*
	Audio File Library

	Copyright (c) 1998-1999, Michael Pruett <michael@68k.org>
	Copyright (c) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	linuxtest.c

	This file plays a 16-bit, 44.1 kHz monophonic or stereophonic
	audio file through a PC sound card on a Linux system.  This file
	will not compile under any operating system that does not support
	the Open Sound System API.
*/

#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/soundcard.h>

#include <audiofile.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*
	If it's not defined already, define the native audio hardware
	byte order.
*/

#ifndef AFMT_S16_NE
#ifdef WORDS_BIGENDIAN /* defined in config.h */
#define AFMT_S16_NE AFMT_S16_BE
#else
#define AFMT_S16_NE AFMT_S16_LE
#endif /* WORDS_BIGENDIAN */
#endif /* AFMT_S16_NE */

void setupdsp (int audiofd, int channelCount, int frequency);
void usage (void);

/* BUFFER_FRAMES represents the size of the buffer in frames. */
#define BUFFER_FRAMES 4096

int main (int argc, char **argv)
{
	if (argc != 2)
		usage();

	AFfilehandle file = afOpenFile(argv[1], "r", NULL);
	AFframecount frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);
	printf("frame count: %jd\n", (intmax_t) frameCount);

	int channelCount = afGetVirtualChannels(file, AF_DEFAULT_TRACK);
	int sampleFormat, sampleWidth;
	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat,
		&sampleWidth);
	double frequency = afGetRate(file, AF_DEFAULT_TRACK);

	float frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);

	printf("sample format: %d, sample width: %d, channels: %d\n",
		sampleFormat, sampleWidth, channelCount);

	if ((sampleFormat != AF_SAMPFMT_TWOSCOMP) &&
		(sampleFormat != AF_SAMPFMT_UNSIGNED))
	{
		fprintf(stderr, "The audio file must contain integer data in two's complement or unsigned format.\n");
		exit(EXIT_FAILURE);
	}

	if ((sampleWidth != 16) || (channelCount > 2))
	{
		fprintf(stderr, "The audio file must be of a 16-bit monophonic or stereophonic format.\n");
		exit(EXIT_FAILURE);
	}

	void *buffer = malloc(BUFFER_FRAMES * frameSize);

	int audiofd = open("/dev/dsp", O_WRONLY);
	if (audiofd < 0)
	{
		perror("open");
		exit(EXIT_FAILURE);
	}

	setupdsp(audiofd, channelCount, frequency);

	while (1)
	{
		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer,
			BUFFER_FRAMES);
		if (framesRead <= 0)
			break;

		printf("read %jd frames\n", (intmax_t) framesRead);

		ssize_t bytesWritten = write(audiofd, buffer, framesRead * frameSize);
		if (bytesWritten < 0)
			break;
	}

	close(audiofd);
	free(buffer);

	return 0;
}

void setupdsp (int audiofd, int channelCount, int frequency)
{
	int format = AFMT_S16_NE;
	if (ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) == -1)
	{
		perror("set format");
		exit(EXIT_FAILURE);
	}

	if (format != AFMT_S16_NE)
	{
		fprintf(stderr, "format not correct.\n");
		exit(EXIT_FAILURE);
	}

	if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &channelCount) == -1)
	{
		perror("set channels");
		exit(EXIT_FAILURE);
	}

	if (ioctl(audiofd, SNDCTL_DSP_SPEED, &frequency) == -1)
	{
		perror("set frequency");
		exit(EXIT_FAILURE);
	}
}

void usage (void)
{
	fprintf(stderr, "usage: linuxtest file\n");
	fprintf(stderr,
		"where file refers to a 16-bit monophonic or stereophonic 44.1 kHz audio file\n");
	exit(EXIT_FAILURE);
}
/*
	Audio File Library

	Copyright (c) 2003, Michael Pruett.  All rights reserved.

	Redistribution and use in source and binary forms, with or
	without modification, are permitted provided that the following
	conditions are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above
	copyright notice, this list of conditions and the following
	disclaimer in the documentation and/or other materials provided
	with the distribution.

	3. The name of the author may not be used to endorse or promote
	products derived from this software without specific prior
	written permission.

	THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
	WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	osxplay.c

	This program demonstrates audio file playback using the Audio
	File Library and Core Audio.
*/

#include <audiofile.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>

#define BUFFER_FRAME_COUNT 1024

int isPlaying = 1;
void *buffer = NULL;

void getASBDForFile (AFfilehandle file, int track,
	AudioStreamBasicDescription *asbd)
{
	int	sampleFormat, sampleWidth, channelCount;
	double	rate;

	afGetVirtualSampleFormat(file, track, &sampleFormat, &sampleWidth);
	channelCount = afGetChannels(file, track);
	rate = afGetRate(file, track);

	asbd->mSampleRate = rate;
	asbd->mFormatID = kAudioFormatLinearPCM;
	switch (sampleFormat)
	{
		case AF_SAMPFMT_TWOSCOMP:
			asbd->mFormatFlags = kAudioFormatFlagIsSignedInteger;
			asbd->mBitsPerChannel = sampleWidth;
			break;
		case AF_SAMPFMT_UNSIGNED:
			asbd->mFormatFlags = 0;
			asbd->mBitsPerChannel = sampleWidth;
			break;
		case AF_SAMPFMT_FLOAT:
			asbd->mFormatFlags = kAudioFormatFlagIsFloat;
			asbd->mBitsPerChannel = 32;
			break;
		case AF_SAMPFMT_DOUBLE:
			asbd->mFormatFlags = kAudioFormatFlagIsFloat;
			asbd->mBitsPerChannel = 64;
			break;
	}

	asbd->mChannelsPerFrame = channelCount;
	asbd->mFramesPerPacket = 1;
	asbd->mBytesPerFrame = ceilf(afGetVirtualFrameSize(file, track, 1));
	asbd->mBytesPerPacket = asbd->mBytesPerFrame;

	if (afGetVirtualByteOrder(file, track) == AF_BYTEORDER_BIGENDIAN)
		asbd->mFormatFlags |= kAudioFormatFlagIsBigEndian;
}

OSStatus openOutput (AudioUnit *outputUnit)
{
	OSStatus		status = noErr;
	ComponentDescription	description;
	Component		component;

	description.componentType = kAudioUnitType_Output;
	description.componentSubType = kAudioUnitSubType_DefaultOutput;
	description.componentManufacturer = kAudioUnitManufacturer_Apple;
	description.componentFlags = 0;
	description.componentFlagsMask = 0;

	component = FindNextComponent(NULL, &description);
	if (component == NULL)
	{
		fprintf(stderr, "Could not find audio output device.\n");
		exit(EXIT_FAILURE);
	}

	status = OpenAComponent(component, outputUnit);
	if (status != noErr)
	{
		fprintf(stderr, "Could not open audio output device.\n");
		exit(EXIT_FAILURE);
	}

	status = AudioUnitInitialize(*outputUnit);
	if (status != noErr)
	{
		fprintf(stderr, "Could not initialize audio output device.\n");
		exit(EXIT_FAILURE);
	}

	return status;
}

OSStatus fileRenderProc (void *inRefCon,
	AudioUnitRenderActionFlags *inActionFlags,
	const AudioTimeStamp *inTimeStamp,
	UInt32 inBusNumber,
	UInt32 inNumFrames,
	AudioBufferList *ioData)
{
	AFfilehandle	file = (AFfilehandle) inRefCon;
	AFframecount	framesToRead, framesRead;

	framesToRead = inNumFrames;
	if (framesToRead > BUFFER_FRAME_COUNT)
		framesToRead = BUFFER_FRAME_COUNT;

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
		buffer, framesToRead);
	if (framesRead > 0)
	{
		ioData->mBuffers[0].mData = buffer;
		ioData->mBuffers[0].mDataByteSize = framesRead *
			afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1);
	}
	else
		isPlaying = 0;

	return noErr;
}

OSStatus setupOutput (AudioUnit *outputUnit, AFfilehandle file)
{
	OSStatus	status = noErr;
	UInt32		size;
	Boolean		outWritable;

	AudioStreamBasicDescription	fileASBD, inputASBD, outputASBD;
	AURenderCallbackStruct		renderCallback;

	/* Set virtual sample format to single-precision floating-point. */
	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);

	/* Get ASBD for virtual sample format. */ 
	getASBDForFile(file, AF_DEFAULT_TRACK, &fileASBD);

	status = AudioUnitGetPropertyInfo(*outputUnit,
		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
		0, &size, &outWritable);

	status = AudioUnitGetProperty(*outputUnit,
		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
		0, &outputASBD, &size);

	if (outWritable)
	{
		outputASBD = fileASBD;

		status = AudioUnitSetProperty(*outputUnit,
			kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
			0, &outputASBD, size);
	}

	inputASBD = fileASBD;

	status = AudioUnitSetProperty(*outputUnit,
		kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
		0, &inputASBD, size);
	if (status != noErr)
	{
		fprintf(stderr, "Could not set input stream format.\n");
		exit(EXIT_FAILURE);
	}

	/*
		Set the render callback to a procedure which will
		read from the file.
	*/
	renderCallback.inputProc = fileRenderProc;
	renderCallback.inputProcRefCon = file;

	status = AudioUnitSetProperty(*outputUnit,
		kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0,
		&renderCallback, sizeof (AURenderCallbackStruct));
	if (status != noErr)
	{
		fprintf(stderr, "Could not set render callback.\n");
		exit(EXIT_FAILURE);
	}

	return status;
}

int main (int argc, char **argv)
{
	AFfilehandle	file;
	AudioUnit	outputUnit;

	if (argc < 2)
	{
		fprintf(stderr, "usage: %s filename\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(argv[1], "r", AF_NULL_FILESETUP);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "Could not open file '%s' for reading.\n", argv[1]);
		exit(EXIT_FAILURE);
	}

	openOutput(&outputUnit);
	setupOutput(&outputUnit, file);
	AudioOutputUnitStart(outputUnit);

	buffer = malloc(BUFFER_FRAME_COUNT *
		afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1));

	while (isPlaying)
		usleep(250000);

	AudioOutputUnitStop(outputUnit);
	AudioUnitUninitialize(outputUnit);
	CloseComponent(outputUnit);

	free(buffer);

	afCloseFile(file);
}
/*
	This program is derived from Chris Vaill's normalize program
	and has been modified to use the Audio File Library for file
	reading and audio data conversion.

	Copyright (C) 2001, Silicon Graphics, Inc.
	Copyright (C) 1999-2001, Chris Vaill

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	power.c

	Calculate the power and peak amplitudes of an audio file.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <audiofile.h>

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

struct smooth
{
	double	*buf;
	int	length, start, n;
};

static double get_smoothed_data (struct smooth *s)
{
	int i;
	double smoothed;

	smoothed = 0;
	for (i = 0; i < s->n; i++)
		smoothed += s->buf[i];
	smoothed = smoothed / s->n;

	return smoothed;
}

void print_power (char *filename);

int main (int argc, char **argv)
{
	int	i;

	if (argc < 2)
	{
		fprintf(stderr, "usage: %s filename [more filenames...]\n",
			argv[0]);
		exit(EXIT_FAILURE);
	}

	for (i=1; i<argc; i++)
		print_power(argv[i]);

	return 0;
}

void print_power (char *filename)
{
	AFfilehandle	file;
	double		*sums, *frames;
	int		channelCount, windowSize, frameCount;
	int		i, c;
	struct smooth	*powsmooth;
	int		winStart, winEnd;
	int		lastWindow = FALSE;
	double		pow, maxpow;

	double		level, peak, minSample = 1, maxSample = -1;

	file = afOpenFile(filename, "r", NULL);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "Could not open file %s.\n", filename);
		return;
	}

	channelCount = afGetChannels(file, AF_DEFAULT_TRACK);
	windowSize = afGetRate(file, AF_DEFAULT_TRACK) / 100;
	frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK);

	sums = calloc(channelCount, sizeof (double));
	for (c=0; c<channelCount; c++)
		sums[c] = 0;

	frames = calloc(channelCount * windowSize, sizeof (double));

	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_DOUBLE,
		sizeof (double));

	powsmooth = calloc(channelCount, sizeof (struct smooth));
	for (c=0; c<channelCount; c++)
	{
		/* Use a 100-element (1 second) window. */
		powsmooth[c].length = 100;
		powsmooth[c].buf = calloc(powsmooth[c].length, sizeof (double));
		powsmooth[c].start = 0;
		powsmooth[c].n = 0;
	}

	winStart = 0;
	winEnd = 0;
	lastWindow = FALSE;
	maxpow = 0;

	do
	{
		winEnd = winStart + windowSize;

		if (winEnd >= frameCount)
		{
			winEnd = frameCount;
			lastWindow = TRUE;
		}

		afReadFrames(file, AF_DEFAULT_TRACK, frames, windowSize);

		for (c=0; c<channelCount; c++)
		{
			sums[c] = 0;

			for (i=0; i < winEnd - winStart; i++)
			{
				double	sample;

				sample = frames[i*channelCount + c];
				sums[c] += sample*sample;

				if (sample > maxSample)
					maxSample = sample;
				if (sample < minSample)
					minSample = sample;
			}
		}

		/* Compute power for each channel. */
		for (c=0; c<channelCount; c++)
		{
			double pow;
			int end;

			pow = sums[c] / (winEnd - winStart);

			end = (powsmooth[c].start + powsmooth[c].n) %
				powsmooth[c].length;
			powsmooth[c].buf[end] = pow;

			if (powsmooth[c].n == powsmooth[c].length)
			{
				powsmooth[c].start = (powsmooth[c].start + 1) % powsmooth[c].length;
				pow = get_smoothed_data(&powsmooth[c]);
				if (pow > maxpow)
					maxpow = pow;
			}
			else
			{
				powsmooth[c].n++;
			}
		}

		winStart += windowSize;
	} while (!lastWindow);

	for (c = 0; c < channelCount; c++)
	{
		pow = get_smoothed_data(&powsmooth[c]);
		if (pow > maxpow)
			maxpow = pow;
	}

	free(sums);
	free(frames);
	for (c=0; c<channelCount; c++)
		free(powsmooth[c].buf);
	free(powsmooth);

	level = sqrt(maxpow);

	afCloseFile(file);

	printf("file: %s\n", filename);

	printf("level (dB): %f\n", 20 * log10(level));
	printf("peak-: %f\n", minSample);
	printf("peak+: %f\n", maxSample);

	peak = fabs(minSample);
	if (peak < fabs(maxSample))
		peak = fabs(maxSample);

	printf("peak (dB): %f\n", 20 * log10(peak));
}
/*
	Audio File Library

	Copyright 1998-1999, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	sgi.c

	These routines are used in SGI-specific test programs.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <unistd.h>

#include <audiofile.h>

#include <dmedia/audio.h>

/*
	Set the sample width of an audio configuration.
*/
void setwidth (ALconfig config, int sampleWidth)
{
	if (sampleWidth <= 8)
	{
		printf("setting width to 8\n");
		alSetWidth(config, AL_SAMPLE_8);
	}
	else if (sampleWidth <= 16)
	{
		printf("setting width to 16\n");
		alSetWidth(config, AL_SAMPLE_16);
	}
	else if (sampleWidth <= 24)
	{
		printf("setting width to 24\n");
		alSetWidth(config, AL_SAMPLE_24);
	}
}

/*
	Set the sample format of an audio configuration.
*/
void setsampleformat (ALconfig config, int audioFileSampleFormat)
{
	if (audioFileSampleFormat == AF_SAMPFMT_TWOSCOMP)
	{
		printf("setting sample format to 2's complement\n");
		alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP);
	}
	else if (audioFileSampleFormat == AF_SAMPFMT_FLOAT)
	{
		printf("setting sample format to float\n");
		alSetSampFmt(config, AL_SAMPFMT_FLOAT);
	}
	else if (audioFileSampleFormat == AF_SAMPFMT_DOUBLE)
	{
		printf("setting sample format to double\n");
		alSetSampFmt(config, AL_SAMPFMT_DOUBLE);
	}
}

/*
	Set the sample rate of an audio port.
*/
void setrate (ALport port, double rate)
{
	int		rv;
	ALpv	params;

	rv = alGetResource(port);

	params.param = AL_RATE;
	params.value.ll = alDoubleToFixed(rate);

	if (alSetParams(rv, &params, 1) < 0)
	{
		printf("alSetParams failed: %s\n", alGetErrorString(oserror()));
	}
}

/*
	Wait until the audio port has no more samples to play.
*/
void waitport (ALport port)
{
	while (alGetFilled(port) > 0)
		sginap(1);
}
/*
	Audio File Library

	Copyright 1998-1999, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	sgi.h

	These routines are used in SGI-specific test programs.
*/

#ifndef SGI_H
#define SGI_H

#include <dmedia/audio.h>

/*
	Set the sample width of an audio configuration.
*/
void setwidth (ALconfig config, int width);

/*
	Set the sample format of an audio configuration.
*/
void setsampleformat (ALconfig config, int width);

/*
	Set the sample rate of an audio port.
*/
void setrate (ALport port, double rate);

/*
	Wait until the audio port has no more samples to play.
*/
void waitport (ALport port);

#endif
check_LTLIBRARIES = libgtest.la
libgtest_la_SOURCES = gtest-all.cc gtest.h
libgtest_la_LIBADD = -lpthread
libgtest_la_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
libgtest_la_CPPFLAGS = -I$(top_srcdir)
EXTRA_DIST = README.audiofile
This directory contains Google Test version 1.7.0. The fused-source
implementation is used here for simplicity and compactness.

http://code.google.com/p/googletest/
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: mheule@google.com (Markus Heule)
//
// Google C++ Testing Framework (Google Test)
//
// Sometimes it's desirable to build Google Test by compiling a single file.
// This file serves this purpose.

// This line ensures that gtest.h can be compiled on its own, even
// when it's fused.
#include "gtest/gtest.h"

// The following lines pull in the real gtest *.cc files.
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// The Google C++ Testing Framework (Google Test)

// Copyright 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// Utilities for testing Google Test itself and code that uses Google Test
// (e.g. frameworks built on top of Google Test).

#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_


namespace testing {

// This helper class can be used to mock out Google Test failure reporting
// so that we can test Google Test or code that builds on Google Test.
//
// An object of this class appends a TestPartResult object to the
// TestPartResultArray object given in the constructor whenever a Google Test
// failure is reported. It can either intercept only failures that are
// generated in the same thread that created this object or it can intercept
// all generated failures. The scope of this mock object can be controlled with
// the second argument to the two arguments constructor.
class GTEST_API_ ScopedFakeTestPartResultReporter
    : public TestPartResultReporterInterface {
 public:
  // The two possible mocking modes of this object.
  enum InterceptMode {
    INTERCEPT_ONLY_CURRENT_THREAD,  // Intercepts only thread local failures.
    INTERCEPT_ALL_THREADS           // Intercepts all failures.
  };

  // The c'tor sets this object as the test part result reporter used
  // by Google Test.  The 'result' parameter specifies where to report the
  // results. This reporter will only catch failures generated in the current
  // thread. DEPRECATED
  explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);

  // Same as above, but you can choose the interception scope of this object.
  ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
                                   TestPartResultArray* result);

  // The d'tor restores the previous test part result reporter.
  virtual ~ScopedFakeTestPartResultReporter();

  // Appends the TestPartResult object to the TestPartResultArray
  // received in the constructor.
  //
  // This method is from the TestPartResultReporterInterface
  // interface.
  virtual void ReportTestPartResult(const TestPartResult& result);
 private:
  void Init();

  const InterceptMode intercept_mode_;
  TestPartResultReporterInterface* old_reporter_;
  TestPartResultArray* const result_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
};

namespace internal {

// A helper class for implementing EXPECT_FATAL_FAILURE() and
// EXPECT_NONFATAL_FAILURE().  Its destructor verifies that the given
// TestPartResultArray contains exactly one failure that has the given
// type and contains the given substring.  If that's not the case, a
// non-fatal failure will be generated.
class GTEST_API_ SingleFailureChecker {
 public:
  // The constructor remembers the arguments.
  SingleFailureChecker(const TestPartResultArray* results,
                       TestPartResult::Type type,
                       const string& substr);
  ~SingleFailureChecker();
 private:
  const TestPartResultArray* const results_;
  const TestPartResult::Type type_;
  const string substr_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
};

}  // namespace internal

}  // namespace testing

// A set of macros for testing Google Test assertions or code that's expected
// to generate Google Test fatal failures.  It verifies that the given
// statement will cause exactly one fatal Google Test failure with 'substr'
// being part of the failure message.
//
// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
// affects and considers failures generated in the current thread and
// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
//
// The verification of the assertion is done correctly even when the statement
// throws an exception or aborts the current function.
//
// Known restrictions:
//   - 'statement' cannot reference local non-static variables or
//     non-static members of the current object.
//   - 'statement' cannot return a value.
//   - You cannot stream a failure message to this macro.
//
// Note that even though the implementations of the following two
// macros are much alike, we cannot refactor them to use a common
// helper macro, due to some peculiarity in how the preprocessor
// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in
// gtest_unittest.cc will fail to compile if we do that.
#define EXPECT_FATAL_FAILURE(statement, substr) \
  do { \
    class GTestExpectFatalFailureHelper {\
     public:\
      static void Execute() { statement; }\
    };\
    ::testing::TestPartResultArray gtest_failures;\
    ::testing::internal::SingleFailureChecker gtest_checker(\
        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
    {\
      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
          ::testing::ScopedFakeTestPartResultReporter:: \
          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
      GTestExpectFatalFailureHelper::Execute();\
    }\
  } while (::testing::internal::AlwaysFalse())

#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
  do { \
    class GTestExpectFatalFailureHelper {\
     public:\
      static void Execute() { statement; }\
    };\
    ::testing::TestPartResultArray gtest_failures;\
    ::testing::internal::SingleFailureChecker gtest_checker(\
        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
    {\
      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
          ::testing::ScopedFakeTestPartResultReporter:: \
          INTERCEPT_ALL_THREADS, &gtest_failures);\
      GTestExpectFatalFailureHelper::Execute();\
    }\
  } while (::testing::internal::AlwaysFalse())

// A macro for testing Google Test assertions or code that's expected to
// generate Google Test non-fatal failures.  It asserts that the given
// statement will cause exactly one non-fatal Google Test failure with 'substr'
// being part of the failure message.
//
// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
// affects and considers failures generated in the current thread and
// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
//
// 'statement' is allowed to reference local variables and members of
// the current object.
//
// The verification of the assertion is done correctly even when the statement
// throws an exception or aborts the current function.
//
// Known restrictions:
//   - You cannot stream a failure message to this macro.
//
// Note that even though the implementations of the following two
// macros are much alike, we cannot refactor them to use a common
// helper macro, due to some peculiarity in how the preprocessor
// works.  If we do that, the code won't compile when the user gives
// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
// expands to code containing an unprotected comma.  The
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
// catches that.
//
// For the same reason, we have to write
//   if (::testing::internal::AlwaysTrue()) { statement; }
// instead of
//   GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
// to avoid an MSVC warning on unreachable code.
#define EXPECT_NONFATAL_FAILURE(statement, substr) \
  do {\
    ::testing::TestPartResultArray gtest_failures;\
    ::testing::internal::SingleFailureChecker gtest_checker(\
        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
        (substr));\
    {\
      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
          ::testing::ScopedFakeTestPartResultReporter:: \
          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
      if (::testing::internal::AlwaysTrue()) { statement; }\
    }\
  } while (::testing::internal::AlwaysFalse())

#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
  do {\
    ::testing::TestPartResultArray gtest_failures;\
    ::testing::internal::SingleFailureChecker gtest_checker(\
        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
        (substr));\
    {\
      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
          &gtest_failures);\
      if (::testing::internal::AlwaysTrue()) { statement; }\
    }\
  } while (::testing::internal::AlwaysFalse())

#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_

#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <wchar.h>
#include <wctype.h>

#include <algorithm>
#include <iomanip>
#include <limits>
#include <ostream>  // NOLINT
#include <sstream>
#include <vector>

#if GTEST_OS_LINUX

// TODO(kenton@google.com): Use autoconf to detect availability of
// gettimeofday().
# define GTEST_HAS_GETTIMEOFDAY_ 1

# include <fcntl.h>  // NOLINT
# include <limits.h>  // NOLINT
# include <sched.h>  // NOLINT
// Declares vsnprintf().  This header is not available on Windows.
# include <strings.h>  // NOLINT
# include <sys/mman.h>  // NOLINT
# include <sys/time.h>  // NOLINT
# include <unistd.h>  // NOLINT
# include <string>

#elif GTEST_OS_SYMBIAN
# define GTEST_HAS_GETTIMEOFDAY_ 1
# include <sys/time.h>  // NOLINT

#elif GTEST_OS_ZOS
# define GTEST_HAS_GETTIMEOFDAY_ 1
# include <sys/time.h>  // NOLINT

// On z/OS we additionally need strings.h for strcasecmp.
# include <strings.h>  // NOLINT

#elif GTEST_OS_WINDOWS_MOBILE  // We are on Windows CE.

# include <windows.h>  // NOLINT

#elif GTEST_OS_WINDOWS  // We are on Windows proper.

# include <io.h>  // NOLINT
# include <sys/timeb.h>  // NOLINT
# include <sys/types.h>  // NOLINT
# include <sys/stat.h>  // NOLINT

# if GTEST_OS_WINDOWS_MINGW
// MinGW has gettimeofday() but not _ftime64().
// TODO(kenton@google.com): Use autoconf to detect availability of
//   gettimeofday().
// TODO(kenton@google.com): There are other ways to get the time on
//   Windows, like GetTickCount() or GetSystemTimeAsFileTime().  MinGW
//   supports these.  consider using them instead.
#  define GTEST_HAS_GETTIMEOFDAY_ 1
#  include <sys/time.h>  // NOLINT
# endif  // GTEST_OS_WINDOWS_MINGW

// cpplint thinks that the header is already included, so we want to
// silence it.
# include <windows.h>  // NOLINT

#else

// Assume other platforms have gettimeofday().
// TODO(kenton@google.com): Use autoconf to detect availability of
//   gettimeofday().
# define GTEST_HAS_GETTIMEOFDAY_ 1

// cpplint thinks that the header is already included, so we want to
// silence it.
# include <sys/time.h>  // NOLINT
# include <unistd.h>  // NOLINT

#endif  // GTEST_OS_LINUX

#if GTEST_HAS_EXCEPTIONS
# include <stdexcept>
#endif

#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h>  // NOLINT
# include <netdb.h>  // NOLINT
#endif

// Indicates that this translation unit is part of Google Test's
// implementation.  It must come before gtest-internal-inl.h is
// included, or there will be a compiler error.  This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Utility functions and classes used by the Google C++ testing framework.
//
// Author: wan@google.com (Zhanyong Wan)
//
// This file contains purely Google Test's internal implementation.  Please
// DO NOT #INCLUDE IT IN A USER PROGRAM.

#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
#define GTEST_SRC_GTEST_INTERNAL_INL_H_

// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
// part of Google Test's implementation; otherwise it's undefined.
#if !GTEST_IMPLEMENTATION_
// A user is trying to include this from his code - just say no.
# error "gtest-internal-inl.h is part of Google Test's internal implementation."
# error "It must not be included except by Google Test itself."
#endif  // GTEST_IMPLEMENTATION_

#ifndef _WIN32_WCE
# include <errno.h>
#endif  // !_WIN32_WCE
#include <stddef.h>
#include <stdlib.h>  // For strtoll/_strtoul64/malloc/free.
#include <string.h>  // For memmove.

#include <algorithm>
#include <string>
#include <vector>


#if GTEST_CAN_STREAM_RESULTS_
# include <arpa/inet.h>  // NOLINT
# include <netdb.h>  // NOLINT
#endif

#if GTEST_OS_WINDOWS
# include <windows.h>  // NOLINT
#endif  // GTEST_OS_WINDOWS


namespace testing {

// Declares the flags.
//
// We don't want the users to modify this flag in the code, but want
// Google Test's own unit tests to be able to access it. Therefore we
// declare it here as opposed to in gtest.h.
GTEST_DECLARE_bool_(death_test_use_fork);

namespace internal {

// The value of GetTestTypeId() as seen from within the Google Test
// library.  This is solely for testing GetTestTypeId().
GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;

// Names of the flags (needed for parsing Google Test flags).
const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
const char kBreakOnFailureFlag[] = "break_on_failure";
const char kCatchExceptionsFlag[] = "catch_exceptions";
const char kColorFlag[] = "color";
const char kFilterFlag[] = "filter";
const char kListTestsFlag[] = "list_tests";
const char kOutputFlag[] = "output";
const char kPrintTimeFlag[] = "print_time";
const char kRandomSeedFlag[] = "random_seed";
const char kRepeatFlag[] = "repeat";
const char kShuffleFlag[] = "shuffle";
const char kStackTraceDepthFlag[] = "stack_trace_depth";
const char kStreamResultToFlag[] = "stream_result_to";
const char kThrowOnFailureFlag[] = "throw_on_failure";

// A valid random seed must be in [1, kMaxRandomSeed].
const int kMaxRandomSeed = 99999;

// g_help_flag is true iff the --help flag or an equivalent form is
// specified on the command line.
GTEST_API_ extern bool g_help_flag;

// Returns the current time in milliseconds.
GTEST_API_ TimeInMillis GetTimeInMillis();

// Returns true iff Google Test should use colors in the output.
GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);

// Formats the given time in milliseconds as seconds.
GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);

// Converts the given time in milliseconds to a date string in the ISO 8601
// format, without the timezone information.  N.B.: due to the use the
// non-reentrant localtime() function, this function is not thread safe.  Do
// not use it in any code that can be called from multiple threads.
GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);

// Parses a string for an Int32 flag, in the form of "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true.  On failure, returns false without changing *value.
GTEST_API_ bool ParseInt32Flag(
    const char* str, const char* flag, Int32* value);

// Returns a random seed in range [1, kMaxRandomSeed] based on the
// given --gtest_random_seed flag value.
inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
  const unsigned int raw_seed = (random_seed_flag == 0) ?
      static_cast<unsigned int>(GetTimeInMillis()) :
      static_cast<unsigned int>(random_seed_flag);

  // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
  // it's easy to type.
  const int normalized_seed =
      static_cast<int>((raw_seed - 1U) %
                       static_cast<unsigned int>(kMaxRandomSeed)) + 1;
  return normalized_seed;
}

// Returns the first valid random seed after 'seed'.  The behavior is
// undefined if 'seed' is invalid.  The seed after kMaxRandomSeed is
// considered to be 1.
inline int GetNextRandomSeed(int seed) {
  GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
      << "Invalid random seed " << seed << " - must be in [1, "
      << kMaxRandomSeed << "].";
  const int next_seed = seed + 1;
  return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
}

// This class saves the values of all Google Test flags in its c'tor, and
// restores them in its d'tor.
class GTestFlagSaver {
 public:
  // The c'tor.
  GTestFlagSaver() {
    also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
    break_on_failure_ = GTEST_FLAG(break_on_failure);
    catch_exceptions_ = GTEST_FLAG(catch_exceptions);
    color_ = GTEST_FLAG(color);
    death_test_style_ = GTEST_FLAG(death_test_style);
    death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
    filter_ = GTEST_FLAG(filter);
    internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
    list_tests_ = GTEST_FLAG(list_tests);
    output_ = GTEST_FLAG(output);
    print_time_ = GTEST_FLAG(print_time);
    random_seed_ = GTEST_FLAG(random_seed);
    repeat_ = GTEST_FLAG(repeat);
    shuffle_ = GTEST_FLAG(shuffle);
    stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
    stream_result_to_ = GTEST_FLAG(stream_result_to);
    throw_on_failure_ = GTEST_FLAG(throw_on_failure);
  }

  // The d'tor is not virtual.  DO NOT INHERIT FROM THIS CLASS.
  ~GTestFlagSaver() {
    GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
    GTEST_FLAG(break_on_failure) = break_on_failure_;
    GTEST_FLAG(catch_exceptions) = catch_exceptions_;
    GTEST_FLAG(color) = color_;
    GTEST_FLAG(death_test_style) = death_test_style_;
    GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
    GTEST_FLAG(filter) = filter_;
    GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
    GTEST_FLAG(list_tests) = list_tests_;
    GTEST_FLAG(output) = output_;
    GTEST_FLAG(print_time) = print_time_;
    GTEST_FLAG(random_seed) = random_seed_;
    GTEST_FLAG(repeat) = repeat_;
    GTEST_FLAG(shuffle) = shuffle_;
    GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
    GTEST_FLAG(stream_result_to) = stream_result_to_;
    GTEST_FLAG(throw_on_failure) = throw_on_failure_;
  }

 private:
  // Fields for saving the original values of flags.
  bool also_run_disabled_tests_;
  bool break_on_failure_;
  bool catch_exceptions_;
  std::string color_;
  std::string death_test_style_;
  bool death_test_use_fork_;
  std::string filter_;
  std::string internal_run_death_test_;
  bool list_tests_;
  std::string output_;
  bool print_time_;
  internal::Int32 random_seed_;
  internal::Int32 repeat_;
  bool shuffle_;
  internal::Int32 stack_trace_depth_;
  std::string stream_result_to_;
  bool throw_on_failure_;
} GTEST_ATTRIBUTE_UNUSED_;

// Converts a Unicode code point to a narrow string in UTF-8 encoding.
// code_point parameter is of type UInt32 because wchar_t may not be
// wide enough to contain a code point.
// If the code_point is not a valid Unicode code point
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
// to "(Invalid Unicode 0xXXXXXXXX)".
GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);

// Converts a wide string to a narrow string in UTF-8 encoding.
// The wide string is assumed to have the following encoding:
//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
// Parameter str points to a null-terminated wide string.
// Parameter num_chars may additionally limit the number
// of wchar_t characters processed. -1 is used when the entire string
// should be processed.
// If the string contains code points that are not valid Unicode code points
// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
// and contains invalid UTF-16 surrogate pairs, values in those pairs
// will be encoded as individual Unicode characters from Basic Normal Plane.
GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);

// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
// if the variable is present. If a file already exists at this location, this
// function will write over it. If the variable is present, but the file cannot
// be created, prints an error and exits.
void WriteToShardStatusFileIfNeeded();

// Checks whether sharding is enabled by examining the relevant
// environment variable values. If the variables are present,
// but inconsistent (e.g., shard_index >= total_shards), prints
// an error and exits. If in_subprocess_for_death_test, sharding is
// disabled because it must only be applied to the original test
// process. Otherwise, we could filter out death tests we intended to execute.
GTEST_API_ bool ShouldShard(const char* total_shards_str,
                            const char* shard_index_str,
                            bool in_subprocess_for_death_test);

// Parses the environment variable var as an Int32. If it is unset,
// returns default_val. If it is not an Int32, prints an error and
// and aborts.
GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);

// Given the total number of shards, the shard index, and the test id,
// returns true iff the test should be run on this shard. The test id is
// some arbitrary but unique non-negative integer assigned to each test
// method. Assumes that 0 <= shard_index < total_shards.
GTEST_API_ bool ShouldRunTestOnShard(
    int total_shards, int shard_index, int test_id);

// STL container utilities.

// Returns the number of elements in the given container that satisfy
// the given predicate.
template <class Container, typename Predicate>
inline int CountIf(const Container& c, Predicate predicate) {
  // Implemented as an explicit loop since std::count_if() in libCstd on
  // Solaris has a non-standard signature.
  int count = 0;
  for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
    if (predicate(*it))
      ++count;
  }
  return count;
}

// Applies a function/functor to each element in the container.
template <class Container, typename Functor>
void ForEach(const Container& c, Functor functor) {
  std::for_each(c.begin(), c.end(), functor);
}

// Returns the i-th element of the vector, or default_value if i is not
// in range [0, v.size()).
template <typename E>
inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
  return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
}

// Performs an in-place shuffle of a range of the vector's elements.
// 'begin' and 'end' are element indices as an STL-style range;
// i.e. [begin, end) are shuffled, where 'end' == size() means to
// shuffle to the end of the vector.
template <typename E>
void ShuffleRange(internal::Random* random, int begin, int end,
                  std::vector<E>* v) {
  const int size = static_cast<int>(v->size());
  GTEST_CHECK_(0 <= begin && begin <= size)
      << "Invalid shuffle range start " << begin << ": must be in range [0, "
      << size << "].";
  GTEST_CHECK_(begin <= end && end <= size)
      << "Invalid shuffle range finish " << end << ": must be in range ["
      << begin << ", " << size << "].";

  // Fisher-Yates shuffle, from
  // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
  for (int range_width = end - begin; range_width >= 2; range_width--) {
    const int last_in_range = begin + range_width - 1;
    const int selected = begin + random->Generate(range_width);
    std::swap((*v)[selected], (*v)[last_in_range]);
  }
}

// Performs an in-place shuffle of the vector's elements.
template <typename E>
inline void Shuffle(internal::Random* random, std::vector<E>* v) {
  ShuffleRange(random, 0, static_cast<int>(v->size()), v);
}

// A function for deleting an object.  Handy for being used as a
// functor.
template <typename T>
static void Delete(T* x) {
  delete x;
}

// A predicate that checks the key of a TestProperty against a known key.
//
// TestPropertyKeyIs is copyable.
class TestPropertyKeyIs {
 public:
  // Constructor.
  //
  // TestPropertyKeyIs has NO default constructor.
  explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}

  // Returns true iff the test name of test property matches on key_.
  bool operator()(const TestProperty& test_property) const {
    return test_property.key() == key_;
  }

 private:
  std::string key_;
};

// Class UnitTestOptions.
//
// This class contains functions for processing options the user
// specifies when running the tests.  It has only static members.
//
// In most cases, the user can specify an option using either an
// environment variable or a command line flag.  E.g. you can set the
// test filter using either GTEST_FILTER or --gtest_filter.  If both
// the variable and the flag are present, the latter overrides the
// former.
class GTEST_API_ UnitTestOptions {
 public:
  // Functions for processing the gtest_output flag.

  // Returns the output format, or "" for normal printed output.
  static std::string GetOutputFormat();

  // Returns the absolute path of the requested output file, or the
  // default (test_detail.xml in the original working directory) if
  // none was explicitly specified.
  static std::string GetAbsolutePathToOutputFile();

  // Functions for processing the gtest_filter flag.

  // Returns true iff the wildcard pattern matches the string.  The
  // first ':' or '\0' character in pattern marks the end of it.
  //
  // This recursive algorithm isn't very efficient, but is clear and
  // works well enough for matching test names, which are short.
  static bool PatternMatchesString(const char *pattern, const char *str);

  // Returns true iff the user-specified filter matches the test case
  // name and the test name.
  static bool FilterMatchesTest(const std::string &test_case_name,
                                const std::string &test_name);

#if GTEST_OS_WINDOWS
  // Function for supporting the gtest_catch_exception flag.

  // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
  // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
  // This function is useful as an __except condition.
  static int GTestShouldProcessSEH(DWORD exception_code);
#endif  // GTEST_OS_WINDOWS

  // Returns true if "name" matches the ':' separated list of glob-style
  // filters in "filter".
  static bool MatchesFilter(const std::string& name, const char* filter);
};

// Returns the current application's name, removing directory path if that
// is present.  Used by UnitTestOptions::GetOutputFile.
GTEST_API_ FilePath GetCurrentExecutableName();

// The role interface for getting the OS stack trace as a string.
class OsStackTraceGetterInterface {
 public:
  OsStackTraceGetterInterface() {}
  virtual ~OsStackTraceGetterInterface() {}

  // Returns the current OS stack trace as an std::string.  Parameters:
  //
  //   max_depth  - the maximum number of stack frames to be included
  //                in the trace.
  //   skip_count - the number of top frames to be skipped; doesn't count
  //                against max_depth.
  virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;

  // UponLeavingGTest() should be called immediately before Google Test calls
  // user code. It saves some information about the current stack that
  // CurrentStackTrace() will use to find and hide Google Test stack frames.
  virtual void UponLeavingGTest() = 0;

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
};

// A working implementation of the OsStackTraceGetterInterface interface.
class OsStackTraceGetter : public OsStackTraceGetterInterface {
 public:
  OsStackTraceGetter() : caller_frame_(NULL) {}

  virtual string CurrentStackTrace(int max_depth, int skip_count)
      GTEST_LOCK_EXCLUDED_(mutex_);

  virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);

  // This string is inserted in place of stack frames that are part of
  // Google Test's implementation.
  static const char* const kElidedFramesMarker;

 private:
  Mutex mutex_;  // protects all internal state

  // We save the stack frame below the frame that calls user code.
  // We do this because the address of the frame immediately below
  // the user code changes between the call to UponLeavingGTest()
  // and any calls to CurrentStackTrace() from within the user code.
  void* caller_frame_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
};

// Information about a Google Test trace point.
struct TraceInfo {
  const char* file;
  int line;
  std::string message;
};

// This is the default global test part result reporter used in UnitTestImpl.
// This class should only be used by UnitTestImpl.
class DefaultGlobalTestPartResultReporter
  : public TestPartResultReporterInterface {
 public:
  explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
  // Implements the TestPartResultReporterInterface. Reports the test part
  // result in the current test.
  virtual void ReportTestPartResult(const TestPartResult& result);

 private:
  UnitTestImpl* const unit_test_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
};

// This is the default per thread test part result reporter used in
// UnitTestImpl. This class should only be used by UnitTestImpl.
class DefaultPerThreadTestPartResultReporter
    : public TestPartResultReporterInterface {
 public:
  explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
  // Implements the TestPartResultReporterInterface. The implementation just
  // delegates to the current global test part result reporter of *unit_test_.
  virtual void ReportTestPartResult(const TestPartResult& result);

 private:
  UnitTestImpl* const unit_test_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
};

// The private implementation of the UnitTest class.  We don't protect
// the methods under a mutex, as this class is not accessible by a
// user and the UnitTest class that delegates work to this class does
// proper locking.
class GTEST_API_ UnitTestImpl {
 public:
  explicit UnitTestImpl(UnitTest* parent);
  virtual ~UnitTestImpl();

  // There are two different ways to register your own TestPartResultReporter.
  // You can register your own repoter to listen either only for test results
  // from the current thread or for results from all threads.
  // By default, each per-thread test result repoter just passes a new
  // TestPartResult to the global test result reporter, which registers the
  // test part result for the currently running test.

  // Returns the global test part result reporter.
  TestPartResultReporterInterface* GetGlobalTestPartResultReporter();

  // Sets the global test part result reporter.
  void SetGlobalTestPartResultReporter(
      TestPartResultReporterInterface* reporter);

  // Returns the test part result reporter for the current thread.
  TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();

  // Sets the test part result reporter for the current thread.
  void SetTestPartResultReporterForCurrentThread(
      TestPartResultReporterInterface* reporter);

  // Gets the number of successful test cases.
  int successful_test_case_count() const;

  // Gets the number of failed test cases.
  int failed_test_case_count() const;

  // Gets the number of all test cases.
  int total_test_case_count() const;

  // Gets the number of all test cases that contain at least one test
  // that should run.
  int test_case_to_run_count() const;

  // Gets the number of successful tests.
  int successful_test_count() const;

  // Gets the number of failed tests.
  int failed_test_count() const;

  // Gets the number of disabled tests that will be reported in the XML report.
  int reportable_disabled_test_count() const;

  // Gets the number of disabled tests.
  int disabled_test_count() const;

  // Gets the number of tests to be printed in the XML report.
  int reportable_test_count() const;

  // Gets the number of all tests.
  int total_test_count() const;

  // Gets the number of tests that should run.
  int test_to_run_count() const;

  // Gets the time of the test program start, in ms from the start of the
  // UNIX epoch.
  TimeInMillis start_timestamp() const { return start_timestamp_; }

  // Gets the elapsed time, in milliseconds.
  TimeInMillis elapsed_time() const { return elapsed_time_; }

  // Returns true iff the unit test passed (i.e. all test cases passed).
  bool Passed() const { return !Failed(); }

  // Returns true iff the unit test failed (i.e. some test case failed
  // or something outside of all tests failed).
  bool Failed() const {
    return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
  }

  // Gets the i-th test case among all the test cases. i can range from 0 to
  // total_test_case_count() - 1. If i is not in that range, returns NULL.
  const TestCase* GetTestCase(int i) const {
    const int index = GetElementOr(test_case_indices_, i, -1);
    return index < 0 ? NULL : test_cases_[i];
  }

  // Gets the i-th test case among all the test cases. i can range from 0 to
  // total_test_case_count() - 1. If i is not in that range, returns NULL.
  TestCase* GetMutableTestCase(int i) {
    const int index = GetElementOr(test_case_indices_, i, -1);
    return index < 0 ? NULL : test_cases_[index];
  }

  // Provides access to the event listener list.
  TestEventListeners* listeners() { return &listeners_; }

  // Returns the TestResult for the test that's currently running, or
  // the TestResult for the ad hoc test if no test is running.
  TestResult* current_test_result();

  // Returns the TestResult for the ad hoc test.
  const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }

  // Sets the OS stack trace getter.
  //
  // Does nothing if the input and the current OS stack trace getter
  // are the same; otherwise, deletes the old getter and makes the
  // input the current getter.
  void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);

  // Returns the current OS stack trace getter if it is not NULL;
  // otherwise, creates an OsStackTraceGetter, makes it the current
  // getter, and returns it.
  OsStackTraceGetterInterface* os_stack_trace_getter();

  // Returns the current OS stack trace as an std::string.
  //
  // The maximum number of stack frames to be included is specified by
  // the gtest_stack_trace_depth flag.  The skip_count parameter
  // specifies the number of top frames to be skipped, which doesn't
  // count against the number of frames to be included.
  //
  // For example, if Foo() calls Bar(), which in turn calls
  // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
  // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
  std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;

  // Finds and returns a TestCase with the given name.  If one doesn't
  // exist, creates one and returns it.
  //
  // Arguments:
  //
  //   test_case_name: name of the test case
  //   type_param:     the name of the test's type parameter, or NULL if
  //                   this is not a typed or a type-parameterized test.
  //   set_up_tc:      pointer to the function that sets up the test case
  //   tear_down_tc:   pointer to the function that tears down the test case
  TestCase* GetTestCase(const char* test_case_name,
                        const char* type_param,
                        Test::SetUpTestCaseFunc set_up_tc,
                        Test::TearDownTestCaseFunc tear_down_tc);

  // Adds a TestInfo to the unit test.
  //
  // Arguments:
  //
  //   set_up_tc:    pointer to the function that sets up the test case
  //   tear_down_tc: pointer to the function that tears down the test case
  //   test_info:    the TestInfo object
  void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
                   Test::TearDownTestCaseFunc tear_down_tc,
                   TestInfo* test_info) {
    // In order to support thread-safe death tests, we need to
    // remember the original working directory when the test program
    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
    // the user may have changed the current directory before calling
    // RUN_ALL_TESTS().  Therefore we capture the current directory in
    // AddTestInfo(), which is called to register a TEST or TEST_F
    // before main() is reached.
    if (original_working_dir_.IsEmpty()) {
      original_working_dir_.Set(FilePath::GetCurrentDir());
      GTEST_CHECK_(!original_working_dir_.IsEmpty())
          << "Failed to get the current working directory.";
    }

    GetTestCase(test_info->test_case_name(),
                test_info->type_param(),
                set_up_tc,
                tear_down_tc)->AddTestInfo(test_info);
  }

#if GTEST_HAS_PARAM_TEST
  // Returns ParameterizedTestCaseRegistry object used to keep track of
  // value-parameterized tests and instantiate and register them.
  internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
    return parameterized_test_registry_;
  }
#endif  // GTEST_HAS_PARAM_TEST

  // Sets the TestCase object for the test that's currently running.
  void set_current_test_case(TestCase* a_current_test_case) {
    current_test_case_ = a_current_test_case;
  }

  // Sets the TestInfo object for the test that's currently running.  If
  // current_test_info is NULL, the assertion results will be stored in
  // ad_hoc_test_result_.
  void set_current_test_info(TestInfo* a_current_test_info) {
    current_test_info_ = a_current_test_info;
  }

  // Registers all parameterized tests defined using TEST_P and
  // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
  // combination. This method can be called more then once; it has guards
  // protecting from registering the tests more then once.  If
  // value-parameterized tests are disabled, RegisterParameterizedTests is
  // present but does nothing.
  void RegisterParameterizedTests();

  // Runs all tests in this UnitTest object, prints the result, and
  // returns true if all tests are successful.  If any exception is
  // thrown during a test, this test is considered to be failed, but
  // the rest of the tests will still be run.
  bool RunAllTests();

  // Clears the results of all tests, except the ad hoc tests.
  void ClearNonAdHocTestResult() {
    ForEach(test_cases_, TestCase::ClearTestCaseResult);
  }

  // Clears the results of ad-hoc test assertions.
  void ClearAdHocTestResult() {
    ad_hoc_test_result_.Clear();
  }

  // Adds a TestProperty to the current TestResult object when invoked in a
  // context of a test or a test case, or to the global property set. If the
  // result already contains a property with the same key, the value will be
  // updated.
  void RecordProperty(const TestProperty& test_property);

  enum ReactionToSharding {
    HONOR_SHARDING_PROTOCOL,
    IGNORE_SHARDING_PROTOCOL
  };

  // Matches the full name of each test against the user-specified
  // filter to decide whether the test should run, then records the
  // result in each TestCase and TestInfo object.
  // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
  // based on sharding variables in the environment.
  // Returns the number of tests that should run.
  int FilterTests(ReactionToSharding shard_tests);

  // Prints the names of the tests matching the user-specified filter flag.
  void ListTestsMatchingFilter();

  const TestCase* current_test_case() const { return current_test_case_; }
  TestInfo* current_test_info() { return current_test_info_; }
  const TestInfo* current_test_info() const { return current_test_info_; }

  // Returns the vector of environments that need to be set-up/torn-down
  // before/after the tests are run.
  std::vector<Environment*>& environments() { return environments_; }

  // Getters for the per-thread Google Test trace stack.
  std::vector<TraceInfo>& gtest_trace_stack() {
    return *(gtest_trace_stack_.pointer());
  }
  const std::vector<TraceInfo>& gtest_trace_stack() const {
    return gtest_trace_stack_.get();
  }

#if GTEST_HAS_DEATH_TEST
  void InitDeathTestSubprocessControlInfo() {
    internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
  }
  // Returns a pointer to the parsed --gtest_internal_run_death_test
  // flag, or NULL if that flag was not specified.
  // This information is useful only in a death test child process.
  // Must not be called before a call to InitGoogleTest.
  const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
    return internal_run_death_test_flag_.get();
  }

  // Returns a pointer to the current death test factory.
  internal::DeathTestFactory* death_test_factory() {
    return death_test_factory_.get();
  }

  void SuppressTestEventsIfInSubprocess();

  friend class ReplaceDeathTestFactory;
#endif  // GTEST_HAS_DEATH_TEST

  // Initializes the event listener performing XML output as specified by
  // UnitTestOptions. Must not be called before InitGoogleTest.
  void ConfigureXmlOutput();

#if GTEST_CAN_STREAM_RESULTS_
  // Initializes the event listener for streaming test results to a socket.
  // Must not be called before InitGoogleTest.
  void ConfigureStreamingOutput();
#endif

  // Performs initialization dependent upon flag values obtained in
  // ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
  // ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
  // this function is also called from RunAllTests.  Since this function can be
  // called more than once, it has to be idempotent.
  void PostFlagParsingInit();

  // Gets the random seed used at the start of the current test iteration.
  int random_seed() const { return random_seed_; }

  // Gets the random number generator.
  internal::Random* random() { return &random_; }

  // Shuffles all test cases, and the tests within each test case,
  // making sure that death tests are still run first.
  void ShuffleTests();

  // Restores the test cases and tests to their order before the first shuffle.
  void UnshuffleTests();

  // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
  // UnitTest::Run() starts.
  bool catch_exceptions() const { return catch_exceptions_; }

 private:
  friend class ::testing::UnitTest;

  // Used by UnitTest::Run() to capture the state of
  // GTEST_FLAG(catch_exceptions) at the moment it starts.
  void set_catch_exceptions(bool value) { catch_exceptions_ = value; }

  // The UnitTest object that owns this implementation object.
  UnitTest* const parent_;

  // The working directory when the first TEST() or TEST_F() was
  // executed.
  internal::FilePath original_working_dir_;

  // The default test part result reporters.
  DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
  DefaultPerThreadTestPartResultReporter
      default_per_thread_test_part_result_reporter_;

  // Points to (but doesn't own) the global test part result reporter.
  TestPartResultReporterInterface* global_test_part_result_repoter_;

  // Protects read and write access to global_test_part_result_reporter_.
  internal::Mutex global_test_part_result_reporter_mutex_;

  // Points to (but doesn't own) the per-thread test part result reporter.
  internal::ThreadLocal<TestPartResultReporterInterface*>
      per_thread_test_part_result_reporter_;

  // The vector of environments that need to be set-up/torn-down
  // before/after the tests are run.
  std::vector<Environment*> environments_;

  // The vector of TestCases in their original order.  It owns the
  // elements in the vector.
  std::vector<TestCase*> test_cases_;

  // Provides a level of indirection for the test case list to allow
  // easy shuffling and restoring the test case order.  The i-th
  // element of this vector is the index of the i-th test case in the
  // shuffled order.
  std::vector<int> test_case_indices_;

#if GTEST_HAS_PARAM_TEST
  // ParameterizedTestRegistry object used to register value-parameterized
  // tests.
  internal::ParameterizedTestCaseRegistry parameterized_test_registry_;

  // Indicates whether RegisterParameterizedTests() has been called already.
  bool parameterized_tests_registered_;
#endif  // GTEST_HAS_PARAM_TEST

  // Index of the last death test case registered.  Initially -1.
  int last_death_test_case_;

  // This points to the TestCase for the currently running test.  It
  // changes as Google Test goes through one test case after another.
  // When no test is running, this is set to NULL and Google Test
  // stores assertion results in ad_hoc_test_result_.  Initially NULL.
  TestCase* current_test_case_;

  // This points to the TestInfo for the currently running test.  It
  // changes as Google Test goes through one test after another.  When
  // no test is running, this is set to NULL and Google Test stores
  // assertion results in ad_hoc_test_result_.  Initially NULL.
  TestInfo* current_test_info_;

  // Normally, a user only writes assertions inside a TEST or TEST_F,
  // or inside a function called by a TEST or TEST_F.  Since Google
  // Test keeps track of which test is current running, it can
  // associate such an assertion with the test it belongs to.
  //
  // If an assertion is encountered when no TEST or TEST_F is running,
  // Google Test attributes the assertion result to an imaginary "ad hoc"
  // test, and records the result in ad_hoc_test_result_.
  TestResult ad_hoc_test_result_;

  // The list of event listeners that can be used to track events inside
  // Google Test.
  TestEventListeners listeners_;

  // The OS stack trace getter.  Will be deleted when the UnitTest
  // object is destructed.  By default, an OsStackTraceGetter is used,
  // but the user can set this field to use a custom getter if that is
  // desired.
  OsStackTraceGetterInterface* os_stack_trace_getter_;

  // True iff PostFlagParsingInit() has been called.
  bool post_flag_parse_init_performed_;

  // The random number seed used at the beginning of the test run.
  int random_seed_;

  // Our random number generator.
  internal::Random random_;

  // The time of the test program start, in ms from the start of the
  // UNIX epoch.
  TimeInMillis start_timestamp_;

  // How long the test took to run, in milliseconds.
  TimeInMillis elapsed_time_;

#if GTEST_HAS_DEATH_TEST
  // The decomposed components of the gtest_internal_run_death_test flag,
  // parsed when RUN_ALL_TESTS is called.
  internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
  internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
#endif  // GTEST_HAS_DEATH_TEST

  // A per-thread stack of traces created by the SCOPED_TRACE() macro.
  internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;

  // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
  // starts.
  bool catch_exceptions_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
};  // class UnitTestImpl

// Convenience function for accessing the global UnitTest
// implementation object.
inline UnitTestImpl* GetUnitTestImpl() {
  return UnitTest::GetInstance()->impl();
}

#if GTEST_USES_SIMPLE_RE

// Internal helper functions for implementing the simple regular
// expression matcher.
GTEST_API_ bool IsInSet(char ch, const char* str);
GTEST_API_ bool IsAsciiDigit(char ch);
GTEST_API_ bool IsAsciiPunct(char ch);
GTEST_API_ bool IsRepeat(char ch);
GTEST_API_ bool IsAsciiWhiteSpace(char ch);
GTEST_API_ bool IsAsciiWordChar(char ch);
GTEST_API_ bool IsValidEscape(char ch);
GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
GTEST_API_ bool ValidateRegex(const char* regex);
GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
GTEST_API_ bool MatchRepetitionAndRegexAtHead(
    bool escaped, char ch, char repeat, const char* regex, const char* str);
GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);

#endif  // GTEST_USES_SIMPLE_RE

// Parses the command line for Google Test flags, without initializing
// other parts of Google Test.
GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);

#if GTEST_HAS_DEATH_TEST

// Returns the message describing the last system error, regardless of the
// platform.
GTEST_API_ std::string GetLastErrnoDescription();

# if GTEST_OS_WINDOWS
// Provides leak-safe Windows kernel handle ownership.
class AutoHandle {
 public:
  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
  explicit AutoHandle(HANDLE handle) : handle_(handle) {}

  ~AutoHandle() { Reset(); }

  HANDLE Get() const { return handle_; }
  void Reset() { Reset(INVALID_HANDLE_VALUE); }
  void Reset(HANDLE handle) {
    if (handle != handle_) {
      if (handle_ != INVALID_HANDLE_VALUE)
        ::CloseHandle(handle_);
      handle_ = handle;
    }
  }

 private:
  HANDLE handle_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
};
# endif  // GTEST_OS_WINDOWS

// Attempts to parse a string into a positive integer pointed to by the
// number parameter.  Returns true if that is possible.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
// it here.
template <typename Integer>
bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
  // Fail fast if the given string does not begin with a digit;
  // this bypasses strtoXXX's "optional leading whitespace and plus
  // or minus sign" semantics, which are undesirable here.
  if (str.empty() || !IsDigit(str[0])) {
    return false;
  }
  errno = 0;

  char* end;
  // BiggestConvertible is the largest integer type that system-provided
  // string-to-number conversion routines can return.

# if GTEST_OS_WINDOWS && !defined(__GNUC__)

  // MSVC and C++ Builder define __int64 instead of the standard long long.
  typedef unsigned __int64 BiggestConvertible;
  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);

# else

  typedef unsigned long long BiggestConvertible;  // NOLINT
  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);

# endif  // GTEST_OS_WINDOWS && !defined(__GNUC__)

  const bool parse_success = *end == '\0' && errno == 0;

  // TODO(vladl@google.com): Convert this to compile time assertion when it is
  // available.
  GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));

  const Integer result = static_cast<Integer>(parsed);
  if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
    *number = result;
    return true;
  }
  return false;
}
#endif  // GTEST_HAS_DEATH_TEST

// TestResult contains some private methods that should be hidden from
// Google Test user but are required for testing. This class allow our tests
// to access them.
//
// This class is supplied only for the purpose of testing Google Test's own
// constructs. Do not use it in user tests, either directly or indirectly.
class TestResultAccessor {
 public:
  static void RecordProperty(TestResult* test_result,
                             const std::string& xml_element,
                             const TestProperty& property) {
    test_result->RecordProperty(xml_element, property);
  }

  static void ClearTestPartResults(TestResult* test_result) {
    test_result->ClearTestPartResults();
  }

  static const std::vector<testing::TestPartResult>& test_part_results(
      const TestResult& test_result) {
    return test_result.test_part_results();
  }
};

#if GTEST_CAN_STREAM_RESULTS_

// Streams test results to the given port on the given host machine.
class StreamingListener : public EmptyTestEventListener {
 public:
  // Abstract base class for writing strings to a socket.
  class AbstractSocketWriter {
   public:
    virtual ~AbstractSocketWriter() {}

    // Sends a string to the socket.
    virtual void Send(const string& message) = 0;

    // Closes the socket.
    virtual void CloseConnection() {}

    // Sends a string and a newline to the socket.
    void SendLn(const string& message) {
      Send(message + "\n");
    }
  };

  // Concrete class for actually writing strings to a socket.
  class SocketWriter : public AbstractSocketWriter {
   public:
    SocketWriter(const string& host, const string& port)
        : sockfd_(-1), host_name_(host), port_num_(port) {
      MakeConnection();
    }

    virtual ~SocketWriter() {
      if (sockfd_ != -1)
        CloseConnection();
    }

    // Sends a string to the socket.
    virtual void Send(const string& message) {
      GTEST_CHECK_(sockfd_ != -1)
          << "Send() can be called only when there is a connection.";

      const int len = static_cast<int>(message.length());
      if (write(sockfd_, message.c_str(), len) != len) {
        GTEST_LOG_(WARNING)
            << "stream_result_to: failed to stream to "
            << host_name_ << ":" << port_num_;
      }
    }

   private:
    // Creates a client socket and connects to the server.
    void MakeConnection();

    // Closes the socket.
    void CloseConnection() {
      GTEST_CHECK_(sockfd_ != -1)
          << "CloseConnection() can be called only when there is a connection.";

      close(sockfd_);
      sockfd_ = -1;
    }

    int sockfd_;  // socket file descriptor
    const string host_name_;
    const string port_num_;

    GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
  };  // class SocketWriter

  // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
  static string UrlEncode(const char* str);

  StreamingListener(const string& host, const string& port)
      : socket_writer_(new SocketWriter(host, port)) { Start(); }

  explicit StreamingListener(AbstractSocketWriter* socket_writer)
      : socket_writer_(socket_writer) { Start(); }

  void OnTestProgramStart(const UnitTest& /* unit_test */) {
    SendLn("event=TestProgramStart");
  }

  void OnTestProgramEnd(const UnitTest& unit_test) {
    // Note that Google Test current only report elapsed time for each
    // test iteration, not for the entire test program.
    SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));

    // Notify the streaming server to stop.
    socket_writer_->CloseConnection();
  }

  void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
    SendLn("event=TestIterationStart&iteration=" +
           StreamableToString(iteration));
  }

  void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
    SendLn("event=TestIterationEnd&passed=" +
           FormatBool(unit_test.Passed()) + "&elapsed_time=" +
           StreamableToString(unit_test.elapsed_time()) + "ms");
  }

  void OnTestCaseStart(const TestCase& test_case) {
    SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
  }

  void OnTestCaseEnd(const TestCase& test_case) {
    SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
           + "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
           + "ms");
  }

  void OnTestStart(const TestInfo& test_info) {
    SendLn(std::string("event=TestStart&name=") + test_info.name());
  }

  void OnTestEnd(const TestInfo& test_info) {
    SendLn("event=TestEnd&passed=" +
           FormatBool((test_info.result())->Passed()) +
           "&elapsed_time=" +
           StreamableToString((test_info.result())->elapsed_time()) + "ms");
  }

  void OnTestPartResult(const TestPartResult& test_part_result) {
    const char* file_name = test_part_result.file_name();
    if (file_name == NULL)
      file_name = "";
    SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
           "&line=" + StreamableToString(test_part_result.line_number()) +
           "&message=" + UrlEncode(test_part_result.message()));
  }

 private:
  // Sends the given message and a newline to the socket.
  void SendLn(const string& message) { socket_writer_->SendLn(message); }

  // Called at the start of streaming to notify the receiver what
  // protocol we are using.
  void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }

  string FormatBool(bool value) { return value ? "1" : "0"; }

  const scoped_ptr<AbstractSocketWriter> socket_writer_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
};  // class StreamingListener

#endif  // GTEST_CAN_STREAM_RESULTS_

}  // namespace internal
}  // namespace testing

#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_
#undef GTEST_IMPLEMENTATION_

#if GTEST_OS_WINDOWS
# define vsnprintf _vsnprintf
#endif  // GTEST_OS_WINDOWS

namespace testing {

using internal::CountIf;
using internal::ForEach;
using internal::GetElementOr;
using internal::Shuffle;

// Constants.

// A test whose test case name or test name matches this filter is
// disabled and not run.
static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";

// A test case whose name matches this filter is considered a death
// test case and will be run before test cases whose name doesn't
// match this filter.
static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";

// A test filter that matches everything.
static const char kUniversalFilter[] = "*";

// The default output file for XML output.
static const char kDefaultOutputFile[] = "test_detail.xml";

// The environment variable name for the test shard index.
static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
// The environment variable name for the total number of test shards.
static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
// The environment variable name for the test shard status file.
static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";

namespace internal {

// The text used in failure messages to indicate the start of the
// stack trace.
const char kStackTraceMarker[] = "\nStack trace:\n";

// g_help_flag is true iff the --help flag or an equivalent form is
// specified on the command line.
bool g_help_flag = false;

}  // namespace internal

static const char* GetDefaultFilter() {
  return kUniversalFilter;
}

GTEST_DEFINE_bool_(
    also_run_disabled_tests,
    internal::BoolFromGTestEnv("also_run_disabled_tests", false),
    "Run disabled tests too, in addition to the tests normally being run.");

GTEST_DEFINE_bool_(
    break_on_failure,
    internal::BoolFromGTestEnv("break_on_failure", false),
    "True iff a failed assertion should be a debugger break-point.");

GTEST_DEFINE_bool_(
    catch_exceptions,
    internal::BoolFromGTestEnv("catch_exceptions", true),
    "True iff " GTEST_NAME_
    " should catch exceptions and treat them as test failures.");

GTEST_DEFINE_string_(
    color,
    internal::StringFromGTestEnv("color", "auto"),
    "Whether to use colors in the output.  Valid values: yes, no, "
    "and auto.  'auto' means to use colors if the output is "
    "being sent to a terminal and the TERM environment variable "
    "is set to a terminal type that supports colors.");

GTEST_DEFINE_string_(
    filter,
    internal::StringFromGTestEnv("filter", GetDefaultFilter()),
    "A colon-separated list of glob (not regex) patterns "
    "for filtering the tests to run, optionally followed by a "
    "'-' and a : separated list of negative patterns (tests to "
    "exclude).  A test is run if it matches one of the positive "
    "patterns and does not match any of the negative patterns.");

GTEST_DEFINE_bool_(list_tests, false,
                   "List all tests without running them.");

GTEST_DEFINE_string_(
    output,
    internal::StringFromGTestEnv("output", ""),
    "A format (currently must be \"xml\"), optionally followed "
    "by a colon and an output file name or directory. A directory "
    "is indicated by a trailing pathname separator. "
    "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
    "If a directory is specified, output files will be created "
    "within that directory, with file-names based on the test "
    "executable's name and, if necessary, made unique by adding "
    "digits.");

GTEST_DEFINE_bool_(
    print_time,
    internal::BoolFromGTestEnv("print_time", true),
    "True iff " GTEST_NAME_
    " should display elapsed time in text output.");

GTEST_DEFINE_int32_(
    random_seed,
    internal::Int32FromGTestEnv("random_seed", 0),
    "Random number seed to use when shuffling test orders.  Must be in range "
    "[1, 99999], or 0 to use a seed based on the current time.");

GTEST_DEFINE_int32_(
    repeat,
    internal::Int32FromGTestEnv("repeat", 1),
    "How many times to repeat each test.  Specify a negative number "
    "for repeating forever.  Useful for shaking out flaky tests.");

GTEST_DEFINE_bool_(
    show_internal_stack_frames, false,
    "True iff " GTEST_NAME_ " should include internal stack frames when "
    "printing test failure stack traces.");

GTEST_DEFINE_bool_(
    shuffle,
    internal::BoolFromGTestEnv("shuffle", false),
    "True iff " GTEST_NAME_
    " should randomize tests' order on every run.");

GTEST_DEFINE_int32_(
    stack_trace_depth,
    internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
    "The maximum number of stack frames to print when an "
    "assertion fails.  The valid range is 0 through 100, inclusive.");

GTEST_DEFINE_string_(
    stream_result_to,
    internal::StringFromGTestEnv("stream_result_to", ""),
    "This flag specifies the host name and the port number on which to stream "
    "test results. Example: \"localhost:555\". The flag is effective only on "
    "Linux.");

GTEST_DEFINE_bool_(
    throw_on_failure,
    internal::BoolFromGTestEnv("throw_on_failure", false),
    "When this flag is specified, a failed assertion will throw an exception "
    "if exceptions are enabled or exit the program with a non-zero code "
    "otherwise.");

namespace internal {

// Generates a random number from [0, range), using a Linear
// Congruential Generator (LCG).  Crashes if 'range' is 0 or greater
// than kMaxRange.
UInt32 Random::Generate(UInt32 range) {
  // These constants are the same as are used in glibc's rand(3).
  state_ = (1103515245U*state_ + 12345U) % kMaxRange;

  GTEST_CHECK_(range > 0)
      << "Cannot generate a number in the range [0, 0).";
  GTEST_CHECK_(range <= kMaxRange)
      << "Generation of a number in [0, " << range << ") was requested, "
      << "but this can only generate numbers in [0, " << kMaxRange << ").";

  // Converting via modulus introduces a bit of downward bias, but
  // it's simple, and a linear congruential generator isn't too good
  // to begin with.
  return state_ % range;
}

// GTestIsInitialized() returns true iff the user has initialized
// Google Test.  Useful for catching the user mistake of not initializing
// Google Test before calling RUN_ALL_TESTS().
//
// A user must call testing::InitGoogleTest() to initialize Google
// Test.  g_init_gtest_count is set to the number of times
// InitGoogleTest() has been called.  We don't protect this variable
// under a mutex as it is only accessed in the main thread.
GTEST_API_ int g_init_gtest_count = 0;
static bool GTestIsInitialized() { return g_init_gtest_count != 0; }

// Iterates over a vector of TestCases, keeping a running sum of the
// results of calling a given int-returning method on each.
// Returns the sum.
static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
                               int (TestCase::*method)() const) {
  int sum = 0;
  for (size_t i = 0; i < case_list.size(); i++) {
    sum += (case_list[i]->*method)();
  }
  return sum;
}

// Returns true iff the test case passed.
static bool TestCasePassed(const TestCase* test_case) {
  return test_case->should_run() && test_case->Passed();
}

// Returns true iff the test case failed.
static bool TestCaseFailed(const TestCase* test_case) {
  return test_case->should_run() && test_case->Failed();
}

// Returns true iff test_case contains at least one test that should
// run.
static bool ShouldRunTestCase(const TestCase* test_case) {
  return test_case->should_run();
}

// AssertHelper constructor.
AssertHelper::AssertHelper(TestPartResult::Type type,
                           const char* file,
                           int line,
                           const char* message)
    : data_(new AssertHelperData(type, file, line, message)) {
}

AssertHelper::~AssertHelper() {
  delete data_;
}

// Message assignment, for assertion streaming support.
void AssertHelper::operator=(const Message& message) const {
  UnitTest::GetInstance()->
    AddTestPartResult(data_->type, data_->file, data_->line,
                      AppendUserMessage(data_->message, message),
                      UnitTest::GetInstance()->impl()
                      ->CurrentOsStackTraceExceptTop(1)
                      // Skips the stack frame for this function itself.
                      );  // NOLINT
}

// Mutex for linked pointers.
GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);

// Application pathname gotten in InitGoogleTest.
std::string g_executable_path;

// Returns the current application's name, removing directory path if that
// is present.
FilePath GetCurrentExecutableName() {
  FilePath result;

#if GTEST_OS_WINDOWS
  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
#else
  result.Set(FilePath(g_executable_path));
#endif  // GTEST_OS_WINDOWS

  return result.RemoveDirectoryName();
}

// Functions for processing the gtest_output flag.

// Returns the output format, or "" for normal printed output.
std::string UnitTestOptions::GetOutputFormat() {
  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
  if (gtest_output_flag == NULL) return std::string("");

  const char* const colon = strchr(gtest_output_flag, ':');
  return (colon == NULL) ?
      std::string(gtest_output_flag) :
      std::string(gtest_output_flag, colon - gtest_output_flag);
}

// Returns the name of the requested output file, or the default if none
// was explicitly specified.
std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
  if (gtest_output_flag == NULL)
    return "";

  const char* const colon = strchr(gtest_output_flag, ':');
  if (colon == NULL)
    return internal::FilePath::ConcatPaths(
        internal::FilePath(
            UnitTest::GetInstance()->original_working_dir()),
        internal::FilePath(kDefaultOutputFile)).string();

  internal::FilePath output_name(colon + 1);
  if (!output_name.IsAbsolutePath())
    // TODO(wan@google.com): on Windows \some\path is not an absolute
    // path (as its meaning depends on the current drive), yet the
    // following logic for turning it into an absolute path is wrong.
    // Fix it.
    output_name = internal::FilePath::ConcatPaths(
        internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
        internal::FilePath(colon + 1));

  if (!output_name.IsDirectory())
    return output_name.string();

  internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
      output_name, internal::GetCurrentExecutableName(),
      GetOutputFormat().c_str()));
  return result.string();
}

// Returns true iff the wildcard pattern matches the string.  The
// first ':' or '\0' character in pattern marks the end of it.
//
// This recursive algorithm isn't very efficient, but is clear and
// works well enough for matching test names, which are short.
bool UnitTestOptions::PatternMatchesString(const char *pattern,
                                           const char *str) {
  switch (*pattern) {
    case '\0':
    case ':':  // Either ':' or '\0' marks the end of the pattern.
      return *str == '\0';
    case '?':  // Matches any single character.
      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
    case '*':  // Matches any string (possibly empty) of characters.
      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
          PatternMatchesString(pattern + 1, str);
    default:  // Non-special character.  Matches itself.
      return *pattern == *str &&
          PatternMatchesString(pattern + 1, str + 1);
  }
}

bool UnitTestOptions::MatchesFilter(
    const std::string& name, const char* filter) {
  const char *cur_pattern = filter;
  for (;;) {
    if (PatternMatchesString(cur_pattern, name.c_str())) {
      return true;
    }

    // Finds the next pattern in the filter.
    cur_pattern = strchr(cur_pattern, ':');

    // Returns if no more pattern can be found.
    if (cur_pattern == NULL) {
      return false;
    }

    // Skips the pattern separater (the ':' character).
    cur_pattern++;
  }
}

// Returns true iff the user-specified filter matches the test case
// name and the test name.
bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name,
                                        const std::string &test_name) {
  const std::string& full_name = test_case_name + "." + test_name.c_str();

  // Split --gtest_filter at '-', if there is one, to separate into
  // positive filter and negative filter portions
  const char* const p = GTEST_FLAG(filter).c_str();
  const char* const dash = strchr(p, '-');
  std::string positive;
  std::string negative;
  if (dash == NULL) {
    positive = GTEST_FLAG(filter).c_str();  // Whole string is a positive filter
    negative = "";
  } else {
    positive = std::string(p, dash);   // Everything up to the dash
    negative = std::string(dash + 1);  // Everything after the dash
    if (positive.empty()) {
      // Treat '-test1' as the same as '*-test1'
      positive = kUniversalFilter;
    }
  }

  // A filter is a colon-separated list of patterns.  It matches a
  // test if any pattern in it matches the test.
  return (MatchesFilter(full_name, positive.c_str()) &&
          !MatchesFilter(full_name, negative.c_str()));
}

#if GTEST_HAS_SEH
// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
// This function is useful as an __except condition.
int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
  // Google Test should handle a SEH exception if:
  //   1. the user wants it to, AND
  //   2. this is not a breakpoint exception, AND
  //   3. this is not a C++ exception (VC++ implements them via SEH,
  //      apparently).
  //
  // SEH exception code for C++ exceptions.
  // (see http://support.microsoft.com/kb/185294 for more information).
  const DWORD kCxxExceptionCode = 0xe06d7363;

  bool should_handle = true;

  if (!GTEST_FLAG(catch_exceptions))
    should_handle = false;
  else if (exception_code == EXCEPTION_BREAKPOINT)
    should_handle = false;
  else if (exception_code == kCxxExceptionCode)
    should_handle = false;

  return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
}
#endif  // GTEST_HAS_SEH

}  // namespace internal

// The c'tor sets this object as the test part result reporter used by
// Google Test.  The 'result' parameter specifies where to report the
// results. Intercepts only failures from the current thread.
ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
    TestPartResultArray* result)
    : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
      result_(result) {
  Init();
}

// The c'tor sets this object as the test part result reporter used by
// Google Test.  The 'result' parameter specifies where to report the
// results.
ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
    InterceptMode intercept_mode, TestPartResultArray* result)
    : intercept_mode_(intercept_mode),
      result_(result) {
  Init();
}

void ScopedFakeTestPartResultReporter::Init() {
  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
    old_reporter_ = impl->GetGlobalTestPartResultReporter();
    impl->SetGlobalTestPartResultReporter(this);
  } else {
    old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
    impl->SetTestPartResultReporterForCurrentThread(this);
  }
}

// The d'tor restores the test part result reporter used by Google Test
// before.
ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
    impl->SetGlobalTestPartResultReporter(old_reporter_);
  } else {
    impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
  }
}

// Increments the test part result count and remembers the result.
// This method is from the TestPartResultReporterInterface interface.
void ScopedFakeTestPartResultReporter::ReportTestPartResult(
    const TestPartResult& result) {
  result_->Append(result);
}

namespace internal {

// Returns the type ID of ::testing::Test.  We should always call this
// instead of GetTypeId< ::testing::Test>() to get the type ID of
// testing::Test.  This is to work around a suspected linker bug when
// using Google Test as a framework on Mac OS X.  The bug causes
// GetTypeId< ::testing::Test>() to return different values depending
// on whether the call is from the Google Test framework itself or
// from user test code.  GetTestTypeId() is guaranteed to always
// return the same value, as it always calls GetTypeId<>() from the
// gtest.cc, which is within the Google Test framework.
TypeId GetTestTypeId() {
  return GetTypeId<Test>();
}

// The value of GetTestTypeId() as seen from within the Google Test
// library.  This is solely for testing GetTestTypeId().
extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();

// This predicate-formatter checks that 'results' contains a test part
// failure of the given type and that the failure message contains the
// given substring.
AssertionResult HasOneFailure(const char* /* results_expr */,
                              const char* /* type_expr */,
                              const char* /* substr_expr */,
                              const TestPartResultArray& results,
                              TestPartResult::Type type,
                              const string& substr) {
  const std::string expected(type == TestPartResult::kFatalFailure ?
                        "1 fatal failure" :
                        "1 non-fatal failure");
  Message msg;
  if (results.size() != 1) {
    msg << "Expected: " << expected << "\n"
        << "  Actual: " << results.size() << " failures";
    for (int i = 0; i < results.size(); i++) {
      msg << "\n" << results.GetTestPartResult(i);
    }
    return AssertionFailure() << msg;
  }

  const TestPartResult& r = results.GetTestPartResult(0);
  if (r.type() != type) {
    return AssertionFailure() << "Expected: " << expected << "\n"
                              << "  Actual:\n"
                              << r;
  }

  if (strstr(r.message(), substr.c_str()) == NULL) {
    return AssertionFailure() << "Expected: " << expected << " containing \""
                              << substr << "\"\n"
                              << "  Actual:\n"
                              << r;
  }

  return AssertionSuccess();
}

// The constructor of SingleFailureChecker remembers where to look up
// test part results, what type of failure we expect, and what
// substring the failure message should contain.
SingleFailureChecker:: SingleFailureChecker(
    const TestPartResultArray* results,
    TestPartResult::Type type,
    const string& substr)
    : results_(results),
      type_(type),
      substr_(substr) {}

// The destructor of SingleFailureChecker verifies that the given
// TestPartResultArray contains exactly one failure that has the given
// type and contains the given substring.  If that's not the case, a
// non-fatal failure will be generated.
SingleFailureChecker::~SingleFailureChecker() {
  EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
}

DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
    UnitTestImpl* unit_test) : unit_test_(unit_test) {}

void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
    const TestPartResult& result) {
  unit_test_->current_test_result()->AddTestPartResult(result);
  unit_test_->listeners()->repeater()->OnTestPartResult(result);
}

DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
    UnitTestImpl* unit_test) : unit_test_(unit_test) {}

void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
    const TestPartResult& result) {
  unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
}

// Returns the global test part result reporter.
TestPartResultReporterInterface*
UnitTestImpl::GetGlobalTestPartResultReporter() {
  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
  return global_test_part_result_repoter_;
}

// Sets the global test part result reporter.
void UnitTestImpl::SetGlobalTestPartResultReporter(
    TestPartResultReporterInterface* reporter) {
  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
  global_test_part_result_repoter_ = reporter;
}

// Returns the test part result reporter for the current thread.
TestPartResultReporterInterface*
UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
  return per_thread_test_part_result_reporter_.get();
}

// Sets the test part result reporter for the current thread.
void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
    TestPartResultReporterInterface* reporter) {
  per_thread_test_part_result_reporter_.set(reporter);
}

// Gets the number of successful test cases.
int UnitTestImpl::successful_test_case_count() const {
  return CountIf(test_cases_, TestCasePassed);
}

// Gets the number of failed test cases.
int UnitTestImpl::failed_test_case_count() const {
  return CountIf(test_cases_, TestCaseFailed);
}

// Gets the number of all test cases.
int UnitTestImpl::total_test_case_count() const {
  return static_cast<int>(test_cases_.size());
}

// Gets the number of all test cases that contain at least one test
// that should run.
int UnitTestImpl::test_case_to_run_count() const {
  return CountIf(test_cases_, ShouldRunTestCase);
}

// Gets the number of successful tests.
int UnitTestImpl::successful_test_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
}

// Gets the number of failed tests.
int UnitTestImpl::failed_test_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
}

// Gets the number of disabled tests that will be reported in the XML report.
int UnitTestImpl::reportable_disabled_test_count() const {
  return SumOverTestCaseList(test_cases_,
                             &TestCase::reportable_disabled_test_count);
}

// Gets the number of disabled tests.
int UnitTestImpl::disabled_test_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
}

// Gets the number of tests to be printed in the XML report.
int UnitTestImpl::reportable_test_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
}

// Gets the number of all tests.
int UnitTestImpl::total_test_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
}

// Gets the number of tests that should run.
int UnitTestImpl::test_to_run_count() const {
  return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
}

// Returns the current OS stack trace as an std::string.
//
// The maximum number of stack frames to be included is specified by
// the gtest_stack_trace_depth flag.  The skip_count parameter
// specifies the number of top frames to be skipped, which doesn't
// count against the number of frames to be included.
//
// For example, if Foo() calls Bar(), which in turn calls
// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
  (void)skip_count;
  return "";
}

// Returns the current time in milliseconds.
TimeInMillis GetTimeInMillis() {
#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
  // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
  // http://analogous.blogspot.com/2005/04/epoch.html
  const TimeInMillis kJavaEpochToWinFileTimeDelta =
    static_cast<TimeInMillis>(116444736UL) * 100000UL;
  const DWORD kTenthMicrosInMilliSecond = 10000;

  SYSTEMTIME now_systime;
  FILETIME now_filetime;
  ULARGE_INTEGER now_int64;
  // TODO(kenton@google.com): Shouldn't this just use
  //   GetSystemTimeAsFileTime()?
  GetSystemTime(&now_systime);
  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
    now_int64.LowPart = now_filetime.dwLowDateTime;
    now_int64.HighPart = now_filetime.dwHighDateTime;
    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
      kJavaEpochToWinFileTimeDelta;
    return now_int64.QuadPart;
  }
  return 0;
#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
  __timeb64 now;

# ifdef _MSC_VER

  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
  // (deprecated function) there.
  // TODO(kenton@google.com): Use GetTickCount()?  Or use
  //   SystemTimeToFileTime()
#  pragma warning(push)          // Saves the current warning state.
#  pragma warning(disable:4996)  // Temporarily disables warning 4996.
  _ftime64(&now);
#  pragma warning(pop)           // Restores the warning state.
# else

  _ftime64(&now);

# endif  // _MSC_VER

  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
#elif GTEST_HAS_GETTIMEOFDAY_
  struct timeval now;
  gettimeofday(&now, NULL);
  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
#else
# error "Don't know how to get the current time on your system."
#endif
}

// Utilities

// class String.

#if GTEST_OS_WINDOWS_MOBILE
// Creates a UTF-16 wide string from the given ANSI string, allocating
// memory using new. The caller is responsible for deleting the return
// value using delete[]. Returns the wide string, or NULL if the
// input is NULL.
LPCWSTR String::AnsiToUtf16(const char* ansi) {
  if (!ansi) return NULL;
  const int length = strlen(ansi);
  const int unicode_length =
      MultiByteToWideChar(CP_ACP, 0, ansi, length,
                          NULL, 0);
  WCHAR* unicode = new WCHAR[unicode_length + 1];
  MultiByteToWideChar(CP_ACP, 0, ansi, length,
                      unicode, unicode_length);
  unicode[unicode_length] = 0;
  return unicode;
}

// Creates an ANSI string from the given wide string, allocating
// memory using new. The caller is responsible for deleting the return
// value using delete[]. Returns the ANSI string, or NULL if the
// input is NULL.
const char* String::Utf16ToAnsi(LPCWSTR utf16_str)  {
  if (!utf16_str) return NULL;
  const int ansi_length =
      WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
                          NULL, 0, NULL, NULL);
  char* ansi = new char[ansi_length + 1];
  WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
                      ansi, ansi_length, NULL, NULL);
  ansi[ansi_length] = 0;
  return ansi;
}

#endif  // GTEST_OS_WINDOWS_MOBILE

// Compares two C strings.  Returns true iff they have the same content.
//
// Unlike strcmp(), this function can handle NULL argument(s).  A NULL
// C string is considered different to any non-NULL C string,
// including the empty string.
bool String::CStringEquals(const char * lhs, const char * rhs) {
  if ( lhs == NULL ) return rhs == NULL;

  if ( rhs == NULL ) return false;

  return strcmp(lhs, rhs) == 0;
}

#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

// Converts an array of wide chars to a narrow string using the UTF-8
// encoding, and streams the result to the given Message object.
static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
                                     Message* msg) {
  for (size_t i = 0; i != length; ) {  // NOLINT
    if (wstr[i] != L'\0') {
      *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
      while (i != length && wstr[i] != L'\0')
        i++;
    } else {
      *msg << '\0';
      i++;
    }
  }
}

#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

}  // namespace internal

// Constructs an empty Message.
// We allocate the stringstream separately because otherwise each use of
// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
// stack frame leading to huge stack frames in some cases; gcc does not reuse
// the stack space.
Message::Message() : ss_(new ::std::stringstream) {
  // By default, we want there to be enough precision when printing
  // a double to a Message.
  *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
}

// These two overloads allow streaming a wide C string to a Message
// using the UTF-8 encoding.
Message& Message::operator <<(const wchar_t* wide_c_str) {
  return *this << internal::String::ShowWideCString(wide_c_str);
}
Message& Message::operator <<(wchar_t* wide_c_str) {
  return *this << internal::String::ShowWideCString(wide_c_str);
}

#if GTEST_HAS_STD_WSTRING
// Converts the given wide string to a narrow string using the UTF-8
// encoding, and streams the result to this Message object.
Message& Message::operator <<(const ::std::wstring& wstr) {
  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
  return *this;
}
#endif  // GTEST_HAS_STD_WSTRING

#if GTEST_HAS_GLOBAL_WSTRING
// Converts the given wide string to a narrow string using the UTF-8
// encoding, and streams the result to this Message object.
Message& Message::operator <<(const ::wstring& wstr) {
  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
  return *this;
}
#endif  // GTEST_HAS_GLOBAL_WSTRING

// Gets the text streamed to this object so far as an std::string.
// Each '\0' character in the buffer is replaced with "\\0".
std::string Message::GetString() const {
  return internal::StringStreamToString(ss_.get());
}

// AssertionResult constructors.
// Used in EXPECT_TRUE/FALSE(assertion_result).
AssertionResult::AssertionResult(const AssertionResult& other)
    : success_(other.success_),
      message_(other.message_.get() != NULL ?
               new ::std::string(*other.message_) :
               static_cast< ::std::string*>(NULL)) {
}

// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
AssertionResult AssertionResult::operator!() const {
  AssertionResult negation(!success_);
  if (message_.get() != NULL)
    negation << *message_;
  return negation;
}

// Makes a successful assertion result.
AssertionResult AssertionSuccess() {
  return AssertionResult(true);
}

// Makes a failed assertion result.
AssertionResult AssertionFailure() {
  return AssertionResult(false);
}

// Makes a failed assertion result with the given failure message.
// Deprecated; use AssertionFailure() << message.
AssertionResult AssertionFailure(const Message& message) {
  return AssertionFailure() << message;
}

namespace internal {

// Constructs and returns the message for an equality assertion
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
//
// The first four parameters are the expressions used in the assertion
// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
// where foo is 5 and bar is 6, we have:
//
//   expected_expression: "foo"
//   actual_expression:   "bar"
//   expected_value:      "5"
//   actual_value:        "6"
//
// The ignoring_case parameter is true iff the assertion is a
// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
// be inserted into the message.
AssertionResult EqFailure(const char* expected_expression,
                          const char* actual_expression,
                          const std::string& expected_value,
                          const std::string& actual_value,
                          bool ignoring_case) {
  Message msg;
  msg << "Value of: " << actual_expression;
  if (actual_value != actual_expression) {
    msg << "\n  Actual: " << actual_value;
  }

  msg << "\nExpected: " << expected_expression;
  if (ignoring_case) {
    msg << " (ignoring case)";
  }
  if (expected_value != expected_expression) {
    msg << "\nWhich is: " << expected_value;
  }

  return AssertionFailure() << msg;
}

// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
std::string GetBoolAssertionFailureMessage(
    const AssertionResult& assertion_result,
    const char* expression_text,
    const char* actual_predicate_value,
    const char* expected_predicate_value) {
  const char* actual_message = assertion_result.message();
  Message msg;
  msg << "Value of: " << expression_text
      << "\n  Actual: " << actual_predicate_value;
  if (actual_message[0] != '\0')
    msg << " (" << actual_message << ")";
  msg << "\nExpected: " << expected_predicate_value;
  return msg.GetString();
}

// Helper function for implementing ASSERT_NEAR.
AssertionResult DoubleNearPredFormat(const char* expr1,
                                     const char* expr2,
                                     const char* abs_error_expr,
                                     double val1,
                                     double val2,
                                     double abs_error) {
  const double diff = fabs(val1 - val2);
  if (diff <= abs_error) return AssertionSuccess();

  // TODO(wan): do not print the value of an expression if it's
  // already a literal.
  return AssertionFailure()
      << "The difference between " << expr1 << " and " << expr2
      << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
      << expr1 << " evaluates to " << val1 << ",\n"
      << expr2 << " evaluates to " << val2 << ", and\n"
      << abs_error_expr << " evaluates to " << abs_error << ".";
}


// Helper template for implementing FloatLE() and DoubleLE().
template <typename RawType>
AssertionResult FloatingPointLE(const char* expr1,
                                const char* expr2,
                                RawType val1,
                                RawType val2) {
  // Returns success if val1 is less than val2,
  if (val1 < val2) {
    return AssertionSuccess();
  }

  // or if val1 is almost equal to val2.
  const FloatingPoint<RawType> lhs(val1), rhs(val2);
  if (lhs.AlmostEquals(rhs)) {
    return AssertionSuccess();
  }

  // Note that the above two checks will both fail if either val1 or
  // val2 is NaN, as the IEEE floating-point standard requires that
  // any predicate involving a NaN must return false.

  ::std::stringstream val1_ss;
  val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
          << val1;

  ::std::stringstream val2_ss;
  val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
          << val2;

  return AssertionFailure()
      << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
      << "  Actual: " << StringStreamToString(&val1_ss) << " vs "
      << StringStreamToString(&val2_ss);
}

}  // namespace internal

// Asserts that val1 is less than, or almost equal to, val2.  Fails
// otherwise.  In particular, it fails if either val1 or val2 is NaN.
AssertionResult FloatLE(const char* expr1, const char* expr2,
                        float val1, float val2) {
  return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
}

// Asserts that val1 is less than, or almost equal to, val2.  Fails
// otherwise.  In particular, it fails if either val1 or val2 is NaN.
AssertionResult DoubleLE(const char* expr1, const char* expr2,
                         double val1, double val2) {
  return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
}

namespace internal {

// The helper function for {ASSERT|EXPECT}_EQ with int or enum
// arguments.
AssertionResult CmpHelperEQ(const char* expected_expression,
                            const char* actual_expression,
                            BiggestInt expected,
                            BiggestInt actual) {
  if (expected == actual) {
    return AssertionSuccess();
  }

  return EqFailure(expected_expression,
                   actual_expression,
                   FormatForComparisonFailureMessage(expected, actual),
                   FormatForComparisonFailureMessage(actual, expected),
                   false);
}

// A macro for implementing the helper functions needed to implement
// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here
// just to avoid copy-and-paste of similar code.
#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
                                   BiggestInt val1, BiggestInt val2) {\
  if (val1 op val2) {\
    return AssertionSuccess();\
  } else {\
    return AssertionFailure() \
        << "Expected: (" << expr1 << ") " #op " (" << expr2\
        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
  }\
}

// Implements the helper function for {ASSERT|EXPECT}_NE with int or
// enum arguments.
GTEST_IMPL_CMP_HELPER_(NE, !=)
// Implements the helper function for {ASSERT|EXPECT}_LE with int or
// enum arguments.
GTEST_IMPL_CMP_HELPER_(LE, <=)
// Implements the helper function for {ASSERT|EXPECT}_LT with int or
// enum arguments.
GTEST_IMPL_CMP_HELPER_(LT, < )
// Implements the helper function for {ASSERT|EXPECT}_GE with int or
// enum arguments.
GTEST_IMPL_CMP_HELPER_(GE, >=)
// Implements the helper function for {ASSERT|EXPECT}_GT with int or
// enum arguments.
GTEST_IMPL_CMP_HELPER_(GT, > )

#undef GTEST_IMPL_CMP_HELPER_

// The helper function for {ASSERT|EXPECT}_STREQ.
AssertionResult CmpHelperSTREQ(const char* expected_expression,
                               const char* actual_expression,
                               const char* expected,
                               const char* actual) {
  if (String::CStringEquals(expected, actual)) {
    return AssertionSuccess();
  }

  return EqFailure(expected_expression,
                   actual_expression,
                   PrintToString(expected),
                   PrintToString(actual),
                   false);
}

// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
                                   const char* actual_expression,
                                   const char* expected,
                                   const char* actual) {
  if (String::CaseInsensitiveCStringEquals(expected, actual)) {
    return AssertionSuccess();
  }

  return EqFailure(expected_expression,
                   actual_expression,
                   PrintToString(expected),
                   PrintToString(actual),
                   true);
}

// The helper function for {ASSERT|EXPECT}_STRNE.
AssertionResult CmpHelperSTRNE(const char* s1_expression,
                               const char* s2_expression,
                               const char* s1,
                               const char* s2) {
  if (!String::CStringEquals(s1, s2)) {
    return AssertionSuccess();
  } else {
    return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
                              << s2_expression << "), actual: \""
                              << s1 << "\" vs \"" << s2 << "\"";
  }
}

// The helper function for {ASSERT|EXPECT}_STRCASENE.
AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
                                   const char* s2_expression,
                                   const char* s1,
                                   const char* s2) {
  if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
    return AssertionSuccess();
  } else {
    return AssertionFailure()
        << "Expected: (" << s1_expression << ") != ("
        << s2_expression << ") (ignoring case), actual: \""
        << s1 << "\" vs \"" << s2 << "\"";
  }
}

}  // namespace internal

namespace {

// Helper functions for implementing IsSubString() and IsNotSubstring().

// This group of overloaded functions return true iff needle is a
// substring of haystack.  NULL is considered a substring of itself
// only.

bool IsSubstringPred(const char* needle, const char* haystack) {
  if (needle == NULL || haystack == NULL)
    return needle == haystack;

  return strstr(haystack, needle) != NULL;
}

bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
  if (needle == NULL || haystack == NULL)
    return needle == haystack;

  return wcsstr(haystack, needle) != NULL;
}

// StringType here can be either ::std::string or ::std::wstring.
template <typename StringType>
bool IsSubstringPred(const StringType& needle,
                     const StringType& haystack) {
  return haystack.find(needle) != StringType::npos;
}

// This function implements either IsSubstring() or IsNotSubstring(),
// depending on the value of the expected_to_be_substring parameter.
// StringType here can be const char*, const wchar_t*, ::std::string,
// or ::std::wstring.
template <typename StringType>
AssertionResult IsSubstringImpl(
    bool expected_to_be_substring,
    const char* needle_expr, const char* haystack_expr,
    const StringType& needle, const StringType& haystack) {
  if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
    return AssertionSuccess();

  const bool is_wide_string = sizeof(needle[0]) > 1;
  const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
  return AssertionFailure()
      << "Value of: " << needle_expr << "\n"
      << "  Actual: " << begin_string_quote << needle << "\"\n"
      << "Expected: " << (expected_to_be_substring ? "" : "not ")
      << "a substring of " << haystack_expr << "\n"
      << "Which is: " << begin_string_quote << haystack << "\"";
}

}  // namespace

// IsSubstring() and IsNotSubstring() check whether needle is a
// substring of haystack (NULL is considered a substring of itself
// only), and return an appropriate error message when they fail.

AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const char* needle, const char* haystack) {
  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const wchar_t* needle, const wchar_t* haystack) {
  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const char* needle, const char* haystack) {
  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const wchar_t* needle, const wchar_t* haystack) {
  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::string& needle, const ::std::string& haystack) {
  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::string& needle, const ::std::string& haystack) {
  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
}

#if GTEST_HAS_STD_WSTRING
AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::wstring& needle, const ::std::wstring& haystack) {
  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
}

AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::wstring& needle, const ::std::wstring& haystack) {
  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
}
#endif  // GTEST_HAS_STD_WSTRING

namespace internal {

#if GTEST_OS_WINDOWS

namespace {

// Helper function for IsHRESULT{SuccessFailure} predicates
AssertionResult HRESULTFailureHelper(const char* expr,
                                     const char* expected,
                                     long hr) {  // NOLINT
# if GTEST_OS_WINDOWS_MOBILE

  // Windows CE doesn't support FormatMessage.
  const char error_text[] = "";

# else

  // Looks up the human-readable system message for the HRESULT code
  // and since we're not passing any params to FormatMessage, we don't
  // want inserts expanded.
  const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
                       FORMAT_MESSAGE_IGNORE_INSERTS;
  const DWORD kBufSize = 4096;
  // Gets the system's human readable message string for this HRESULT.
  char error_text[kBufSize] = { '\0' };
  DWORD message_length = ::FormatMessageA(kFlags,
                                          0,  // no source, we're asking system
                                          hr,  // the error
                                          0,  // no line width restrictions
                                          error_text,  // output buffer
                                          kBufSize,  // buf size
                                          NULL);  // no arguments for inserts
  // Trims tailing white space (FormatMessage leaves a trailing CR-LF)
  for (; message_length && IsSpace(error_text[message_length - 1]);
          --message_length) {
    error_text[message_length - 1] = '\0';
  }

# endif  // GTEST_OS_WINDOWS_MOBILE

  const std::string error_hex("0x" + String::FormatHexInt(hr));
  return ::testing::AssertionFailure()
      << "Expected: " << expr << " " << expected << ".\n"
      << "  Actual: " << error_hex << " " << error_text << "\n";
}

}  // namespace

AssertionResult IsHRESULTSuccess(const char* expr, long hr) {  // NOLINT
  if (SUCCEEDED(hr)) {
    return AssertionSuccess();
  }
  return HRESULTFailureHelper(expr, "succeeds", hr);
}

AssertionResult IsHRESULTFailure(const char* expr, long hr) {  // NOLINT
  if (FAILED(hr)) {
    return AssertionSuccess();
  }
  return HRESULTFailureHelper(expr, "fails", hr);
}

#endif  // GTEST_OS_WINDOWS

// Utility functions for encoding Unicode text (wide strings) in
// UTF-8.

// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
// like this:
//
// Code-point length   Encoding
//   0 -  7 bits       0xxxxxxx
//   8 - 11 bits       110xxxxx 10xxxxxx
//  12 - 16 bits       1110xxxx 10xxxxxx 10xxxxxx
//  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

// The maximum code-point a one-byte UTF-8 sequence can represent.
const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;

// The maximum code-point a two-byte UTF-8 sequence can represent.
const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;

// The maximum code-point a three-byte UTF-8 sequence can represent.
const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;

// The maximum code-point a four-byte UTF-8 sequence can represent.
const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;

// Chops off the n lowest bits from a bit pattern.  Returns the n
// lowest bits.  As a side effect, the original bit pattern will be
// shifted to the right by n bits.
inline UInt32 ChopLowBits(UInt32* bits, int n) {
  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
  *bits >>= n;
  return low_bits;
}

// Converts a Unicode code point to a narrow string in UTF-8 encoding.
// code_point parameter is of type UInt32 because wchar_t may not be
// wide enough to contain a code point.
// If the code_point is not a valid Unicode code point
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
// to "(Invalid Unicode 0xXXXXXXXX)".
std::string CodePointToUtf8(UInt32 code_point) {
  if (code_point > kMaxCodePoint4) {
    return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
  }

  char str[5];  // Big enough for the largest valid code point.
  if (code_point <= kMaxCodePoint1) {
    str[1] = '\0';
    str[0] = static_cast<char>(code_point);                          // 0xxxxxxx
  } else if (code_point <= kMaxCodePoint2) {
    str[2] = '\0';
    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[0] = static_cast<char>(0xC0 | code_point);                   // 110xxxxx
  } else if (code_point <= kMaxCodePoint3) {
    str[3] = '\0';
    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[0] = static_cast<char>(0xE0 | code_point);                   // 1110xxxx
  } else {  // code_point <= kMaxCodePoint4
    str[4] = '\0';
    str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
    str[0] = static_cast<char>(0xF0 | code_point);                   // 11110xxx
  }
  return str;
}

// The following two functions only make sense if the the system
// uses UTF-16 for wide string encoding. All supported systems
// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.

// Determines if the arguments constitute UTF-16 surrogate pair
// and thus should be combined into a single Unicode code point
// using CreateCodePointFromUtf16SurrogatePair.
inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
  return sizeof(wchar_t) == 2 &&
      (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
}

// Creates a Unicode code point from UTF16 surrogate pair.
inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
                                                    wchar_t second) {
  const UInt32 mask = (1 << 10) - 1;
  return (sizeof(wchar_t) == 2) ?
      (((first & mask) << 10) | (second & mask)) + 0x10000 :
      // This function should not be called when the condition is
      // false, but we provide a sensible default in case it is.
      static_cast<UInt32>(first);
}

// Converts a wide string to a narrow string in UTF-8 encoding.
// The wide string is assumed to have the following encoding:
//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
// Parameter str points to a null-terminated wide string.
// Parameter num_chars may additionally limit the number
// of wchar_t characters processed. -1 is used when the entire string
// should be processed.
// If the string contains code points that are not valid Unicode code points
// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
// and contains invalid UTF-16 surrogate pairs, values in those pairs
// will be encoded as individual Unicode characters from Basic Normal Plane.
std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
  if (num_chars == -1)
    num_chars = static_cast<int>(wcslen(str));

  ::std::stringstream stream;
  for (int i = 0; i < num_chars; ++i) {
    UInt32 unicode_code_point;

    if (str[i] == L'\0') {
      break;
    } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
      unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
                                                                 str[i + 1]);
      i++;
    } else {
      unicode_code_point = static_cast<UInt32>(str[i]);
    }

    stream << CodePointToUtf8(unicode_code_point);
  }
  return StringStreamToString(&stream);
}

// Converts a wide C string to an std::string using the UTF-8 encoding.
// NULL will be converted to "(null)".
std::string String::ShowWideCString(const wchar_t * wide_c_str) {
  if (wide_c_str == NULL)  return "(null)";

  return internal::WideStringToUtf8(wide_c_str, -1);
}

// Compares two wide C strings.  Returns true iff they have the same
// content.
//
// Unlike wcscmp(), this function can handle NULL argument(s).  A NULL
// C string is considered different to any non-NULL C string,
// including the empty string.
bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
  if (lhs == NULL) return rhs == NULL;

  if (rhs == NULL) return false;

  return wcscmp(lhs, rhs) == 0;
}

// Helper function for *_STREQ on wide strings.
AssertionResult CmpHelperSTREQ(const char* expected_expression,
                               const char* actual_expression,
                               const wchar_t* expected,
                               const wchar_t* actual) {
  if (String::WideCStringEquals(expected, actual)) {
    return AssertionSuccess();
  }

  return EqFailure(expected_expression,
                   actual_expression,
                   PrintToString(expected),
                   PrintToString(actual),
                   false);
}

// Helper function for *_STRNE on wide strings.
AssertionResult CmpHelperSTRNE(const char* s1_expression,
                               const char* s2_expression,
                               const wchar_t* s1,
                               const wchar_t* s2) {
  if (!String::WideCStringEquals(s1, s2)) {
    return AssertionSuccess();
  }

  return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
                            << s2_expression << "), actual: "
                            << PrintToString(s1)
                            << " vs " << PrintToString(s2);
}

// Compares two C strings, ignoring case.  Returns true iff they have
// the same content.
//
// Unlike strcasecmp(), this function can handle NULL argument(s).  A
// NULL C string is considered different to any non-NULL C string,
// including the empty string.
bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
  if (lhs == NULL)
    return rhs == NULL;
  if (rhs == NULL)
    return false;
  return posix::StrCaseCmp(lhs, rhs) == 0;
}

  // Compares two wide C strings, ignoring case.  Returns true iff they
  // have the same content.
  //
  // Unlike wcscasecmp(), this function can handle NULL argument(s).
  // A NULL C string is considered different to any non-NULL wide C string,
  // including the empty string.
  // NB: The implementations on different platforms slightly differ.
  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
  // environment variable. On GNU platform this method uses wcscasecmp
  // which compares according to LC_CTYPE category of the current locale.
  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
  // current locale.
bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
                                              const wchar_t* rhs) {
  if (lhs == NULL) return rhs == NULL;

  if (rhs == NULL) return false;

#if GTEST_OS_WINDOWS
  return _wcsicmp(lhs, rhs) == 0;
#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
  return wcscasecmp(lhs, rhs) == 0;
#else
  // Android, Mac OS X and Cygwin don't define wcscasecmp.
  // Other unknown OSes may not define it either.
  wint_t left, right;
  do {
    left = towlower(*lhs++);
    right = towlower(*rhs++);
  } while (left && left == right);
  return left == right;
#endif  // OS selector
}

// Returns true iff str ends with the given suffix, ignoring case.
// Any string is considered to end with an empty suffix.
bool String::EndsWithCaseInsensitive(
    const std::string& str, const std::string& suffix) {
  const size_t str_len = str.length();
  const size_t suffix_len = suffix.length();
  return (str_len >= suffix_len) &&
         CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
                                      suffix.c_str());
}

// Formats an int value as "%02d".
std::string String::FormatIntWidth2(int value) {
  std::stringstream ss;
  ss << std::setfill('0') << std::setw(2) << value;
  return ss.str();
}

// Formats an int value as "%X".
std::string String::FormatHexInt(int value) {
  std::stringstream ss;
  ss << std::hex << std::uppercase << value;
  return ss.str();
}

// Formats a byte as "%02X".
std::string String::FormatByte(unsigned char value) {
  std::stringstream ss;
  ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
     << static_cast<unsigned int>(value);
  return ss.str();
}

// Converts the buffer in a stringstream to an std::string, converting NUL
// bytes to "\\0" along the way.
std::string StringStreamToString(::std::stringstream* ss) {
  const ::std::string& str = ss->str();
  const char* const start = str.c_str();
  const char* const end = start + str.length();

  std::string result;
  result.reserve(2 * (end - start));
  for (const char* ch = start; ch != end; ++ch) {
    if (*ch == '\0') {
      result += "\\0";  // Replaces NUL with "\\0";
    } else {
      result += *ch;
    }
  }

  return result;
}

// Appends the user-supplied message to the Google-Test-generated message.
std::string AppendUserMessage(const std::string& gtest_msg,
                              const Message& user_msg) {
  // Appends the user message if it's non-empty.
  const std::string user_msg_string = user_msg.GetString();
  if (user_msg_string.empty()) {
    return gtest_msg;
  }

  return gtest_msg + "\n" + user_msg_string;
}

}  // namespace internal

// class TestResult

// Creates an empty TestResult.
TestResult::TestResult()
    : death_test_count_(0),
      elapsed_time_(0) {
}

// D'tor.
TestResult::~TestResult() {
}

// Returns the i-th test part result among all the results. i can
// range from 0 to total_part_count() - 1. If i is not in that range,
// aborts the program.
const TestPartResult& TestResult::GetTestPartResult(int i) const {
  if (i < 0 || i >= total_part_count())
    internal::posix::Abort();
  return test_part_results_.at(i);
}

// Returns the i-th test property. i can range from 0 to
// test_property_count() - 1. If i is not in that range, aborts the
// program.
const TestProperty& TestResult::GetTestProperty(int i) const {
  if (i < 0 || i >= test_property_count())
    internal::posix::Abort();
  return test_properties_.at(i);
}

// Clears the test part results.
void TestResult::ClearTestPartResults() {
  test_part_results_.clear();
}

// Adds a test part result to the list.
void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
  test_part_results_.push_back(test_part_result);
}

// Adds a test property to the list. If a property with the same key as the
// supplied property is already represented, the value of this test_property
// replaces the old value for that key.
void TestResult::RecordProperty(const std::string& xml_element,
                                const TestProperty& test_property) {
  if (!ValidateTestProperty(xml_element, test_property)) {
    return;
  }
  internal::MutexLock lock(&test_properites_mutex_);
  const std::vector<TestProperty>::iterator property_with_matching_key =
      std::find_if(test_properties_.begin(), test_properties_.end(),
                   internal::TestPropertyKeyIs(test_property.key()));
  if (property_with_matching_key == test_properties_.end()) {
    test_properties_.push_back(test_property);
    return;
  }
  property_with_matching_key->SetValue(test_property.value());
}

// The list of reserved attributes used in the <testsuites> element of XML
// output.
static const char* const kReservedTestSuitesAttributes[] = {
  "disabled",
  "errors",
  "failures",
  "name",
  "random_seed",
  "tests",
  "time",
  "timestamp"
};

// The list of reserved attributes used in the <testsuite> element of XML
// output.
static const char* const kReservedTestSuiteAttributes[] = {
  "disabled",
  "errors",
  "failures",
  "name",
  "tests",
  "time"
};

// The list of reserved attributes used in the <testcase> element of XML output.
static const char* const kReservedTestCaseAttributes[] = {
  "classname",
  "name",
  "status",
  "time",
  "type_param",
  "value_param"
};

template <int kSize>
std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
  return std::vector<std::string>(array, array + kSize);
}

static std::vector<std::string> GetReservedAttributesForElement(
    const std::string& xml_element) {
  if (xml_element == "testsuites") {
    return ArrayAsVector(kReservedTestSuitesAttributes);
  } else if (xml_element == "testsuite") {
    return ArrayAsVector(kReservedTestSuiteAttributes);
  } else if (xml_element == "testcase") {
    return ArrayAsVector(kReservedTestCaseAttributes);
  } else {
    GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
  }
  // This code is unreachable but some compilers may not realizes that.
  return std::vector<std::string>();
}

static std::string FormatWordList(const std::vector<std::string>& words) {
  Message word_list;
  for (size_t i = 0; i < words.size(); ++i) {
    if (i > 0 && words.size() > 2) {
      word_list << ", ";
    }
    if (i == words.size() - 1) {
      word_list << "and ";
    }
    word_list << "'" << words[i] << "'";
  }
  return word_list.GetString();
}

bool ValidateTestPropertyName(const std::string& property_name,
                              const std::vector<std::string>& reserved_names) {
  if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
          reserved_names.end()) {
    ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
                  << " (" << FormatWordList(reserved_names)
                  << " are reserved by " << GTEST_NAME_ << ")";
    return false;
  }
  return true;
}

// Adds a failure if the key is a reserved attribute of the element named
// xml_element.  Returns true if the property is valid.
bool TestResult::ValidateTestProperty(const std::string& xml_element,
                                      const TestProperty& test_property) {
  return ValidateTestPropertyName(test_property.key(),
                                  GetReservedAttributesForElement(xml_element));
}

// Clears the object.
void TestResult::Clear() {
  test_part_results_.clear();
  test_properties_.clear();
  death_test_count_ = 0;
  elapsed_time_ = 0;
}

// Returns true iff the test failed.
bool TestResult::Failed() const {
  for (int i = 0; i < total_part_count(); ++i) {
    if (GetTestPartResult(i).failed())
      return true;
  }
  return false;
}

// Returns true iff the test part fatally failed.
static bool TestPartFatallyFailed(const TestPartResult& result) {
  return result.fatally_failed();
}

// Returns true iff the test fatally failed.
bool TestResult::HasFatalFailure() const {
  return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
}

// Returns true iff the test part non-fatally failed.
static bool TestPartNonfatallyFailed(const TestPartResult& result) {
  return result.nonfatally_failed();
}

// Returns true iff the test has a non-fatal failure.
bool TestResult::HasNonfatalFailure() const {
  return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
}

// Gets the number of all test parts.  This is the sum of the number
// of successful test parts and the number of failed test parts.
int TestResult::total_part_count() const {
  return static_cast<int>(test_part_results_.size());
}

// Returns the number of the test properties.
int TestResult::test_property_count() const {
  return static_cast<int>(test_properties_.size());
}

// class Test

// Creates a Test object.

// The c'tor saves the values of all Google Test flags.
Test::Test()
    : gtest_flag_saver_(new internal::GTestFlagSaver) {
}

// The d'tor restores the values of all Google Test flags.
Test::~Test() {
  delete gtest_flag_saver_;
}

// Sets up the test fixture.
//
// A sub-class may override this.
void Test::SetUp() {
}

// Tears down the test fixture.
//
// A sub-class may override this.
void Test::TearDown() {
}

// Allows user supplied key value pairs to be recorded for later output.
void Test::RecordProperty(const std::string& key, const std::string& value) {
  UnitTest::GetInstance()->RecordProperty(key, value);
}

// Allows user supplied key value pairs to be recorded for later output.
void Test::RecordProperty(const std::string& key, int value) {
  Message value_message;
  value_message << value;
  RecordProperty(key, value_message.GetString().c_str());
}

namespace internal {

void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
                                    const std::string& message) {
  // This function is a friend of UnitTest and as such has access to
  // AddTestPartResult.
  UnitTest::GetInstance()->AddTestPartResult(
      result_type,
      NULL,  // No info about the source file where the exception occurred.
      -1,    // We have no info on which line caused the exception.
      message,
      "");   // No stack trace, either.
}

}  // namespace internal

// Google Test requires all tests in the same test case to use the same test
// fixture class.  This function checks if the current test has the
// same fixture class as the first test in the current test case.  If
// yes, it returns true; otherwise it generates a Google Test failure and
// returns false.
bool Test::HasSameFixtureClass() {
  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  const TestCase* const test_case = impl->current_test_case();

  // Info about the first test in the current test case.
  const TestInfo* const first_test_info = test_case->test_info_list()[0];
  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
  const char* const first_test_name = first_test_info->name();

  // Info about the current test.
  const TestInfo* const this_test_info = impl->current_test_info();
  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
  const char* const this_test_name = this_test_info->name();

  if (this_fixture_id != first_fixture_id) {
    // Is the first test defined using TEST?
    const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
    // Is this test defined using TEST?
    const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();

    if (first_is_TEST || this_is_TEST) {
      // The user mixed TEST and TEST_F in this test case - we'll tell
      // him/her how to fix it.

      // Gets the name of the TEST and the name of the TEST_F.  Note
      // that first_is_TEST and this_is_TEST cannot both be true, as
      // the fixture IDs are different for the two tests.
      const char* const TEST_name =
          first_is_TEST ? first_test_name : this_test_name;
      const char* const TEST_F_name =
          first_is_TEST ? this_test_name : first_test_name;

      ADD_FAILURE()
          << "All tests in the same test case must use the same test fixture\n"
          << "class, so mixing TEST_F and TEST in the same test case is\n"
          << "illegal.  In test case " << this_test_info->test_case_name()
          << ",\n"
          << "test " << TEST_F_name << " is defined using TEST_F but\n"
          << "test " << TEST_name << " is defined using TEST.  You probably\n"
          << "want to change the TEST to TEST_F or move it to another test\n"
          << "case.";
    } else {
      // The user defined two fixture classes with the same name in
      // two namespaces - we'll tell him/her how to fix it.
      ADD_FAILURE()
          << "All tests in the same test case must use the same test fixture\n"
          << "class.  However, in test case "
          << this_test_info->test_case_name() << ",\n"
          << "you defined test " << first_test_name
          << " and test " << this_test_name << "\n"
          << "using two different test fixture classes.  This can happen if\n"
          << "the two classes are from different namespaces or translation\n"
          << "units and have the same name.  You should probably rename one\n"
          << "of the classes to put the tests into different test cases.";
    }
    return false;
  }

  return true;
}

#if GTEST_HAS_SEH

// Adds an "exception thrown" fatal failure to the current test.  This
// function returns its result via an output parameter pointer because VC++
// prohibits creation of objects with destructors on stack in functions
// using __try (see error C2712).
static std::string* FormatSehExceptionMessage(DWORD exception_code,
                                              const char* location) {
  Message message;
  message << "SEH exception with code 0x" << std::setbase(16) <<
    exception_code << std::setbase(10) << " thrown in " << location << ".";

  return new std::string(message.GetString());
}

#endif  // GTEST_HAS_SEH

namespace internal {

#if GTEST_HAS_EXCEPTIONS

// Adds an "exception thrown" fatal failure to the current test.
static std::string FormatCxxExceptionMessage(const char* description,
                                             const char* location) {
  Message message;
  if (description != NULL) {
    message << "C++ exception with description \"" << description << "\"";
  } else {
    message << "Unknown C++ exception";
  }
  message << " thrown in " << location << ".";

  return message.GetString();
}

static std::string PrintTestPartResultToString(
    const TestPartResult& test_part_result);

GoogleTestFailureException::GoogleTestFailureException(
    const TestPartResult& failure)
    : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}

#endif  // GTEST_HAS_EXCEPTIONS

// We put these helper functions in the internal namespace as IBM's xlC
// compiler rejects the code if they were declared static.

// Runs the given method and handles SEH exceptions it throws, when
// SEH is supported; returns the 0-value for type Result in case of an
// SEH exception.  (Microsoft compilers cannot handle SEH and C++
// exceptions in the same function.  Therefore, we provide a separate
// wrapper function for handling SEH exceptions.)
template <class T, typename Result>
Result HandleSehExceptionsInMethodIfSupported(
    T* object, Result (T::*method)(), const char* location) {
#if GTEST_HAS_SEH
  __try {
    return (object->*method)();
  } __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINT
      GetExceptionCode())) {
    // We create the exception message on the heap because VC++ prohibits
    // creation of objects with destructors on stack in functions using __try
    // (see error C2712).
    std::string* exception_message = FormatSehExceptionMessage(
        GetExceptionCode(), location);
    internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
                                             *exception_message);
    delete exception_message;
    return static_cast<Result>(0);
  }
#else
  (void)location;
  return (object->*method)();
#endif  // GTEST_HAS_SEH
}

// Runs the given method and catches and reports C++ and/or SEH-style
// exceptions, if they are supported; returns the 0-value for type
// Result in case of an SEH exception.
template <class T, typename Result>
Result HandleExceptionsInMethodIfSupported(
    T* object, Result (T::*method)(), const char* location) {
  // NOTE: The user code can affect the way in which Google Test handles
  // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
  // RUN_ALL_TESTS() starts. It is technically possible to check the flag
  // after the exception is caught and either report or re-throw the
  // exception based on the flag's value:
  //
  // try {
  //   // Perform the test method.
  // } catch (...) {
  //   if (GTEST_FLAG(catch_exceptions))
  //     // Report the exception as failure.
  //   else
  //     throw;  // Re-throws the original exception.
  // }
  //
  // However, the purpose of this flag is to allow the program to drop into
  // the debugger when the exception is thrown. On most platforms, once the
  // control enters the catch block, the exception origin information is
  // lost and the debugger will stop the program at the point of the
  // re-throw in this function -- instead of at the point of the original
  // throw statement in the code under test.  For this reason, we perform
  // the check early, sacrificing the ability to affect Google Test's
  // exception handling in the method where the exception is thrown.
  if (internal::GetUnitTestImpl()->catch_exceptions()) {
#if GTEST_HAS_EXCEPTIONS
    try {
      return HandleSehExceptionsInMethodIfSupported(object, method, location);
    } catch (const internal::GoogleTestFailureException&) {  // NOLINT
      // This exception type can only be thrown by a failed Google
      // Test assertion with the intention of letting another testing
      // framework catch it.  Therefore we just re-throw it.
      throw;
    } catch (const std::exception& e) {  // NOLINT
      internal::ReportFailureInUnknownLocation(
          TestPartResult::kFatalFailure,
          FormatCxxExceptionMessage(e.what(), location));
    } catch (...) {  // NOLINT
      internal::ReportFailureInUnknownLocation(
          TestPartResult::kFatalFailure,
          FormatCxxExceptionMessage(NULL, location));
    }
    return static_cast<Result>(0);
#else
    return HandleSehExceptionsInMethodIfSupported(object, method, location);
#endif  // GTEST_HAS_EXCEPTIONS
  } else {
    return (object->*method)();
  }
}

}  // namespace internal

// Runs the test and updates the test result.
void Test::Run() {
  if (!HasSameFixtureClass()) return;

  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
  // We will run the test only if SetUp() was successful.
  if (!HasFatalFailure()) {
    impl->os_stack_trace_getter()->UponLeavingGTest();
    internal::HandleExceptionsInMethodIfSupported(
        this, &Test::TestBody, "the test body");
  }

  // However, we want to clean up as much as possible.  Hence we will
  // always call TearDown(), even if SetUp() or the test body has
  // failed.
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      this, &Test::TearDown, "TearDown()");
}

// Returns true iff the current test has a fatal failure.
bool Test::HasFatalFailure() {
  return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
}

// Returns true iff the current test has a non-fatal failure.
bool Test::HasNonfatalFailure() {
  return internal::GetUnitTestImpl()->current_test_result()->
      HasNonfatalFailure();
}

// class TestInfo

// Constructs a TestInfo object. It assumes ownership of the test factory
// object.
TestInfo::TestInfo(const std::string& a_test_case_name,
                   const std::string& a_name,
                   const char* a_type_param,
                   const char* a_value_param,
                   internal::TypeId fixture_class_id,
                   internal::TestFactoryBase* factory)
    : test_case_name_(a_test_case_name),
      name_(a_name),
      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
      value_param_(a_value_param ? new std::string(a_value_param) : NULL),
      fixture_class_id_(fixture_class_id),
      should_run_(false),
      is_disabled_(false),
      matches_filter_(false),
      factory_(factory),
      result_() {}

// Destructs a TestInfo object.
TestInfo::~TestInfo() { delete factory_; }

namespace internal {

// Creates a new TestInfo object and registers it with Google Test;
// returns the created object.
//
// Arguments:
//
//   test_case_name:   name of the test case
//   name:             name of the test
//   type_param:       the name of the test's type parameter, or NULL if
//                     this is not a typed or a type-parameterized test.
//   value_param:      text representation of the test's value parameter,
//                     or NULL if this is not a value-parameterized test.
//   fixture_class_id: ID of the test fixture class
//   set_up_tc:        pointer to the function that sets up the test case
//   tear_down_tc:     pointer to the function that tears down the test case
//   factory:          pointer to the factory that creates a test object.
//                     The newly created TestInfo instance will assume
//                     ownership of the factory object.
TestInfo* MakeAndRegisterTestInfo(
    const char* test_case_name,
    const char* name,
    const char* type_param,
    const char* value_param,
    TypeId fixture_class_id,
    SetUpTestCaseFunc set_up_tc,
    TearDownTestCaseFunc tear_down_tc,
    TestFactoryBase* factory) {
  TestInfo* const test_info =
      new TestInfo(test_case_name, name, type_param, value_param,
                   fixture_class_id, factory);
  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
  return test_info;
}

#if GTEST_HAS_PARAM_TEST
void ReportInvalidTestCaseType(const char* test_case_name,
                               const char* file, int line) {
  Message errors;
  errors
      << "Attempted redefinition of test case " << test_case_name << ".\n"
      << "All tests in the same test case must use the same test fixture\n"
      << "class.  However, in test case " << test_case_name << ", you tried\n"
      << "to define a test using a fixture class different from the one\n"
      << "used earlier. This can happen if the two fixture classes are\n"
      << "from different namespaces and have the same name. You should\n"
      << "probably rename one of the classes to put the tests into different\n"
      << "test cases.";

  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
          errors.GetString().c_str());
}
#endif  // GTEST_HAS_PARAM_TEST

}  // namespace internal

namespace {

// A predicate that checks the test name of a TestInfo against a known
// value.
//
// This is used for implementation of the TestCase class only.  We put
// it in the anonymous namespace to prevent polluting the outer
// namespace.
//
// TestNameIs is copyable.
class TestNameIs {
 public:
  // Constructor.
  //
  // TestNameIs has NO default constructor.
  explicit TestNameIs(const char* name)
      : name_(name) {}

  // Returns true iff the test name of test_info matches name_.
  bool operator()(const TestInfo * test_info) const {
    return test_info && test_info->name() == name_;
  }

 private:
  std::string name_;
};

}  // namespace

namespace internal {

// This method expands all parameterized tests registered with macros TEST_P
// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
// This will be done just once during the program runtime.
void UnitTestImpl::RegisterParameterizedTests() {
#if GTEST_HAS_PARAM_TEST
  if (!parameterized_tests_registered_) {
    parameterized_test_registry_.RegisterTests();
    parameterized_tests_registered_ = true;
  }
#endif
}

}  // namespace internal

// Creates the test object, runs it, records its result, and then
// deletes it.
void TestInfo::Run() {
  if (!should_run_) return;

  // Tells UnitTest where to store test result.
  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  impl->set_current_test_info(this);

  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();

  // Notifies the unit test event listeners that a test is about to start.
  repeater->OnTestStart(*this);

  const TimeInMillis start = internal::GetTimeInMillis();

  impl->os_stack_trace_getter()->UponLeavingGTest();

  // Creates the test object.
  Test* const test = internal::HandleExceptionsInMethodIfSupported(
      factory_, &internal::TestFactoryBase::CreateTest,
      "the test fixture's constructor");

  // Runs the test only if the test object was created and its
  // constructor didn't generate a fatal failure.
  if ((test != NULL) && !Test::HasFatalFailure()) {
    // This doesn't throw as all user code that can throw are wrapped into
    // exception handling code.
    test->Run();
  }

  // Deletes the test object.
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      test, &Test::DeleteSelf_, "the test fixture's destructor");

  result_.set_elapsed_time(internal::GetTimeInMillis() - start);

  // Notifies the unit test event listener that a test has just finished.
  repeater->OnTestEnd(*this);

  // Tells UnitTest to stop associating assertion results to this
  // test.
  impl->set_current_test_info(NULL);
}

// class TestCase

// Gets the number of successful tests in this test case.
int TestCase::successful_test_count() const {
  return CountIf(test_info_list_, TestPassed);
}

// Gets the number of failed tests in this test case.
int TestCase::failed_test_count() const {
  return CountIf(test_info_list_, TestFailed);
}

// Gets the number of disabled tests that will be reported in the XML report.
int TestCase::reportable_disabled_test_count() const {
  return CountIf(test_info_list_, TestReportableDisabled);
}

// Gets the number of disabled tests in this test case.
int TestCase::disabled_test_count() const {
  return CountIf(test_info_list_, TestDisabled);
}

// Gets the number of tests to be printed in the XML report.
int TestCase::reportable_test_count() const {
  return CountIf(test_info_list_, TestReportable);
}

// Get the number of tests in this test case that should run.
int TestCase::test_to_run_count() const {
  return CountIf(test_info_list_, ShouldRunTest);
}

// Gets the number of all tests.
int TestCase::total_test_count() const {
  return static_cast<int>(test_info_list_.size());
}

// Creates a TestCase with the given name.
//
// Arguments:
//
//   name:         name of the test case
//   a_type_param: the name of the test case's type parameter, or NULL if
//                 this is not a typed or a type-parameterized test case.
//   set_up_tc:    pointer to the function that sets up the test case
//   tear_down_tc: pointer to the function that tears down the test case
TestCase::TestCase(const char* a_name, const char* a_type_param,
                   Test::SetUpTestCaseFunc set_up_tc,
                   Test::TearDownTestCaseFunc tear_down_tc)
    : name_(a_name),
      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
      set_up_tc_(set_up_tc),
      tear_down_tc_(tear_down_tc),
      should_run_(false),
      elapsed_time_(0) {
}

// Destructor of TestCase.
TestCase::~TestCase() {
  // Deletes every Test in the collection.
  ForEach(test_info_list_, internal::Delete<TestInfo>);
}

// Returns the i-th test among all the tests. i can range from 0 to
// total_test_count() - 1. If i is not in that range, returns NULL.
const TestInfo* TestCase::GetTestInfo(int i) const {
  const int index = GetElementOr(test_indices_, i, -1);
  return index < 0 ? NULL : test_info_list_[index];
}

// Returns the i-th test among all the tests. i can range from 0 to
// total_test_count() - 1. If i is not in that range, returns NULL.
TestInfo* TestCase::GetMutableTestInfo(int i) {
  const int index = GetElementOr(test_indices_, i, -1);
  return index < 0 ? NULL : test_info_list_[index];
}

// Adds a test to this test case.  Will delete the test upon
// destruction of the TestCase object.
void TestCase::AddTestInfo(TestInfo * test_info) {
  test_info_list_.push_back(test_info);
  test_indices_.push_back(static_cast<int>(test_indices_.size()));
}

// Runs every test in this TestCase.
void TestCase::Run() {
  if (!should_run_) return;

  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  impl->set_current_test_case(this);

  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();

  repeater->OnTestCaseStart(*this);
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");

  const internal::TimeInMillis start = internal::GetTimeInMillis();
  for (int i = 0; i < total_test_count(); i++) {
    GetMutableTestInfo(i)->Run();
  }
  elapsed_time_ = internal::GetTimeInMillis() - start;

  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");

  repeater->OnTestCaseEnd(*this);
  impl->set_current_test_case(NULL);
}

// Clears the results of all tests in this test case.
void TestCase::ClearResult() {
  ad_hoc_test_result_.Clear();
  ForEach(test_info_list_, TestInfo::ClearTestResult);
}

// Shuffles the tests in this test case.
void TestCase::ShuffleTests(internal::Random* random) {
  Shuffle(random, &test_indices_);
}

// Restores the test order to before the first shuffle.
void TestCase::UnshuffleTests() {
  for (size_t i = 0; i < test_indices_.size(); i++) {
    test_indices_[i] = static_cast<int>(i);
  }
}

// Formats a countable noun.  Depending on its quantity, either the
// singular form or the plural form is used. e.g.
//
// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
// FormatCountableNoun(5, "book", "books") returns "5 books".
static std::string FormatCountableNoun(int count,
                                       const char * singular_form,
                                       const char * plural_form) {
  return internal::StreamableToString(count) + " " +
      (count == 1 ? singular_form : plural_form);
}

// Formats the count of tests.
static std::string FormatTestCount(int test_count) {
  return FormatCountableNoun(test_count, "test", "tests");
}

// Formats the count of test cases.
static std::string FormatTestCaseCount(int test_case_count) {
  return FormatCountableNoun(test_case_count, "test case", "test cases");
}

// Converts a TestPartResult::Type enum to human-friendly string
// representation.  Both kNonFatalFailure and kFatalFailure are translated
// to "Failure", as the user usually doesn't care about the difference
// between the two when viewing the test result.
static const char * TestPartResultTypeToString(TestPartResult::Type type) {
  switch (type) {
    case TestPartResult::kSuccess:
      return "Success";

    case TestPartResult::kNonFatalFailure:
    case TestPartResult::kFatalFailure:
#ifdef _MSC_VER
      return "error: ";
#else
      return "Failure\n";
#endif
    default:
      return "Unknown result type";
  }
}

namespace internal {

// Prints a TestPartResult to an std::string.
static std::string PrintTestPartResultToString(
    const TestPartResult& test_part_result) {
  return (Message()
          << internal::FormatFileLocation(test_part_result.file_name(),
                                          test_part_result.line_number())
          << " " << TestPartResultTypeToString(test_part_result.type())
          << test_part_result.message()).GetString();
}

// Prints a TestPartResult.
static void PrintTestPartResult(const TestPartResult& test_part_result) {
  const std::string& result =
      PrintTestPartResultToString(test_part_result);
  printf("%s\n", result.c_str());
  fflush(stdout);
  // If the test program runs in Visual Studio or a debugger, the
  // following statements add the test part result message to the Output
  // window such that the user can double-click on it to jump to the
  // corresponding source code location; otherwise they do nothing.
#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
  // We don't call OutputDebugString*() on Windows Mobile, as printing
  // to stdout is done by OutputDebugString() there already - we don't
  // want the same message printed twice.
  ::OutputDebugStringA(result.c_str());
  ::OutputDebugStringA("\n");
#endif
}

// class PrettyUnitTestResultPrinter

enum GTestColor {
  COLOR_DEFAULT,
  COLOR_RED,
  COLOR_GREEN,
  COLOR_YELLOW
};

#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE

// Returns the character attribute for the given color.
WORD GetColorAttribute(GTestColor color) {
  switch (color) {
    case COLOR_RED:    return FOREGROUND_RED;
    case COLOR_GREEN:  return FOREGROUND_GREEN;
    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
    default:           return 0;
  }
}

#else

// Returns the ANSI color code for the given color.  COLOR_DEFAULT is
// an invalid input.
const char* GetAnsiColorCode(GTestColor color) {
  switch (color) {
    case COLOR_RED:     return "1";
    case COLOR_GREEN:   return "2";
    case COLOR_YELLOW:  return "3";
    default:            return NULL;
  };
}

#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE

// Returns true iff Google Test should use colors in the output.
bool ShouldUseColor(bool stdout_is_tty) {
  const char* const gtest_color = GTEST_FLAG(color).c_str();

  if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
#if GTEST_OS_WINDOWS
    // On Windows the TERM variable is usually not set, but the
    // console there does support colors.
    return stdout_is_tty;
#else
    // On non-Windows platforms, we rely on the TERM variable.
    const char* const term = posix::GetEnv("TERM");
    const bool term_supports_color =
        String::CStringEquals(term, "xterm") ||
        String::CStringEquals(term, "xterm-color") ||
        String::CStringEquals(term, "xterm-256color") ||
        String::CStringEquals(term, "screen") ||
        String::CStringEquals(term, "screen-256color") ||
        String::CStringEquals(term, "linux") ||
        String::CStringEquals(term, "cygwin");
    return stdout_is_tty && term_supports_color;
#endif  // GTEST_OS_WINDOWS
  }

  return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
      String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
      String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
      String::CStringEquals(gtest_color, "1");
  // We take "yes", "true", "t", and "1" as meaning "yes".  If the
  // value is neither one of these nor "auto", we treat it as "no" to
  // be conservative.
}

// Helpers for printing colored strings to stdout. Note that on Windows, we
// cannot simply emit special characters and have the terminal change colors.
// This routine must actually emit the characters rather than return a string
// that would be colored when printed, as can be done on Linux.
void ColoredPrintf(GTestColor color, const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);

#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
  const bool use_color = false;
#else
  static const bool in_color_mode =
      ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
#endif  // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
  // The '!= 0' comparison is necessary to satisfy MSVC 7.1.

  if (!use_color) {
    vprintf(fmt, args);
    va_end(args);
    return;
  }

#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);

  // Gets the current text color.
  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
  const WORD old_color_attrs = buffer_info.wAttributes;

  // We need to flush the stream buffers into the console before each
  // SetConsoleTextAttribute call lest it affect the text that is already
  // printed but has not yet reached the console.
  fflush(stdout);
  SetConsoleTextAttribute(stdout_handle,
                          GetColorAttribute(color) | FOREGROUND_INTENSITY);
  vprintf(fmt, args);

  fflush(stdout);
  // Restores the text color.
  SetConsoleTextAttribute(stdout_handle, old_color_attrs);
#else
  printf("\033[0;3%sm", GetAnsiColorCode(color));
  vprintf(fmt, args);
  printf("\033[m");  // Resets the terminal to default.
#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
  va_end(args);
}

// Text printed in Google Test's text output and --gunit_list_tests
// output to label the type parameter and value parameter for a test.
static const char kTypeParamLabel[] = "TypeParam";
static const char kValueParamLabel[] = "GetParam()";

void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
  const char* const type_param = test_info.type_param();
  const char* const value_param = test_info.value_param();

  if (type_param != NULL || value_param != NULL) {
    printf(", where ");
    if (type_param != NULL) {
      printf("%s = %s", kTypeParamLabel, type_param);
      if (value_param != NULL)
        printf(" and ");
    }
    if (value_param != NULL) {
      printf("%s = %s", kValueParamLabel, value_param);
    }
  }
}

// This class implements the TestEventListener interface.
//
// Class PrettyUnitTestResultPrinter is copyable.
class PrettyUnitTestResultPrinter : public TestEventListener {
 public:
  PrettyUnitTestResultPrinter() {}
  static void PrintTestName(const char * test_case, const char * test) {
    printf("%s.%s", test_case, test);
  }

  // The following methods override what's in the TestEventListener class.
  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
  virtual void OnTestCaseStart(const TestCase& test_case);
  virtual void OnTestStart(const TestInfo& test_info);
  virtual void OnTestPartResult(const TestPartResult& result);
  virtual void OnTestEnd(const TestInfo& test_info);
  virtual void OnTestCaseEnd(const TestCase& test_case);
  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}

 private:
  static void PrintFailedTests(const UnitTest& unit_test);
};

  // Fired before each iteration of tests starts.
void PrettyUnitTestResultPrinter::OnTestIterationStart(
    const UnitTest& unit_test, int iteration) {
  if (GTEST_FLAG(repeat) != 1)
    printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);

  const char* const filter = GTEST_FLAG(filter).c_str();

  // Prints the filter if it's not *.  This reminds the user that some
  // tests may be skipped.
  if (!String::CStringEquals(filter, kUniversalFilter)) {
    ColoredPrintf(COLOR_YELLOW,
                  "Note: %s filter = %s\n", GTEST_NAME_, filter);
  }

  if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
    const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
    ColoredPrintf(COLOR_YELLOW,
                  "Note: This is test shard %d of %s.\n",
                  static_cast<int>(shard_index) + 1,
                  internal::posix::GetEnv(kTestTotalShards));
  }

  if (GTEST_FLAG(shuffle)) {
    ColoredPrintf(COLOR_YELLOW,
                  "Note: Randomizing tests' orders with a seed of %d .\n",
                  unit_test.random_seed());
  }

  ColoredPrintf(COLOR_GREEN,  "[==========] ");
  printf("Running %s from %s.\n",
         FormatTestCount(unit_test.test_to_run_count()).c_str(),
         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
    const UnitTest& /*unit_test*/) {
  ColoredPrintf(COLOR_GREEN,  "[----------] ");
  printf("Global test environment set-up.\n");
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
  const std::string counts =
      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
  ColoredPrintf(COLOR_GREEN, "[----------] ");
  printf("%s from %s", counts.c_str(), test_case.name());
  if (test_case.type_param() == NULL) {
    printf("\n");
  } else {
    printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
  }
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");
  PrintTestName(test_info.test_case_name(), test_info.name());
  printf("\n");
  fflush(stdout);
}

// Called after an assertion failure.
void PrettyUnitTestResultPrinter::OnTestPartResult(
    const TestPartResult& result) {
  // If the test part succeeded, we don't need to do anything.
  if (result.type() == TestPartResult::kSuccess)
    return;

  // Print failure message from the assertion (e.g. expected this and got that).
  PrintTestPartResult(result);
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
  if (test_info.result()->Passed()) {
    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
  } else {
    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
  }
  PrintTestName(test_info.test_case_name(), test_info.name());
  if (test_info.result()->Failed())
    PrintFullTestCommentIfPresent(test_info);

  if (GTEST_FLAG(print_time)) {
    printf(" (%s ms)\n", internal::StreamableToString(
           test_info.result()->elapsed_time()).c_str());
  } else {
    printf("\n");
  }
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
  if (!GTEST_FLAG(print_time)) return;

  const std::string counts =
      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
  ColoredPrintf(COLOR_GREEN, "[----------] ");
  printf("%s from %s (%s ms total)\n\n",
         counts.c_str(), test_case.name(),
         internal::StreamableToString(test_case.elapsed_time()).c_str());
  fflush(stdout);
}

void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
    const UnitTest& /*unit_test*/) {
  ColoredPrintf(COLOR_GREEN,  "[----------] ");
  printf("Global test environment tear-down\n");
  fflush(stdout);
}

// Internal helper for printing the list of failed tests.
void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
  const int failed_test_count = unit_test.failed_test_count();
  if (failed_test_count == 0) {
    return;
  }

  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
    const TestCase& test_case = *unit_test.GetTestCase(i);
    if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
      continue;
    }
    for (int j = 0; j < test_case.total_test_count(); ++j) {
      const TestInfo& test_info = *test_case.GetTestInfo(j);
      if (!test_info.should_run() || test_info.result()->Passed()) {
        continue;
      }
      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
      printf("%s.%s", test_case.name(), test_info.name());
      PrintFullTestCommentIfPresent(test_info);
      printf("\n");
    }
  }
}

void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
                                                     int /*iteration*/) {
  ColoredPrintf(COLOR_GREEN,  "[==========] ");
  printf("%s from %s ran.",
         FormatTestCount(unit_test.test_to_run_count()).c_str(),
         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
  if (GTEST_FLAG(print_time)) {
    printf(" (%s ms total)",
           internal::StreamableToString(unit_test.elapsed_time()).c_str());
  }
  printf("\n");
  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");
  printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());

  int num_failures = unit_test.failed_test_count();
  if (!unit_test.Passed()) {
    const int failed_test_count = unit_test.failed_test_count();
    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");
    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
    PrintFailedTests(unit_test);
    printf("\n%2d FAILED %s\n", num_failures,
                        num_failures == 1 ? "TEST" : "TESTS");
  }

  int num_disabled = unit_test.reportable_disabled_test_count();
  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
    if (!num_failures) {
      printf("\n");  // Add a spacer if no FAILURE banner is displayed.
    }
    ColoredPrintf(COLOR_YELLOW,
                  "  YOU HAVE %d DISABLED %s\n\n",
                  num_disabled,
                  num_disabled == 1 ? "TEST" : "TESTS");
  }
  // Ensure that Google Test output is printed before, e.g., heapchecker output.
  fflush(stdout);
}

// End PrettyUnitTestResultPrinter

// class TestEventRepeater
//
// This class forwards events to other event listeners.
class TestEventRepeater : public TestEventListener {
 public:
  TestEventRepeater() : forwarding_enabled_(true) {}
  virtual ~TestEventRepeater();
  void Append(TestEventListener *listener);
  TestEventListener* Release(TestEventListener* listener);

  // Controls whether events will be forwarded to listeners_. Set to false
  // in death test child processes.
  bool forwarding_enabled() const { return forwarding_enabled_; }
  void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }

  virtual void OnTestProgramStart(const UnitTest& unit_test);
  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
  virtual void OnTestCaseStart(const TestCase& test_case);
  virtual void OnTestStart(const TestInfo& test_info);
  virtual void OnTestPartResult(const TestPartResult& result);
  virtual void OnTestEnd(const TestInfo& test_info);
  virtual void OnTestCaseEnd(const TestCase& test_case);
  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
  virtual void OnTestProgramEnd(const UnitTest& unit_test);

 private:
  // Controls whether events will be forwarded to listeners_. Set to false
  // in death test child processes.
  bool forwarding_enabled_;
  // The list of listeners that receive events.
  std::vector<TestEventListener*> listeners_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
};

TestEventRepeater::~TestEventRepeater() {
  ForEach(listeners_, Delete<TestEventListener>);
}

void TestEventRepeater::Append(TestEventListener *listener) {
  listeners_.push_back(listener);
}

// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
  for (size_t i = 0; i < listeners_.size(); ++i) {
    if (listeners_[i] == listener) {
      listeners_.erase(listeners_.begin() + i);
      return listener;
    }
  }

  return NULL;
}

// Since most methods are very similar, use macros to reduce boilerplate.
// This defines a member that forwards the call to all listeners.
#define GTEST_REPEATER_METHOD_(Name, Type) \
void TestEventRepeater::Name(const Type& parameter) { \
  if (forwarding_enabled_) { \
    for (size_t i = 0; i < listeners_.size(); i++) { \
      listeners_[i]->Name(parameter); \
    } \
  } \
}
// This defines a member that forwards the call to all listeners in reverse
// order.
#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
void TestEventRepeater::Name(const Type& parameter) { \
  if (forwarding_enabled_) { \
    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
      listeners_[i]->Name(parameter); \
    } \
  } \
}

GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)

#undef GTEST_REPEATER_METHOD_
#undef GTEST_REVERSE_REPEATER_METHOD_

void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
                                             int iteration) {
  if (forwarding_enabled_) {
    for (size_t i = 0; i < listeners_.size(); i++) {
      listeners_[i]->OnTestIterationStart(unit_test, iteration);
    }
  }
}

void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
                                           int iteration) {
  if (forwarding_enabled_) {
    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
      listeners_[i]->OnTestIterationEnd(unit_test, iteration);
    }
  }
}

// End TestEventRepeater

// This class generates an XML output file.
class XmlUnitTestResultPrinter : public EmptyTestEventListener {
 public:
  explicit XmlUnitTestResultPrinter(const char* output_file);

  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);

 private:
  // Is c a whitespace character that is normalized to a space character
  // when it appears in an XML attribute value?
  static bool IsNormalizableWhitespace(char c) {
    return c == 0x9 || c == 0xA || c == 0xD;
  }

  // May c appear in a well-formed XML document?
  static bool IsValidXmlCharacter(char c) {
    return IsNormalizableWhitespace(c) || c >= 0x20;
  }

  // Returns an XML-escaped copy of the input string str.  If
  // is_attribute is true, the text is meant to appear as an attribute
  // value, and normalizable whitespace is preserved by replacing it
  // with character references.
  static std::string EscapeXml(const std::string& str, bool is_attribute);

  // Returns the given string with all characters invalid in XML removed.
  static std::string RemoveInvalidXmlCharacters(const std::string& str);

  // Convenience wrapper around EscapeXml when str is an attribute value.
  static std::string EscapeXmlAttribute(const std::string& str) {
    return EscapeXml(str, true);
  }

  // Convenience wrapper around EscapeXml when str is not an attribute value.
  static std::string EscapeXmlText(const char* str) {
    return EscapeXml(str, false);
  }

  // Verifies that the given attribute belongs to the given element and
  // streams the attribute as XML.
  static void OutputXmlAttribute(std::ostream* stream,
                                 const std::string& element_name,
                                 const std::string& name,
                                 const std::string& value);

  // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
  static void OutputXmlCDataSection(::std::ostream* stream, const char* data);

  // Streams an XML representation of a TestInfo object.
  static void OutputXmlTestInfo(::std::ostream* stream,
                                const char* test_case_name,
                                const TestInfo& test_info);

  // Prints an XML representation of a TestCase object
  static void PrintXmlTestCase(::std::ostream* stream,
                               const TestCase& test_case);

  // Prints an XML summary of unit_test to output stream out.
  static void PrintXmlUnitTest(::std::ostream* stream,
                               const UnitTest& unit_test);

  // Produces a string representing the test properties in a result as space
  // delimited XML attributes based on the property key="value" pairs.
  // When the std::string is not empty, it includes a space at the beginning,
  // to delimit this attribute from prior attributes.
  static std::string TestPropertiesAsXmlAttributes(const TestResult& result);

  // The output file.
  const std::string output_file_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
};

// Creates a new XmlUnitTestResultPrinter.
XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
    : output_file_(output_file) {
  if (output_file_.c_str() == NULL || output_file_.empty()) {
    fprintf(stderr, "XML output file may not be null\n");
    fflush(stderr);
    exit(EXIT_FAILURE);
  }
}

// Called after the unit test ends.
void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
                                                  int /*iteration*/) {
  FILE* xmlout = NULL;
  FilePath output_file(output_file_);
  FilePath output_dir(output_file.RemoveFileName());

  if (output_dir.CreateDirectoriesRecursively()) {
    xmlout = posix::FOpen(output_file_.c_str(), "w");
  }
  if (xmlout == NULL) {
    // TODO(wan): report the reason of the failure.
    //
    // We don't do it for now as:
    //
    //   1. There is no urgent need for it.
    //   2. It's a bit involved to make the errno variable thread-safe on
    //      all three operating systems (Linux, Windows, and Mac OS).
    //   3. To interpret the meaning of errno in a thread-safe way,
    //      we need the strerror_r() function, which is not available on
    //      Windows.
    fprintf(stderr,
            "Unable to open file \"%s\"\n",
            output_file_.c_str());
    fflush(stderr);
    exit(EXIT_FAILURE);
  }
  std::stringstream stream;
  PrintXmlUnitTest(&stream, unit_test);
  fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
  fclose(xmlout);
}

// Returns an XML-escaped copy of the input string str.  If is_attribute
// is true, the text is meant to appear as an attribute value, and
// normalizable whitespace is preserved by replacing it with character
// references.
//
// Invalid XML characters in str, if any, are stripped from the output.
// It is expected that most, if not all, of the text processed by this
// module will consist of ordinary English text.
// If this module is ever modified to produce version 1.1 XML output,
// most invalid characters can be retained using character references.
// TODO(wan): It might be nice to have a minimally invasive, human-readable
// escaping scheme for invalid characters, rather than dropping them.
std::string XmlUnitTestResultPrinter::EscapeXml(
    const std::string& str, bool is_attribute) {
  Message m;

  for (size_t i = 0; i < str.size(); ++i) {
    const char ch = str[i];
    switch (ch) {
      case '<':
        m << "&lt;";
        break;
      case '>':
        m << "&gt;";
        break;
      case '&':
        m << "&amp;";
        break;
      case '\'':
        if (is_attribute)
          m << "&apos;";
        else
          m << '\'';
        break;
      case '"':
        if (is_attribute)
          m << "&quot;";
        else
          m << '"';
        break;
      default:
        if (IsValidXmlCharacter(ch)) {
          if (is_attribute && IsNormalizableWhitespace(ch))
            m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
              << ";";
          else
            m << ch;
        }
        break;
    }
  }

  return m.GetString();
}

// Returns the given string with all characters invalid in XML removed.
// Currently invalid characters are dropped from the string. An
// alternative is to replace them with certain characters such as . or ?.
std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
    const std::string& str) {
  std::string output;
  output.reserve(str.size());
  for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
    if (IsValidXmlCharacter(*it))
      output.push_back(*it);

  return output;
}

// The following routines generate an XML representation of a UnitTest
// object.
//
// This is how Google Test concepts map to the DTD:
//
// <testsuites name="AllTests">        <-- corresponds to a UnitTest object
//   <testsuite name="testcase-name">  <-- corresponds to a TestCase object
//     <testcase name="test-name">     <-- corresponds to a TestInfo object
//       <failure message="...">...</failure>
//       <failure message="...">...</failure>
//       <failure message="...">...</failure>
//                                     <-- individual assertion failures
//     </testcase>
//   </testsuite>
// </testsuites>

// Formats the given time in milliseconds as seconds.
std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
  ::std::stringstream ss;
  ss << ms/1000.0;
  return ss.str();
}

// Converts the given epoch time in milliseconds to a date string in the ISO
// 8601 format, without the timezone information.
std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
  // Using non-reentrant version as localtime_r is not portable.
  time_t seconds = static_cast<time_t>(ms / 1000);
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4996)  // Temporarily disables warning 4996
                                // (function or variable may be unsafe).
  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
# pragma warning(pop)           // Restores the warning state again.
#else
  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
#endif
  if (time_struct == NULL)
    return "";  // Invalid ms value

  // YYYY-MM-DDThh:mm:ss
  return StreamableToString(time_struct->tm_year + 1900) + "-" +
      String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
      String::FormatIntWidth2(time_struct->tm_mday) + "T" +
      String::FormatIntWidth2(time_struct->tm_hour) + ":" +
      String::FormatIntWidth2(time_struct->tm_min) + ":" +
      String::FormatIntWidth2(time_struct->tm_sec);
}

// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
                                                     const char* data) {
  const char* segment = data;
  *stream << "<![CDATA[";
  for (;;) {
    const char* const next_segment = strstr(segment, "]]>");
    if (next_segment != NULL) {
      stream->write(
          segment, static_cast<std::streamsize>(next_segment - segment));
      *stream << "]]>]]&gt;<![CDATA[";
      segment = next_segment + strlen("]]>");
    } else {
      *stream << segment;
      break;
    }
  }
  *stream << "]]>";
}

void XmlUnitTestResultPrinter::OutputXmlAttribute(
    std::ostream* stream,
    const std::string& element_name,
    const std::string& name,
    const std::string& value) {
  const std::vector<std::string>& allowed_names =
      GetReservedAttributesForElement(element_name);

  GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
                   allowed_names.end())
      << "Attribute " << name << " is not allowed for element <" << element_name
      << ">.";

  *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
}

// Prints an XML representation of a TestInfo object.
// TODO(wan): There is also value in printing properties with the plain printer.
void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
                                                 const char* test_case_name,
                                                 const TestInfo& test_info) {
  const TestResult& result = *test_info.result();
  const std::string kTestcase = "testcase";

  *stream << "    <testcase";
  OutputXmlAttribute(stream, kTestcase, "name", test_info.name());

  if (test_info.value_param() != NULL) {
    OutputXmlAttribute(stream, kTestcase, "value_param",
                       test_info.value_param());
  }
  if (test_info.type_param() != NULL) {
    OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
  }

  OutputXmlAttribute(stream, kTestcase, "status",
                     test_info.should_run() ? "run" : "notrun");
  OutputXmlAttribute(stream, kTestcase, "time",
                     FormatTimeInMillisAsSeconds(result.elapsed_time()));
  OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
  *stream << TestPropertiesAsXmlAttributes(result);

  int failures = 0;
  for (int i = 0; i < result.total_part_count(); ++i) {
    const TestPartResult& part = result.GetTestPartResult(i);
    if (part.failed()) {
      if (++failures == 1) {
        *stream << ">\n";
      }
      const string location = internal::FormatCompilerIndependentFileLocation(
          part.file_name(), part.line_number());
      const string summary = location + "\n" + part.summary();
      *stream << "      <failure message=\""
              << EscapeXmlAttribute(summary.c_str())
              << "\" type=\"\">";
      const string detail = location + "\n" + part.message();
      OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
      *stream << "</failure>\n";
    }
  }

  if (failures == 0)
    *stream << " />\n";
  else
    *stream << "    </testcase>\n";
}

// Prints an XML representation of a TestCase object
void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
                                                const TestCase& test_case) {
  const std::string kTestsuite = "testsuite";
  *stream << "  <" << kTestsuite;
  OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
  OutputXmlAttribute(stream, kTestsuite, "tests",
                     StreamableToString(test_case.reportable_test_count()));
  OutputXmlAttribute(stream, kTestsuite, "failures",
                     StreamableToString(test_case.failed_test_count()));
  OutputXmlAttribute(
      stream, kTestsuite, "disabled",
      StreamableToString(test_case.reportable_disabled_test_count()));
  OutputXmlAttribute(stream, kTestsuite, "errors", "0");
  OutputXmlAttribute(stream, kTestsuite, "time",
                     FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
  *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
          << ">\n";

  for (int i = 0; i < test_case.total_test_count(); ++i) {
    if (test_case.GetTestInfo(i)->is_reportable())
      OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
  }
  *stream << "  </" << kTestsuite << ">\n";
}

// Prints an XML summary of unit_test to output stream out.
void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
                                                const UnitTest& unit_test) {
  const std::string kTestsuites = "testsuites";

  *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
  *stream << "<" << kTestsuites;

  OutputXmlAttribute(stream, kTestsuites, "tests",
                     StreamableToString(unit_test.reportable_test_count()));
  OutputXmlAttribute(stream, kTestsuites, "failures",
                     StreamableToString(unit_test.failed_test_count()));
  OutputXmlAttribute(
      stream, kTestsuites, "disabled",
      StreamableToString(unit_test.reportable_disabled_test_count()));
  OutputXmlAttribute(stream, kTestsuites, "errors", "0");
  OutputXmlAttribute(
      stream, kTestsuites, "timestamp",
      FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
  OutputXmlAttribute(stream, kTestsuites, "time",
                     FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));

  if (GTEST_FLAG(shuffle)) {
    OutputXmlAttribute(stream, kTestsuites, "random_seed",
                       StreamableToString(unit_test.random_seed()));
  }

  *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());

  OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
  *stream << ">\n";

  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
    if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
      PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
  }
  *stream << "</" << kTestsuites << ">\n";
}

// Produces a string representing the test properties in a result as space
// delimited XML attributes based on the property key="value" pairs.
std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
    const TestResult& result) {
  Message attributes;
  for (int i = 0; i < result.test_property_count(); ++i) {
    const TestProperty& property = result.GetTestProperty(i);
    attributes << " " << property.key() << "="
        << "\"" << EscapeXmlAttribute(property.value()) << "\"";
  }
  return attributes.GetString();
}

// End XmlUnitTestResultPrinter

#if GTEST_CAN_STREAM_RESULTS_

// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
// replaces them by "%xx" where xx is their hexadecimal value. For
// example, replaces "=" with "%3D".  This algorithm is O(strlen(str))
// in both time and space -- important as the input str may contain an
// arbitrarily long test failure message and stack trace.
string StreamingListener::UrlEncode(const char* str) {
  string result;
  result.reserve(strlen(str) + 1);
  for (char ch = *str; ch != '\0'; ch = *++str) {
    switch (ch) {
      case '%':
      case '=':
      case '&':
      case '\n':
        result.append("%" + String::FormatByte(static_cast<unsigned char>(ch)));
        break;
      default:
        result.push_back(ch);
        break;
    }
  }
  return result;
}

void StreamingListener::SocketWriter::MakeConnection() {
  GTEST_CHECK_(sockfd_ == -1)
      << "MakeConnection() can't be called when there is already a connection.";

  addrinfo hints;
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;    // To allow both IPv4 and IPv6 addresses.
  hints.ai_socktype = SOCK_STREAM;
  addrinfo* servinfo = NULL;

  // Use the getaddrinfo() to get a linked list of IP addresses for
  // the given host name.
  const int error_num = getaddrinfo(
      host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
  if (error_num != 0) {
    GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
                        << gai_strerror(error_num);
  }

  // Loop through all the results and connect to the first we can.
  for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
       cur_addr = cur_addr->ai_next) {
    sockfd_ = socket(
        cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
    if (sockfd_ != -1) {
      // Connect the client socket to the server socket.
      if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
        close(sockfd_);
        sockfd_ = -1;
      }
    }
  }

  freeaddrinfo(servinfo);  // all done with this structure

  if (sockfd_ == -1) {
    GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
                        << host_name_ << ":" << port_num_;
  }
}

// End of class Streaming Listener
#endif  // GTEST_CAN_STREAM_RESULTS__

// Class ScopedTrace

// Pushes the given source file location and message onto a per-thread
// trace stack maintained by Google Test.
ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
  TraceInfo trace;
  trace.file = file;
  trace.line = line;
  trace.message = message.GetString();

  UnitTest::GetInstance()->PushGTestTrace(trace);
}

// Pops the info pushed by the c'tor.
ScopedTrace::~ScopedTrace()
    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
  UnitTest::GetInstance()->PopGTestTrace();
}


// class OsStackTraceGetter

// Returns the current OS stack trace as an std::string.  Parameters:
//
//   max_depth  - the maximum number of stack frames to be included
//                in the trace.
//   skip_count - the number of top frames to be skipped; doesn't count
//                against max_depth.
//
string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
                                             int /* skip_count */)
    GTEST_LOCK_EXCLUDED_(mutex_) {
  return "";
}

void OsStackTraceGetter::UponLeavingGTest()
    GTEST_LOCK_EXCLUDED_(mutex_) {
}

const char* const
OsStackTraceGetter::kElidedFramesMarker =
    "... " GTEST_NAME_ " internal frames ...";

// A helper class that creates the premature-exit file in its
// constructor and deletes the file in its destructor.
class ScopedPrematureExitFile {
 public:
  explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
      : premature_exit_filepath_(premature_exit_filepath) {
    // If a path to the premature-exit file is specified...
    if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') {
      // create the file with a single "0" character in it.  I/O
      // errors are ignored as there's nothing better we can do and we
      // don't want to fail the test because of this.
      FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
      fwrite("0", 1, 1, pfile);
      fclose(pfile);
    }
  }

  ~ScopedPrematureExitFile() {
    if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') {
      remove(premature_exit_filepath_);
    }
  }

 private:
  const char* const premature_exit_filepath_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
};

}  // namespace internal

// class TestEventListeners

TestEventListeners::TestEventListeners()
    : repeater_(new internal::TestEventRepeater()),
      default_result_printer_(NULL),
      default_xml_generator_(NULL) {
}

TestEventListeners::~TestEventListeners() { delete repeater_; }

// Returns the standard listener responsible for the default console
// output.  Can be removed from the listeners list to shut down default
// console output.  Note that removing this object from the listener list
// with Release transfers its ownership to the user.
void TestEventListeners::Append(TestEventListener* listener) {
  repeater_->Append(listener);
}

// Removes the given event listener from the list and returns it.  It then
// becomes the caller's responsibility to delete the listener. Returns
// NULL if the listener is not found in the list.
TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
  if (listener == default_result_printer_)
    default_result_printer_ = NULL;
  else if (listener == default_xml_generator_)
    default_xml_generator_ = NULL;
  return repeater_->Release(listener);
}

// Returns repeater that broadcasts the TestEventListener events to all
// subscribers.
TestEventListener* TestEventListeners::repeater() { return repeater_; }

// Sets the default_result_printer attribute to the provided listener.
// The listener is also added to the listener list and previous
// default_result_printer is removed from it and deleted. The listener can
// also be NULL in which case it will not be added to the list. Does
// nothing if the previous and the current listener objects are the same.
void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
  if (default_result_printer_ != listener) {
    // It is an error to pass this method a listener that is already in the
    // list.
    delete Release(default_result_printer_);
    default_result_printer_ = listener;
    if (listener != NULL)
      Append(listener);
  }
}

// Sets the default_xml_generator attribute to the provided listener.  The
// listener is also added to the listener list and previous
// default_xml_generator is removed from it and deleted. The listener can
// also be NULL in which case it will not be added to the list. Does
// nothing if the previous and the current listener objects are the same.
void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
  if (default_xml_generator_ != listener) {
    // It is an error to pass this method a listener that is already in the
    // list.
    delete Release(default_xml_generator_);
    default_xml_generator_ = listener;
    if (listener != NULL)
      Append(listener);
  }
}

// Controls whether events will be forwarded by the repeater to the
// listeners in the list.
bool TestEventListeners::EventForwardingEnabled() const {
  return repeater_->forwarding_enabled();
}

void TestEventListeners::SuppressEventForwarding() {
  repeater_->set_forwarding_enabled(false);
}

// class UnitTest

// Gets the singleton UnitTest object.  The first time this method is
// called, a UnitTest object is constructed and returned.  Consecutive
// calls will return the same object.
//
// We don't protect this under mutex_ as a user is not supposed to
// call this before main() starts, from which point on the return
// value will never change.
UnitTest* UnitTest::GetInstance() {
  // When compiled with MSVC 7.1 in optimized mode, destroying the
  // UnitTest object upon exiting the program messes up the exit code,
  // causing successful tests to appear failed.  We have to use a
  // different implementation in this case to bypass the compiler bug.
  // This implementation makes the compiler happy, at the cost of
  // leaking the UnitTest object.

  // CodeGear C++Builder insists on a public destructor for the
  // default implementation.  Use this implementation to keep good OO
  // design with private destructor.

#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
  static UnitTest* const instance = new UnitTest;
  return instance;
#else
  static UnitTest instance;
  return &instance;
#endif  // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
}

// Gets the number of successful test cases.
int UnitTest::successful_test_case_count() const {
  return impl()->successful_test_case_count();
}

// Gets the number of failed test cases.
int UnitTest::failed_test_case_count() const {
  return impl()->failed_test_case_count();
}

// Gets the number of all test cases.
int UnitTest::total_test_case_count() const {
  return impl()->total_test_case_count();
}

// Gets the number of all test cases that contain at least one test
// that should run.
int UnitTest::test_case_to_run_count() const {
  return impl()->test_case_to_run_count();
}

// Gets the number of successful tests.
int UnitTest::successful_test_count() const {
  return impl()->successful_test_count();
}

// Gets the number of failed tests.
int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }

// Gets the number of disabled tests that will be reported in the XML report.
int UnitTest::reportable_disabled_test_count() const {
  return impl()->reportable_disabled_test_count();
}

// Gets the number of disabled tests.
int UnitTest::disabled_test_count() const {
  return impl()->disabled_test_count();
}

// Gets the number of tests to be printed in the XML report.
int UnitTest::reportable_test_count() const {
  return impl()->reportable_test_count();
}

// Gets the number of all tests.
int UnitTest::total_test_count() const { return impl()->total_test_count(); }

// Gets the number of tests that should run.
int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }

// Gets the time of the test program start, in ms from the start of the
// UNIX epoch.
internal::TimeInMillis UnitTest::start_timestamp() const {
    return impl()->start_timestamp();
}

// Gets the elapsed time, in milliseconds.
internal::TimeInMillis UnitTest::elapsed_time() const {
  return impl()->elapsed_time();
}

// Returns true iff the unit test passed (i.e. all test cases passed).
bool UnitTest::Passed() const { return impl()->Passed(); }

// Returns true iff the unit test failed (i.e. some test case failed
// or something outside of all tests failed).
bool UnitTest::Failed() const { return impl()->Failed(); }

// Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL.
const TestCase* UnitTest::GetTestCase(int i) const {
  return impl()->GetTestCase(i);
}

// Returns the TestResult containing information on test failures and
// properties logged outside of individual test cases.
const TestResult& UnitTest::ad_hoc_test_result() const {
  return *impl()->ad_hoc_test_result();
}

// Gets the i-th test case among all the test cases. i can range from 0 to
// total_test_case_count() - 1. If i is not in that range, returns NULL.
TestCase* UnitTest::GetMutableTestCase(int i) {
  return impl()->GetMutableTestCase(i);
}

// Returns the list of event listeners that can be used to track events
// inside Google Test.
TestEventListeners& UnitTest::listeners() {
  return *impl()->listeners();
}

// Registers and returns a global test environment.  When a test
// program is run, all global test environments will be set-up in the
// order they were registered.  After all tests in the program have
// finished, all global test environments will be torn-down in the
// *reverse* order they were registered.
//
// The UnitTest object takes ownership of the given environment.
//
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
Environment* UnitTest::AddEnvironment(Environment* env) {
  if (env == NULL) {
    return NULL;
  }

  impl_->environments().push_back(env);
  return env;
}

// Adds a TestPartResult to the current TestResult object.  All Google Test
// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
// this to report their results.  The user code should use the
// assertion macros instead of calling this directly.
void UnitTest::AddTestPartResult(
    TestPartResult::Type result_type,
    const char* file_name,
    int line_number,
    const std::string& message,
    const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) {
  Message msg;
  msg << message;

  internal::MutexLock lock(&mutex_);
  if (impl_->gtest_trace_stack().size() > 0) {
    msg << "\n" << GTEST_NAME_ << " trace:";

    for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
         i > 0; --i) {
      const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
      msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
          << " " << trace.message;
    }
  }

  if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
    msg << internal::kStackTraceMarker << os_stack_trace;
  }

  const TestPartResult result =
    TestPartResult(result_type, file_name, line_number,
                   msg.GetString().c_str());
  impl_->GetTestPartResultReporterForCurrentThread()->
      ReportTestPartResult(result);

  if (result_type != TestPartResult::kSuccess) {
    // gtest_break_on_failure takes precedence over
    // gtest_throw_on_failure.  This allows a user to set the latter
    // in the code (perhaps in order to use Google Test assertions
    // with another testing framework) and specify the former on the
    // command line for debugging.
    if (GTEST_FLAG(break_on_failure)) {
#if GTEST_OS_WINDOWS
      // Using DebugBreak on Windows allows gtest to still break into a debugger
      // when a failure happens and both the --gtest_break_on_failure and
      // the --gtest_catch_exceptions flags are specified.
      DebugBreak();
#else
      // Dereference NULL through a volatile pointer to prevent the compiler
      // from removing. We use this rather than abort() or __builtin_trap() for
      // portability: Symbian doesn't implement abort() well, and some debuggers
      // don't correctly trap abort().
      *static_cast<volatile int*>(NULL) = 1;
#endif  // GTEST_OS_WINDOWS
    } else if (GTEST_FLAG(throw_on_failure)) {
#if GTEST_HAS_EXCEPTIONS
      throw internal::GoogleTestFailureException(result);
#else
      // We cannot call abort() as it generates a pop-up in debug mode
      // that cannot be suppressed in VC 7.1 or below.
      exit(1);
#endif
    }
  }
}

// Adds a TestProperty to the current TestResult object when invoked from
// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
// from SetUpTestCase or TearDownTestCase, or to the global property set
// when invoked elsewhere.  If the result already contains a property with
// the same key, the value will be updated.
void UnitTest::RecordProperty(const std::string& key,
                              const std::string& value) {
  impl_->RecordProperty(TestProperty(key, value));
}

// Runs all tests in this UnitTest object and prints the result.
// Returns 0 if successful, or 1 otherwise.
//
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
int UnitTest::Run() {
  const bool in_death_test_child_process =
      internal::GTEST_FLAG(internal_run_death_test).length() > 0;

  // Google Test implements this protocol for catching that a test
  // program exits before returning control to Google Test:
  //
  //   1. Upon start, Google Test creates a file whose absolute path
  //      is specified by the environment variable
  //      TEST_PREMATURE_EXIT_FILE.
  //   2. When Google Test has finished its work, it deletes the file.
  //
  // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
  // running a Google-Test-based test program and check the existence
  // of the file at the end of the test execution to see if it has
  // exited prematurely.

  // If we are in the child process of a death test, don't
  // create/delete the premature exit file, as doing so is unnecessary
  // and will confuse the parent process.  Otherwise, create/delete
  // the file upon entering/leaving this function.  If the program
  // somehow exits before this function has a chance to return, the
  // premature-exit file will be left undeleted, causing a test runner
  // that understands the premature-exit-file protocol to report the
  // test as having failed.
  const internal::ScopedPrematureExitFile premature_exit_file(
      in_death_test_child_process ?
      NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));

  // Captures the value of GTEST_FLAG(catch_exceptions).  This value will be
  // used for the duration of the program.
  impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));

#if GTEST_HAS_SEH
  // Either the user wants Google Test to catch exceptions thrown by the
  // tests or this is executing in the context of death test child
  // process. In either case the user does not want to see pop-up dialogs
  // about crashes - they are expected.
  if (impl()->catch_exceptions() || in_death_test_child_process) {
# if !GTEST_OS_WINDOWS_MOBILE
    // SetErrorMode doesn't exist on CE.
    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
# endif  // !GTEST_OS_WINDOWS_MOBILE

# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
    // Death test children can be terminated with _abort().  On Windows,
    // _abort() can show a dialog with a warning message.  This forces the
    // abort message to go to stderr instead.
    _set_error_mode(_OUT_TO_STDERR);
# endif

# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
    // In the debug version, Visual Studio pops up a separate dialog
    // offering a choice to debug the aborted program. We need to suppress
    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
    // executed. Google Test will notify the user of any unexpected
    // failure via stderr.
    //
    // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
    // Users of prior VC versions shall suffer the agony and pain of
    // clicking through the countless debug dialogs.
    // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
    // debug mode when compiled with VC 7.1 or lower.
    if (!GTEST_FLAG(break_on_failure))
      _set_abort_behavior(
          0x0,                                    // Clear the following flags:
          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
# endif
  }
#endif  // GTEST_HAS_SEH

  return internal::HandleExceptionsInMethodIfSupported(
      impl(),
      &internal::UnitTestImpl::RunAllTests,
      "auxiliary test code (environments or event listeners)") ? 0 : 1;
}

// Returns the working directory when the first TEST() or TEST_F() was
// executed.
const char* UnitTest::original_working_dir() const {
  return impl_->original_working_dir_.c_str();
}

// Returns the TestCase object for the test that's currently running,
// or NULL if no test is running.
const TestCase* UnitTest::current_test_case() const
    GTEST_LOCK_EXCLUDED_(mutex_) {
  internal::MutexLock lock(&mutex_);
  return impl_->current_test_case();
}

// Returns the TestInfo object for the test that's currently running,
// or NULL if no test is running.
const TestInfo* UnitTest::current_test_info() const
    GTEST_LOCK_EXCLUDED_(mutex_) {
  internal::MutexLock lock(&mutex_);
  return impl_->current_test_info();
}

// Returns the random seed used at the start of the current test run.
int UnitTest::random_seed() const { return impl_->random_seed(); }

#if GTEST_HAS_PARAM_TEST
// Returns ParameterizedTestCaseRegistry object used to keep track of
// value-parameterized tests and instantiate and register them.
internal::ParameterizedTestCaseRegistry&
    UnitTest::parameterized_test_registry()
        GTEST_LOCK_EXCLUDED_(mutex_) {
  return impl_->parameterized_test_registry();
}
#endif  // GTEST_HAS_PARAM_TEST

// Creates an empty UnitTest.
UnitTest::UnitTest() {
  impl_ = new internal::UnitTestImpl(this);
}

// Destructor of UnitTest.
UnitTest::~UnitTest() {
  delete impl_;
}

// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
// Google Test trace stack.
void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
    GTEST_LOCK_EXCLUDED_(mutex_) {
  internal::MutexLock lock(&mutex_);
  impl_->gtest_trace_stack().push_back(trace);
}

// Pops a trace from the per-thread Google Test trace stack.
void UnitTest::PopGTestTrace()
    GTEST_LOCK_EXCLUDED_(mutex_) {
  internal::MutexLock lock(&mutex_);
  impl_->gtest_trace_stack().pop_back();
}

namespace internal {

UnitTestImpl::UnitTestImpl(UnitTest* parent)
    : parent_(parent),
#ifdef _MSC_VER
# pragma warning(push)                    // Saves the current warning state.
# pragma warning(disable:4355)            // Temporarily disables warning 4355
                                         // (using this in initializer).
      default_global_test_part_result_reporter_(this),
      default_per_thread_test_part_result_reporter_(this),
# pragma warning(pop)                     // Restores the warning state again.
#else
      default_global_test_part_result_reporter_(this),
      default_per_thread_test_part_result_reporter_(this),
#endif  // _MSC_VER
      global_test_part_result_repoter_(
          &default_global_test_part_result_reporter_),
      per_thread_test_part_result_reporter_(
          &default_per_thread_test_part_result_reporter_),
#if GTEST_HAS_PARAM_TEST
      parameterized_test_registry_(),
      parameterized_tests_registered_(false),
#endif  // GTEST_HAS_PARAM_TEST
      last_death_test_case_(-1),
      current_test_case_(NULL),
      current_test_info_(NULL),
      ad_hoc_test_result_(),
      os_stack_trace_getter_(NULL),
      post_flag_parse_init_performed_(false),
      random_seed_(0),  // Will be overridden by the flag before first use.
      random_(0),  // Will be reseeded before first use.
      start_timestamp_(0),
      elapsed_time_(0),
#if GTEST_HAS_DEATH_TEST
      death_test_factory_(new DefaultDeathTestFactory),
#endif
      // Will be overridden by the flag before first use.
      catch_exceptions_(false) {
  listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
}

UnitTestImpl::~UnitTestImpl() {
  // Deletes every TestCase.
  ForEach(test_cases_, internal::Delete<TestCase>);

  // Deletes every Environment.
  ForEach(environments_, internal::Delete<Environment>);

  delete os_stack_trace_getter_;
}

// Adds a TestProperty to the current TestResult object when invoked in a
// context of a test, to current test case's ad_hoc_test_result when invoke
// from SetUpTestCase/TearDownTestCase, or to the global property set
// otherwise.  If the result already contains a property with the same key,
// the value will be updated.
void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
  std::string xml_element;
  TestResult* test_result;  // TestResult appropriate for property recording.

  if (current_test_info_ != NULL) {
    xml_element = "testcase";
    test_result = &(current_test_info_->result_);
  } else if (current_test_case_ != NULL) {
    xml_element = "testsuite";
    test_result = &(current_test_case_->ad_hoc_test_result_);
  } else {
    xml_element = "testsuites";
    test_result = &ad_hoc_test_result_;
  }
  test_result->RecordProperty(xml_element, test_property);
}

#if GTEST_HAS_DEATH_TEST
// Disables event forwarding if the control is currently in a death test
// subprocess. Must not be called before InitGoogleTest.
void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
  if (internal_run_death_test_flag_.get() != NULL)
    listeners()->SuppressEventForwarding();
}
#endif  // GTEST_HAS_DEATH_TEST

// Initializes event listeners performing XML output as specified by
// UnitTestOptions. Must not be called before InitGoogleTest.
void UnitTestImpl::ConfigureXmlOutput() {
  const std::string& output_format = UnitTestOptions::GetOutputFormat();
  if (output_format == "xml") {
    listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
        UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
  } else if (output_format != "") {
    printf("WARNING: unrecognized output format \"%s\" ignored.\n",
           output_format.c_str());
    fflush(stdout);
  }
}

#if GTEST_CAN_STREAM_RESULTS_
// Initializes event listeners for streaming test results in string form.
// Must not be called before InitGoogleTest.
void UnitTestImpl::ConfigureStreamingOutput() {
  const std::string& target = GTEST_FLAG(stream_result_to);
  if (!target.empty()) {
    const size_t pos = target.find(':');
    if (pos != std::string::npos) {
      listeners()->Append(new StreamingListener(target.substr(0, pos),
                                                target.substr(pos+1)));
    } else {
      printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
             target.c_str());
      fflush(stdout);
    }
  }
}
#endif  // GTEST_CAN_STREAM_RESULTS_

// Performs initialization dependent upon flag values obtained in
// ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
// ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
// this function is also called from RunAllTests.  Since this function can be
// called more than once, it has to be idempotent.
void UnitTestImpl::PostFlagParsingInit() {
  // Ensures that this function does not execute more than once.
  if (!post_flag_parse_init_performed_) {
    post_flag_parse_init_performed_ = true;

#if GTEST_HAS_DEATH_TEST
    InitDeathTestSubprocessControlInfo();
    SuppressTestEventsIfInSubprocess();
#endif  // GTEST_HAS_DEATH_TEST

    // Registers parameterized tests. This makes parameterized tests
    // available to the UnitTest reflection API without running
    // RUN_ALL_TESTS.
    RegisterParameterizedTests();

    // Configures listeners for XML output. This makes it possible for users
    // to shut down the default XML output before invoking RUN_ALL_TESTS.
    ConfigureXmlOutput();

#if GTEST_CAN_STREAM_RESULTS_
    // Configures listeners for streaming test results to the specified server.
    ConfigureStreamingOutput();
#endif  // GTEST_CAN_STREAM_RESULTS_
  }
}

// A predicate that checks the name of a TestCase against a known
// value.
//
// This is used for implementation of the UnitTest class only.  We put
// it in the anonymous namespace to prevent polluting the outer
// namespace.
//
// TestCaseNameIs is copyable.
class TestCaseNameIs {
 public:
  // Constructor.
  explicit TestCaseNameIs(const std::string& name)
      : name_(name) {}

  // Returns true iff the name of test_case matches name_.
  bool operator()(const TestCase* test_case) const {
    return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
  }

 private:
  std::string name_;
};

// Finds and returns a TestCase with the given name.  If one doesn't
// exist, creates one and returns it.  It's the CALLER'S
// RESPONSIBILITY to ensure that this function is only called WHEN THE
// TESTS ARE NOT SHUFFLED.
//
// Arguments:
//
//   test_case_name: name of the test case
//   type_param:     the name of the test case's type parameter, or NULL if
//                   this is not a typed or a type-parameterized test case.
//   set_up_tc:      pointer to the function that sets up the test case
//   tear_down_tc:   pointer to the function that tears down the test case
TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
                                    const char* type_param,
                                    Test::SetUpTestCaseFunc set_up_tc,
                                    Test::TearDownTestCaseFunc tear_down_tc) {
  // Can we find a TestCase with the given name?
  const std::vector<TestCase*>::const_iterator test_case =
      std::find_if(test_cases_.begin(), test_cases_.end(),
                   TestCaseNameIs(test_case_name));

  if (test_case != test_cases_.end())
    return *test_case;

  // No.  Let's create one.
  TestCase* const new_test_case =
      new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);

  // Is this a death test case?
  if (internal::UnitTestOptions::MatchesFilter(test_case_name,
                                               kDeathTestCaseFilter)) {
    // Yes.  Inserts the test case after the last death test case
    // defined so far.  This only works when the test cases haven't
    // been shuffled.  Otherwise we may end up running a death test
    // after a non-death test.
    ++last_death_test_case_;
    test_cases_.insert(test_cases_.begin() + last_death_test_case_,
                       new_test_case);
  } else {
    // No.  Appends to the end of the list.
    test_cases_.push_back(new_test_case);
  }

  test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
  return new_test_case;
}

// Helpers for setting up / tearing down the given environment.  They
// are for use in the ForEach() function.
static void SetUpEnvironment(Environment* env) { env->SetUp(); }
static void TearDownEnvironment(Environment* env) { env->TearDown(); }

// Runs all tests in this UnitTest object, prints the result, and
// returns true if all tests are successful.  If any exception is
// thrown during a test, the test is considered to be failed, but the
// rest of the tests will still be run.
//
// When parameterized tests are enabled, it expands and registers
// parameterized tests first in RegisterParameterizedTests().
// All other functions called from RunAllTests() may safely assume that
// parameterized tests are ready to be counted and run.
bool UnitTestImpl::RunAllTests() {
  // Makes sure InitGoogleTest() was called.
  if (!GTestIsInitialized()) {
    printf("%s",
           "\nThis test program did NOT call ::testing::InitGoogleTest "
           "before calling RUN_ALL_TESTS().  Please fix it.\n");
    return false;
  }

  // Do not run any test if the --help flag was specified.
  if (g_help_flag)
    return true;

  // Repeats the call to the post-flag parsing initialization in case the
  // user didn't call InitGoogleTest.
  PostFlagParsingInit();

  // Even if sharding is not on, test runners may want to use the
  // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
  // protocol.
  internal::WriteToShardStatusFileIfNeeded();

  // True iff we are in a subprocess for running a thread-safe-style
  // death test.
  bool in_subprocess_for_death_test = false;

#if GTEST_HAS_DEATH_TEST
  in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
#endif  // GTEST_HAS_DEATH_TEST

  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
                                        in_subprocess_for_death_test);

  // Compares the full test names with the filter to decide which
  // tests to run.
  const bool has_tests_to_run = FilterTests(should_shard
                                              ? HONOR_SHARDING_PROTOCOL
                                              : IGNORE_SHARDING_PROTOCOL) > 0;

  // Lists the tests and exits if the --gtest_list_tests flag was specified.
  if (GTEST_FLAG(list_tests)) {
    // This must be called *after* FilterTests() has been called.
    ListTestsMatchingFilter();
    return true;
  }

  random_seed_ = GTEST_FLAG(shuffle) ?
      GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;

  // True iff at least one test has failed.
  bool failed = false;

  TestEventListener* repeater = listeners()->repeater();

  start_timestamp_ = GetTimeInMillis();
  repeater->OnTestProgramStart(*parent_);

  // How many times to repeat the tests?  We don't want to repeat them
  // when we are inside the subprocess of a death test.
  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
  // Repeats forever if the repeat count is negative.
  const bool forever = repeat < 0;
  for (int i = 0; forever || i != repeat; i++) {
    // We want to preserve failures generated by ad-hoc test
    // assertions executed before RUN_ALL_TESTS().
    ClearNonAdHocTestResult();

    const TimeInMillis start = GetTimeInMillis();

    // Shuffles test cases and tests if requested.
    if (has_tests_to_run && GTEST_FLAG(shuffle)) {
      random()->Reseed(random_seed_);
      // This should be done before calling OnTestIterationStart(),
      // such that a test event listener can see the actual test order
      // in the event.
      ShuffleTests();
    }

    // Tells the unit test event listeners that the tests are about to start.
    repeater->OnTestIterationStart(*parent_, i);

    // Runs each test case if there is at least one test to run.
    if (has_tests_to_run) {
      // Sets up all environments beforehand.
      repeater->OnEnvironmentsSetUpStart(*parent_);
      ForEach(environments_, SetUpEnvironment);
      repeater->OnEnvironmentsSetUpEnd(*parent_);

      // Runs the tests only if there was no fatal failure during global
      // set-up.
      if (!Test::HasFatalFailure()) {
        for (int test_index = 0; test_index < total_test_case_count();
             test_index++) {
          GetMutableTestCase(test_index)->Run();
        }
      }

      // Tears down all environments in reverse order afterwards.
      repeater->OnEnvironmentsTearDownStart(*parent_);
      std::for_each(environments_.rbegin(), environments_.rend(),
                    TearDownEnvironment);
      repeater->OnEnvironmentsTearDownEnd(*parent_);
    }

    elapsed_time_ = GetTimeInMillis() - start;

    // Tells the unit test event listener that the tests have just finished.
    repeater->OnTestIterationEnd(*parent_, i);

    // Gets the result and clears it.
    if (!Passed()) {
      failed = true;
    }

    // Restores the original test order after the iteration.  This
    // allows the user to quickly repro a failure that happens in the
    // N-th iteration without repeating the first (N - 1) iterations.
    // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
    // case the user somehow changes the value of the flag somewhere
    // (it's always safe to unshuffle the tests).
    UnshuffleTests();

    if (GTEST_FLAG(shuffle)) {
      // Picks a new random seed for each iteration.
      random_seed_ = GetNextRandomSeed(random_seed_);
    }
  }

  repeater->OnTestProgramEnd(*parent_);

  return !failed;
}

// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
// if the variable is present. If a file already exists at this location, this
// function will write over it. If the variable is present, but the file cannot
// be created, prints an error and exits.
void WriteToShardStatusFileIfNeeded() {
  const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
  if (test_shard_file != NULL) {
    FILE* const file = posix::FOpen(test_shard_file, "w");
    if (file == NULL) {
      ColoredPrintf(COLOR_RED,
                    "Could not write to the test shard status file \"%s\" "
                    "specified by the %s environment variable.\n",
                    test_shard_file, kTestShardStatusFile);
      fflush(stdout);
      exit(EXIT_FAILURE);
    }
    fclose(file);
  }
}

// Checks whether sharding is enabled by examining the relevant
// environment variable values. If the variables are present,
// but inconsistent (i.e., shard_index >= total_shards), prints
// an error and exits. If in_subprocess_for_death_test, sharding is
// disabled because it must only be applied to the original test
// process. Otherwise, we could filter out death tests we intended to execute.
bool ShouldShard(const char* total_shards_env,
                 const char* shard_index_env,
                 bool in_subprocess_for_death_test) {
  if (in_subprocess_for_death_test) {
    return false;
  }

  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);

  if (total_shards == -1 && shard_index == -1) {
    return false;
  } else if (total_shards == -1 && shard_index != -1) {
    const Message msg = Message()
      << "Invalid environment variables: you have "
      << kTestShardIndex << " = " << shard_index
      << ", but have left " << kTestTotalShards << " unset.\n";
    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
    fflush(stdout);
    exit(EXIT_FAILURE);
  } else if (total_shards != -1 && shard_index == -1) {
    const Message msg = Message()
      << "Invalid environment variables: you have "
      << kTestTotalShards << " = " << total_shards
      << ", but have left " << kTestShardIndex << " unset.\n";
    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
    fflush(stdout);
    exit(EXIT_FAILURE);
  } else if (shard_index < 0 || shard_index >= total_shards) {
    const Message msg = Message()
      << "Invalid environment variables: we require 0 <= "
      << kTestShardIndex << " < " << kTestTotalShards
      << ", but you have " << kTestShardIndex << "=" << shard_index
      << ", " << kTestTotalShards << "=" << total_shards << ".\n";
    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
    fflush(stdout);
    exit(EXIT_FAILURE);
  }

  return total_shards > 1;
}

// Parses the environment variable var as an Int32. If it is unset,
// returns default_val. If it is not an Int32, prints an error
// and aborts.
Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
  const char* str_val = posix::GetEnv(var);
  if (str_val == NULL) {
    return default_val;
  }

  Int32 result;
  if (!ParseInt32(Message() << "The value of environment variable " << var,
                  str_val, &result)) {
    exit(EXIT_FAILURE);
  }
  return result;
}

// Given the total number of shards, the shard index, and the test id,
// returns true iff the test should be run on this shard. The test id is
// some arbitrary but unique non-negative integer assigned to each test
// method. Assumes that 0 <= shard_index < total_shards.
bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
  return (test_id % total_shards) == shard_index;
}

// Compares the name of each test with the user-specified filter to
// decide whether the test should be run, then records the result in
// each TestCase and TestInfo object.
// If shard_tests == true, further filters tests based on sharding
// variables in the environment - see
// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
// Returns the number of tests that should run.
int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
      Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
      Int32FromEnvOrDie(kTestShardIndex, -1) : -1;

  // num_runnable_tests are the number of tests that will
  // run across all shards (i.e., match filter and are not disabled).
  // num_selected_tests are the number of tests to be run on
  // this shard.
  int num_runnable_tests = 0;
  int num_selected_tests = 0;
  for (size_t i = 0; i < test_cases_.size(); i++) {
    TestCase* const test_case = test_cases_[i];
    const std::string &test_case_name = test_case->name();
    test_case->set_should_run(false);

    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
      TestInfo* const test_info = test_case->test_info_list()[j];
      const std::string test_name(test_info->name());
      // A test is disabled if test case name or test name matches
      // kDisableTestFilter.
      const bool is_disabled =
          internal::UnitTestOptions::MatchesFilter(test_case_name,
                                                   kDisableTestFilter) ||
          internal::UnitTestOptions::MatchesFilter(test_name,
                                                   kDisableTestFilter);
      test_info->is_disabled_ = is_disabled;

      const bool matches_filter =
          internal::UnitTestOptions::FilterMatchesTest(test_case_name,
                                                       test_name);
      test_info->matches_filter_ = matches_filter;

      const bool is_runnable =
          (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
          matches_filter;

      const bool is_selected = is_runnable &&
          (shard_tests == IGNORE_SHARDING_PROTOCOL ||
           ShouldRunTestOnShard(total_shards, shard_index,
                                num_runnable_tests));

      num_runnable_tests += is_runnable;
      num_selected_tests += is_selected;

      test_info->should_run_ = is_selected;
      test_case->set_should_run(test_case->should_run() || is_selected);
    }
  }
  return num_selected_tests;
}

// Prints the given C-string on a single line by replacing all '\n'
// characters with string "\\n".  If the output takes more than
// max_length characters, only prints the first max_length characters
// and "...".
static void PrintOnOneLine(const char* str, int max_length) {
  if (str != NULL) {
    for (int i = 0; *str != '\0'; ++str) {
      if (i >= max_length) {
        printf("...");
        break;
      }
      if (*str == '\n') {
        printf("\\n");
        i += 2;
      } else {
        printf("%c", *str);
        ++i;
      }
    }
  }
}

// Prints the names of the tests matching the user-specified filter flag.
void UnitTestImpl::ListTestsMatchingFilter() {
  // Print at most this many characters for each type/value parameter.
  const int kMaxParamLength = 250;

  for (size_t i = 0; i < test_cases_.size(); i++) {
    const TestCase* const test_case = test_cases_[i];
    bool printed_test_case_name = false;

    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
      const TestInfo* const test_info =
          test_case->test_info_list()[j];
      if (test_info->matches_filter_) {
        if (!printed_test_case_name) {
          printed_test_case_name = true;
          printf("%s.", test_case->name());
          if (test_case->type_param() != NULL) {
            printf("  # %s = ", kTypeParamLabel);
            // We print the type parameter on a single line to make
            // the output easy to parse by a program.
            PrintOnOneLine(test_case->type_param(), kMaxParamLength);
          }
          printf("\n");
        }
        printf("  %s", test_info->name());
        if (test_info->value_param() != NULL) {
          printf("  # %s = ", kValueParamLabel);
          // We print the value parameter on a single line to make the
          // output easy to parse by a program.
          PrintOnOneLine(test_info->value_param(), kMaxParamLength);
        }
        printf("\n");
      }
    }
  }
  fflush(stdout);
}

// Sets the OS stack trace getter.
//
// Does nothing if the input and the current OS stack trace getter are
// the same; otherwise, deletes the old getter and makes the input the
// current getter.
void UnitTestImpl::set_os_stack_trace_getter(
    OsStackTraceGetterInterface* getter) {
  if (os_stack_trace_getter_ != getter) {
    delete os_stack_trace_getter_;
    os_stack_trace_getter_ = getter;
  }
}

// Returns the current OS stack trace getter if it is not NULL;
// otherwise, creates an OsStackTraceGetter, makes it the current
// getter, and returns it.
OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
  if (os_stack_trace_getter_ == NULL) {
    os_stack_trace_getter_ = new OsStackTraceGetter;
  }

  return os_stack_trace_getter_;
}

// Returns the TestResult for the test that's currently running, or
// the TestResult for the ad hoc test if no test is running.
TestResult* UnitTestImpl::current_test_result() {
  return current_test_info_ ?
      &(current_test_info_->result_) : &ad_hoc_test_result_;
}

// Shuffles all test cases, and the tests within each test case,
// making sure that death tests are still run first.
void UnitTestImpl::ShuffleTests() {
  // Shuffles the death test cases.
  ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);

  // Shuffles the non-death test cases.
  ShuffleRange(random(), last_death_test_case_ + 1,
               static_cast<int>(test_cases_.size()), &test_case_indices_);

  // Shuffles the tests inside each test case.
  for (size_t i = 0; i < test_cases_.size(); i++) {
    test_cases_[i]->ShuffleTests(random());
  }
}

// Restores the test cases and tests to their order before the first shuffle.
void UnitTestImpl::UnshuffleTests() {
  for (size_t i = 0; i < test_cases_.size(); i++) {
    // Unshuffles the tests in each test case.
    test_cases_[i]->UnshuffleTests();
    // Resets the index of each test case.
    test_case_indices_[i] = static_cast<int>(i);
  }
}

// Returns the current OS stack trace as an std::string.
//
// The maximum number of stack frames to be included is specified by
// the gtest_stack_trace_depth flag.  The skip_count parameter
// specifies the number of top frames to be skipped, which doesn't
// count against the number of frames to be included.
//
// For example, if Foo() calls Bar(), which in turn calls
// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
                                            int skip_count) {
  // We pass skip_count + 1 to skip this wrapper function in addition
  // to what the user really wants to skip.
  return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
}

// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
// suppress unreachable code warnings.
namespace {
class ClassUniqueToAlwaysTrue {};
}

bool IsTrue(bool condition) { return condition; }

bool AlwaysTrue() {
#if GTEST_HAS_EXCEPTIONS
  // This condition is always false so AlwaysTrue() never actually throws,
  // but it makes the compiler think that it may throw.
  if (IsTrue(false))
    throw ClassUniqueToAlwaysTrue();
#endif  // GTEST_HAS_EXCEPTIONS
  return true;
}

// If *pstr starts with the given prefix, modifies *pstr to be right
// past the prefix and returns true; otherwise leaves *pstr unchanged
// and returns false.  None of pstr, *pstr, and prefix can be NULL.
bool SkipPrefix(const char* prefix, const char** pstr) {
  const size_t prefix_len = strlen(prefix);
  if (strncmp(*pstr, prefix, prefix_len) == 0) {
    *pstr += prefix_len;
    return true;
  }
  return false;
}

// Parses a string as a command line flag.  The string should have
// the format "--flag=value".  When def_optional is true, the "=value"
// part can be omitted.
//
// Returns the value of the flag, or NULL if the parsing failed.
const char* ParseFlagValue(const char* str,
                           const char* flag,
                           bool def_optional) {
  // str and flag must not be NULL.
  if (str == NULL || flag == NULL) return NULL;

  // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
  const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
  const size_t flag_len = flag_str.length();
  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;

  // Skips the flag name.
  const char* flag_end = str + flag_len;

  // When def_optional is true, it's OK to not have a "=value" part.
  if (def_optional && (flag_end[0] == '\0')) {
    return flag_end;
  }

  // If def_optional is true and there are more characters after the
  // flag name, or if def_optional is false, there must be a '=' after
  // the flag name.
  if (flag_end[0] != '=') return NULL;

  // Returns the string after "=".
  return flag_end + 1;
}

// Parses a string for a bool flag, in the form of either
// "--flag=value" or "--flag".
//
// In the former case, the value is taken as true as long as it does
// not start with '0', 'f', or 'F'.
//
// In the latter case, the value is taken as true.
//
// On success, stores the value of the flag in *value, and returns
// true.  On failure, returns false without changing *value.
bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
  // Gets the value of the flag as a string.
  const char* const value_str = ParseFlagValue(str, flag, true);

  // Aborts if the parsing failed.
  if (value_str == NULL) return false;

  // Converts the string value to a bool.
  *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
  return true;
}

// Parses a string for an Int32 flag, in the form of
// "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true.  On failure, returns false without changing *value.
bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
  // Gets the value of the flag as a string.
  const char* const value_str = ParseFlagValue(str, flag, false);

  // Aborts if the parsing failed.
  if (value_str == NULL) return false;

  // Sets *value to the value of the flag.
  return ParseInt32(Message() << "The value of flag --" << flag,
                    value_str, value);
}

// Parses a string for a string flag, in the form of
// "--flag=value".
//
// On success, stores the value of the flag in *value, and returns
// true.  On failure, returns false without changing *value.
bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
  // Gets the value of the flag as a string.
  const char* const value_str = ParseFlagValue(str, flag, false);

  // Aborts if the parsing failed.
  if (value_str == NULL) return false;

  // Sets *value to the value of the flag.
  *value = value_str;
  return true;
}

// Determines whether a string has a prefix that Google Test uses for its
// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
// If Google Test detects that a command line flag has its prefix but is not
// recognized, it will print its help message. Flags starting with
// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
// internal flags and do not trigger the help message.
static bool HasGoogleTestFlagPrefix(const char* str) {
  return (SkipPrefix("--", &str) ||
          SkipPrefix("-", &str) ||
          SkipPrefix("/", &str)) &&
         !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
         (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
          SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
}

// Prints a string containing code-encoded text.  The following escape
// sequences can be used in the string to control the text color:
//
//   @@    prints a single '@' character.
//   @R    changes the color to red.
//   @G    changes the color to green.
//   @Y    changes the color to yellow.
//   @D    changes to the default terminal text color.
//
// TODO(wan@google.com): Write tests for this once we add stdout
// capturing to Google Test.
static void PrintColorEncoded(const char* str) {
  GTestColor color = COLOR_DEFAULT;  // The current color.

  // Conceptually, we split the string into segments divided by escape
  // sequences.  Then we print one segment at a time.  At the end of
  // each iteration, the str pointer advances to the beginning of the
  // next segment.
  for (;;) {
    const char* p = strchr(str, '@');
    if (p == NULL) {
      ColoredPrintf(color, "%s", str);
      return;
    }

    ColoredPrintf(color, "%s", std::string(str, p).c_str());

    const char ch = p[1];
    str = p + 2;
    if (ch == '@') {
      ColoredPrintf(color, "@");
    } else if (ch == 'D') {
      color = COLOR_DEFAULT;
    } else if (ch == 'R') {
      color = COLOR_RED;
    } else if (ch == 'G') {
      color = COLOR_GREEN;
    } else if (ch == 'Y') {
      color = COLOR_YELLOW;
    } else {
      --str;
    }
  }
}

static const char kColorEncodedHelpMessage[] =
"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
"following command line flags to control its behavior:\n"
"\n"
"Test Selection:\n"
"  @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
"      List the names of all tests instead of running them. The name of\n"
"      TEST(Foo, Bar) is \"Foo.Bar\".\n"
"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
    "[@G-@YNEGATIVE_PATTERNS]@D\n"
"      Run only the tests whose name matches one of the positive patterns but\n"
"      none of the negative patterns. '?' matches any single character; '*'\n"
"      matches any substring; ':' separates two patterns.\n"
"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
"      Run all disabled tests too.\n"
"\n"
"Test Execution:\n"
"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
"      Run the tests repeatedly; use a negative count to repeat forever.\n"
"  @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
"      Randomize tests' orders on every iteration.\n"
"  @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
"      Random number seed to use for shuffling test orders (between 1 and\n"
"      99999, or 0 to use a seed based on the current time).\n"
"\n"
"Test Output:\n"
"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
"      Enable/disable colored output. The default is @Gauto@D.\n"
"  -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
"      Don't print the elapsed time of each test.\n"
"  @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
"      Generate an XML report in the given directory or with the given file\n"
"      name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
#if GTEST_CAN_STREAM_RESULTS_
"  @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n"
"      Stream test results to the given server.\n"
#endif  // GTEST_CAN_STREAM_RESULTS_
"\n"
"Assertion Behavior:\n"
#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
"      Set the default death test style.\n"
#endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
"      Turn assertion failures into debugger break-points.\n"
"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
"      Turn assertion failures into C++ exceptions.\n"
"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
"      Do not report exceptions as test failures. Instead, allow them\n"
"      to crash the program or throw a pop-up (on Windows).\n"
"\n"
"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
    "the corresponding\n"
"environment variable of a flag (all letters in upper-case). For example, to\n"
"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
    "color=no@D or set\n"
"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
"\n"
"For more information, please read the " GTEST_NAME_ " documentation at\n"
"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
"(not one in your own code or tests), please report it to\n"
"@G<" GTEST_DEV_EMAIL_ ">@D.\n";

// Parses the command line for Google Test flags, without initializing
// other parts of Google Test.  The type parameter CharType can be
// instantiated to either char or wchar_t.
template <typename CharType>
void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
  for (int i = 1; i < *argc; i++) {
    const std::string arg_string = StreamableToString(argv[i]);
    const char* const arg = arg_string.c_str();

    using internal::ParseBoolFlag;
    using internal::ParseInt32Flag;
    using internal::ParseStringFlag;

    // Do we see a Google Test flag?
    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
                      &GTEST_FLAG(also_run_disabled_tests)) ||
        ParseBoolFlag(arg, kBreakOnFailureFlag,
                      &GTEST_FLAG(break_on_failure)) ||
        ParseBoolFlag(arg, kCatchExceptionsFlag,
                      &GTEST_FLAG(catch_exceptions)) ||
        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
        ParseStringFlag(arg, kDeathTestStyleFlag,
                        &GTEST_FLAG(death_test_style)) ||
        ParseBoolFlag(arg, kDeathTestUseFork,
                      &GTEST_FLAG(death_test_use_fork)) ||
        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
        ParseStringFlag(arg, kInternalRunDeathTestFlag,
                        &GTEST_FLAG(internal_run_death_test)) ||
        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
        ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
        ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
        ParseInt32Flag(arg, kStackTraceDepthFlag,
                       &GTEST_FLAG(stack_trace_depth)) ||
        ParseStringFlag(arg, kStreamResultToFlag,
                        &GTEST_FLAG(stream_result_to)) ||
        ParseBoolFlag(arg, kThrowOnFailureFlag,
                      &GTEST_FLAG(throw_on_failure))
        ) {
      // Yes.  Shift the remainder of the argv list left by one.  Note
      // that argv has (*argc + 1) elements, the last one always being
      // NULL.  The following loop moves the trailing NULL element as
      // well.
      for (int j = i; j != *argc; j++) {
        argv[j] = argv[j + 1];
      }

      // Decrements the argument count.
      (*argc)--;

      // We also need to decrement the iterator as we just removed
      // an element.
      i--;
    } else if (arg_string == "--help" || arg_string == "-h" ||
               arg_string == "-?" || arg_string == "/?" ||
               HasGoogleTestFlagPrefix(arg)) {
      // Both help flag and unrecognized Google Test flags (excluding
      // internal ones) trigger help display.
      g_help_flag = true;
    }
  }

  if (g_help_flag) {
    // We print the help here instead of in RUN_ALL_TESTS(), as the
    // latter may not be called at all if the user is using Google
    // Test with another testing framework.
    PrintColorEncoded(kColorEncodedHelpMessage);
  }
}

// Parses the command line for Google Test flags, without initializing
// other parts of Google Test.
void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
  ParseGoogleTestFlagsOnlyImpl(argc, argv);
}
void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
  ParseGoogleTestFlagsOnlyImpl(argc, argv);
}

// The internal implementation of InitGoogleTest().
//
// The type parameter CharType can be instantiated to either char or
// wchar_t.
template <typename CharType>
void InitGoogleTestImpl(int* argc, CharType** argv) {
  g_init_gtest_count++;

  // We don't want to run the initialization code twice.
  if (g_init_gtest_count != 1) return;

  if (*argc <= 0) return;

  internal::g_executable_path = internal::StreamableToString(argv[0]);

#if GTEST_HAS_DEATH_TEST

  g_argvs.clear();
  for (int i = 0; i != *argc; i++) {
    g_argvs.push_back(StreamableToString(argv[i]));
  }

#endif  // GTEST_HAS_DEATH_TEST

  ParseGoogleTestFlagsOnly(argc, argv);
  GetUnitTestImpl()->PostFlagParsingInit();
}

}  // namespace internal

// Initializes Google Test.  This must be called before calling
// RUN_ALL_TESTS().  In particular, it parses a command line for the
// flags that Google Test recognizes.  Whenever a Google Test flag is
// seen, it is removed from argv, and *argc is decremented.
//
// No value is returned.  Instead, the Google Test flag variables are
// updated.
//
// Calling the function for the second time has no user-visible effect.
void InitGoogleTest(int* argc, char** argv) {
  internal::InitGoogleTestImpl(argc, argv);
}

// This overloaded version can be used in Windows programs compiled in
// UNICODE mode.
void InitGoogleTest(int* argc, wchar_t** argv) {
  internal::InitGoogleTestImpl(argc, argv);
}

}  // namespace testing
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
//
// This file implements death tests.


#if GTEST_HAS_DEATH_TEST

# if GTEST_OS_MAC
#  include <crt_externs.h>
# endif  // GTEST_OS_MAC

# include <errno.h>
# include <fcntl.h>
# include <limits.h>

# if GTEST_OS_LINUX
#  include <signal.h>
# endif  // GTEST_OS_LINUX

# include <stdarg.h>

# if GTEST_OS_WINDOWS
#  include <windows.h>
# else
#  include <sys/mman.h>
#  include <sys/wait.h>
# endif  // GTEST_OS_WINDOWS

# if GTEST_OS_QNX
#  include <spawn.h>
# endif  // GTEST_OS_QNX

#endif  // GTEST_HAS_DEATH_TEST


// Indicates that this translation unit is part of Google Test's
// implementation.  It must come before gtest-internal-inl.h is
// included, or there will be a compiler error.  This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
#undef GTEST_IMPLEMENTATION_

namespace testing {

// Constants.

// The default death test style.
static const char kDefaultDeathTestStyle[] = "fast";

GTEST_DEFINE_string_(
    death_test_style,
    internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
    "Indicates how to run a death test in a forked child process: "
    "\"threadsafe\" (child process re-executes the test binary "
    "from the beginning, running only the specific death test) or "
    "\"fast\" (child process runs the death test immediately "
    "after forking).");

GTEST_DEFINE_bool_(
    death_test_use_fork,
    internal::BoolFromGTestEnv("death_test_use_fork", false),
    "Instructs to use fork()/_exit() instead of clone() in death tests. "
    "Ignored and always uses fork() on POSIX systems where clone() is not "
    "implemented. Useful when running under valgrind or similar tools if "
    "those do not support clone(). Valgrind 3.3.1 will just fail if "
    "it sees an unsupported combination of clone() flags. "
    "It is not recommended to use this flag w/o valgrind though it will "
    "work in 99% of the cases. Once valgrind is fixed, this flag will "
    "most likely be removed.");

namespace internal {
GTEST_DEFINE_string_(
    internal_run_death_test, "",
    "Indicates the file, line number, temporal index of "
    "the single death test to run, and a file descriptor to "
    "which a success code may be sent, all separated by "
    "the '|' characters.  This flag is specified if and only if the current "
    "process is a sub-process launched for running a thread-safe "
    "death test.  FOR INTERNAL USE ONLY.");
}  // namespace internal

#if GTEST_HAS_DEATH_TEST

namespace internal {

// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
static bool g_in_fast_death_test_child = false;

// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process.  Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests.  IMPORTANT: This is an internal utility.  Using it may break the
// implementation of death tests.  User code MUST NOT use it.
bool InDeathTestChild() {
# if GTEST_OS_WINDOWS

  // On Windows, death tests are thread-safe regardless of the value of the
  // death_test_style flag.
  return !GTEST_FLAG(internal_run_death_test).empty();

# else

  if (GTEST_FLAG(death_test_style) == "threadsafe")
    return !GTEST_FLAG(internal_run_death_test).empty();
  else
    return g_in_fast_death_test_child;
#endif
}

}  // namespace internal

// ExitedWithCode constructor.
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
}

// ExitedWithCode function-call operator.
bool ExitedWithCode::operator()(int exit_status) const {
# if GTEST_OS_WINDOWS

  return exit_status == exit_code_;

# else

  return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;

# endif  // GTEST_OS_WINDOWS
}

# if !GTEST_OS_WINDOWS
// KilledBySignal constructor.
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
}

// KilledBySignal function-call operator.
bool KilledBySignal::operator()(int exit_status) const {
  return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
}
# endif  // !GTEST_OS_WINDOWS

namespace internal {

// Utilities needed for death tests.

// Generates a textual description of a given exit code, in the format
// specified by wait(2).
static std::string ExitSummary(int exit_code) {
  Message m;

# if GTEST_OS_WINDOWS

  m << "Exited with exit status " << exit_code;

# else

  if (WIFEXITED(exit_code)) {
    m << "Exited with exit status " << WEXITSTATUS(exit_code);
  } else if (WIFSIGNALED(exit_code)) {
    m << "Terminated by signal " << WTERMSIG(exit_code);
  }
#  ifdef WCOREDUMP
  if (WCOREDUMP(exit_code)) {
    m << " (core dumped)";
  }
#  endif
# endif  // GTEST_OS_WINDOWS

  return m.GetString();
}

// Returns true if exit_status describes a process that was terminated
// by a signal, or exited normally with a nonzero exit code.
bool ExitedUnsuccessfully(int exit_status) {
  return !ExitedWithCode(0)(exit_status);
}

# if !GTEST_OS_WINDOWS
// Generates a textual failure message when a death test finds more than
// one thread running, or cannot determine the number of threads, prior
// to executing the given statement.  It is the responsibility of the
// caller not to pass a thread_count of 1.
static std::string DeathTestThreadWarning(size_t thread_count) {
  Message msg;
  msg << "Death tests use fork(), which is unsafe particularly"
      << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
  if (thread_count == 0)
    msg << "couldn't detect the number of threads.";
  else
    msg << "detected " << thread_count << " threads.";
  return msg.GetString();
}
# endif  // !GTEST_OS_WINDOWS

// Flag characters for reporting a death test that did not die.
static const char kDeathTestLived = 'L';
static const char kDeathTestReturned = 'R';
static const char kDeathTestThrew = 'T';
static const char kDeathTestInternalError = 'I';

// An enumeration describing all of the possible ways that a death test can
// conclude.  DIED means that the process died while executing the test
// code; LIVED means that process lived beyond the end of the test code;
// RETURNED means that the test statement attempted to execute a return
// statement, which is not allowed; THREW means that the test statement
// returned control by throwing an exception.  IN_PROGRESS means the test
// has not yet concluded.
// TODO(vladl@google.com): Unify names and possibly values for
// AbortReason, DeathTestOutcome, and flag characters above.
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };

// Routine for aborting the program which is safe to call from an
// exec-style death test child process, in which case the error
// message is propagated back to the parent process.  Otherwise, the
// message is simply printed to stderr.  In either case, the program
// then exits with status 1.
void DeathTestAbort(const std::string& message) {
  // On a POSIX system, this function may be called from a threadsafe-style
  // death test child process, which operates on a very small stack.  Use
  // the heap for any additional non-minuscule memory requirements.
  const InternalRunDeathTestFlag* const flag =
      GetUnitTestImpl()->internal_run_death_test_flag();
  if (flag != NULL) {
    FILE* parent = posix::FDOpen(flag->write_fd(), "w");
    fputc(kDeathTestInternalError, parent);
    fprintf(parent, "%s", message.c_str());
    fflush(parent);
    _exit(1);
  } else {
    fprintf(stderr, "%s", message.c_str());
    fflush(stderr);
    posix::Abort();
  }
}

// A replacement for CHECK that calls DeathTestAbort if the assertion
// fails.
# define GTEST_DEATH_TEST_CHECK_(expression) \
  do { \
    if (!::testing::internal::IsTrue(expression)) { \
      DeathTestAbort( \
          ::std::string("CHECK failed: File ") + __FILE__ +  ", line " \
          + ::testing::internal::StreamableToString(__LINE__) + ": " \
          + #expression); \
    } \
  } while (::testing::internal::AlwaysFalse())

// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
// evaluating any system call that fulfills two conditions: it must return
// -1 on failure, and set errno to EINTR when it is interrupted and
// should be tried again.  The macro expands to a loop that repeatedly
// evaluates the expression as long as it evaluates to -1 and sets
// errno to EINTR.  If the expression evaluates to -1 but errno is
// something other than EINTR, DeathTestAbort is called.
# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
  do { \
    int gtest_retval; \
    do { \
      gtest_retval = (expression); \
    } while (gtest_retval == -1 && errno == EINTR); \
    if (gtest_retval == -1) { \
      DeathTestAbort( \
          ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
          + ::testing::internal::StreamableToString(__LINE__) + ": " \
          + #expression + " != -1"); \
    } \
  } while (::testing::internal::AlwaysFalse())

// Returns the message describing the last system error in errno.
std::string GetLastErrnoDescription() {
    return errno == 0 ? "" : posix::StrError(errno);
}

// This is called from a death test parent process to read a failure
// message from the death test child process and log it with the FATAL
// severity. On Windows, the message is read from a pipe handle. On other
// platforms, it is read from a file descriptor.
static void FailFromInternalError(int fd) {
  Message error;
  char buffer[256];
  int num_read;

  do {
    while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
      buffer[num_read] = '\0';
      error << buffer;
    }
  } while (num_read == -1 && errno == EINTR);

  if (num_read == 0) {
    GTEST_LOG_(FATAL) << error.GetString();
  } else {
    const int last_error = errno;
    GTEST_LOG_(FATAL) << "Error while reading death test internal: "
                      << GetLastErrnoDescription() << " [" << last_error << "]";
  }
}

// Death test constructor.  Increments the running death test count
// for the current test.
DeathTest::DeathTest() {
  TestInfo* const info = GetUnitTestImpl()->current_test_info();
  if (info == NULL) {
    DeathTestAbort("Cannot run a death test outside of a TEST or "
                   "TEST_F construct");
  }
}

// Creates and returns a death test by dispatching to the current
// death test factory.
bool DeathTest::Create(const char* statement, const RE* regex,
                       const char* file, int line, DeathTest** test) {
  return GetUnitTestImpl()->death_test_factory()->Create(
      statement, regex, file, line, test);
}

const char* DeathTest::LastMessage() {
  return last_death_test_message_.c_str();
}

void DeathTest::set_last_death_test_message(const std::string& message) {
  last_death_test_message_ = message;
}

std::string DeathTest::last_death_test_message_;

// Provides cross platform implementation for some death functionality.
class DeathTestImpl : public DeathTest {
 protected:
  DeathTestImpl(const char* a_statement, const RE* a_regex)
      : statement_(a_statement),
        regex_(a_regex),
        spawned_(false),
        status_(-1),
        outcome_(IN_PROGRESS),
        read_fd_(-1),
        write_fd_(-1) {}

  // read_fd_ is expected to be closed and cleared by a derived class.
  ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }

  void Abort(AbortReason reason);
  virtual bool Passed(bool status_ok);

  const char* statement() const { return statement_; }
  const RE* regex() const { return regex_; }
  bool spawned() const { return spawned_; }
  void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
  int status() const { return status_; }
  void set_status(int a_status) { status_ = a_status; }
  DeathTestOutcome outcome() const { return outcome_; }
  void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
  int read_fd() const { return read_fd_; }
  void set_read_fd(int fd) { read_fd_ = fd; }
  int write_fd() const { return write_fd_; }
  void set_write_fd(int fd) { write_fd_ = fd; }

  // Called in the parent process only. Reads the result code of the death
  // test child process via a pipe, interprets it to set the outcome_
  // member, and closes read_fd_.  Outputs diagnostics and terminates in
  // case of unexpected codes.
  void ReadAndInterpretStatusByte();

 private:
  // The textual content of the code this object is testing.  This class
  // doesn't own this string and should not attempt to delete it.
  const char* const statement_;
  // The regular expression which test output must match.  DeathTestImpl
  // doesn't own this object and should not attempt to delete it.
  const RE* const regex_;
  // True if the death test child process has been successfully spawned.
  bool spawned_;
  // The exit status of the child process.
  int status_;
  // How the death test concluded.
  DeathTestOutcome outcome_;
  // Descriptor to the read end of the pipe to the child process.  It is
  // always -1 in the child process.  The child keeps its write end of the
  // pipe in write_fd_.
  int read_fd_;
  // Descriptor to the child's write end of the pipe to the parent process.
  // It is always -1 in the parent process.  The parent keeps its end of the
  // pipe in read_fd_.
  int write_fd_;
};

// Called in the parent process only. Reads the result code of the death
// test child process via a pipe, interprets it to set the outcome_
// member, and closes read_fd_.  Outputs diagnostics and terminates in
// case of unexpected codes.
void DeathTestImpl::ReadAndInterpretStatusByte() {
  char flag;
  int bytes_read;

  // The read() here blocks until data is available (signifying the
  // failure of the death test) or until the pipe is closed (signifying
  // its success), so it's okay to call this in the parent before
  // the child process has exited.
  do {
    bytes_read = posix::Read(read_fd(), &flag, 1);
  } while (bytes_read == -1 && errno == EINTR);

  if (bytes_read == 0) {
    set_outcome(DIED);
  } else if (bytes_read == 1) {
    switch (flag) {
      case kDeathTestReturned:
        set_outcome(RETURNED);
        break;
      case kDeathTestThrew:
        set_outcome(THREW);
        break;
      case kDeathTestLived:
        set_outcome(LIVED);
        break;
      case kDeathTestInternalError:
        FailFromInternalError(read_fd());  // Does not return.
        break;
      default:
        GTEST_LOG_(FATAL) << "Death test child process reported "
                          << "unexpected status byte ("
                          << static_cast<unsigned int>(flag) << ")";
    }
  } else {
    GTEST_LOG_(FATAL) << "Read from death test child process failed: "
                      << GetLastErrnoDescription();
  }
  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
  set_read_fd(-1);
}

// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
// calls _exit(1).
void DeathTestImpl::Abort(AbortReason reason) {
  // The parent process considers the death test to be a failure if
  // it finds any data in our pipe.  So, here we write a single flag byte
  // to the pipe, then exit.
  const char status_ch =
      reason == TEST_DID_NOT_DIE ? kDeathTestLived :
      reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;

  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
  // We are leaking the descriptor here because on some platforms (i.e.,
  // when built as Windows DLL), destructors of global objects will still
  // run after calling _exit(). On such systems, write_fd_ will be
  // indirectly closed from the destructor of UnitTestImpl, causing double
  // close if it is also closed here. On debug configurations, double close
  // may assert. As there are no in-process buffers to flush here, we are
  // relying on the OS to close the descriptor after the process terminates
  // when the destructors are not run.
  _exit(1);  // Exits w/o any normal exit hooks (we were supposed to crash)
}

// Returns an indented copy of stderr output for a death test.
// This makes distinguishing death test output lines from regular log lines
// much easier.
static ::std::string FormatDeathTestOutput(const ::std::string& output) {
  ::std::string ret;
  for (size_t at = 0; ; ) {
    const size_t line_end = output.find('\n', at);
    ret += "[  DEATH   ] ";
    if (line_end == ::std::string::npos) {
      ret += output.substr(at);
      break;
    }
    ret += output.substr(at, line_end + 1 - at);
    at = line_end + 1;
  }
  return ret;
}

// Assesses the success or failure of a death test, using both private
// members which have previously been set, and one argument:
//
// Private data members:
//   outcome:  An enumeration describing how the death test
//             concluded: DIED, LIVED, THREW, or RETURNED.  The death test
//             fails in the latter three cases.
//   status:   The exit status of the child process. On *nix, it is in the
//             in the format specified by wait(2). On Windows, this is the
//             value supplied to the ExitProcess() API or a numeric code
//             of the exception that terminated the program.
//   regex:    A regular expression object to be applied to
//             the test's captured standard error output; the death test
//             fails if it does not match.
//
// Argument:
//   status_ok: true if exit_status is acceptable in the context of
//              this particular death test, which fails if it is false
//
// Returns true iff all of the above conditions are met.  Otherwise, the
// first failing condition, in the order given above, is the one that is
// reported. Also sets the last death test message string.
bool DeathTestImpl::Passed(bool status_ok) {
  if (!spawned())
    return false;

  const std::string error_message = GetCapturedStderr();

  bool success = false;
  Message buffer;

  buffer << "Death test: " << statement() << "\n";
  switch (outcome()) {
    case LIVED:
      buffer << "    Result: failed to die.\n"
             << " Error msg:\n" << FormatDeathTestOutput(error_message);
      break;
    case THREW:
      buffer << "    Result: threw an exception.\n"
             << " Error msg:\n" << FormatDeathTestOutput(error_message);
      break;
    case RETURNED:
      buffer << "    Result: illegal return in test statement.\n"
             << " Error msg:\n" << FormatDeathTestOutput(error_message);
      break;
    case DIED:
      if (status_ok) {
        const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
        if (matched) {
          success = true;
        } else {
          buffer << "    Result: died but not with expected error.\n"
                 << "  Expected: " << regex()->pattern() << "\n"
                 << "Actual msg:\n" << FormatDeathTestOutput(error_message);
        }
      } else {
        buffer << "    Result: died but not with expected exit code:\n"
               << "            " << ExitSummary(status()) << "\n"
               << "Actual msg:\n" << FormatDeathTestOutput(error_message);
      }
      break;
    case IN_PROGRESS:
    default:
      GTEST_LOG_(FATAL)
          << "DeathTest::Passed somehow called before conclusion of test";
  }

  DeathTest::set_last_death_test_message(buffer.GetString());
  return success;
}

# if GTEST_OS_WINDOWS
// WindowsDeathTest implements death tests on Windows. Due to the
// specifics of starting new processes on Windows, death tests there are
// always threadsafe, and Google Test considers the
// --gtest_death_test_style=fast setting to be equivalent to
// --gtest_death_test_style=threadsafe there.
//
// A few implementation notes:  Like the Linux version, the Windows
// implementation uses pipes for child-to-parent communication. But due to
// the specifics of pipes on Windows, some extra steps are required:
//
// 1. The parent creates a communication pipe and stores handles to both
//    ends of it.
// 2. The parent starts the child and provides it with the information
//    necessary to acquire the handle to the write end of the pipe.
// 3. The child acquires the write end of the pipe and signals the parent
//    using a Windows event.
// 4. Now the parent can release the write end of the pipe on its side. If
//    this is done before step 3, the object's reference count goes down to
//    0 and it is destroyed, preventing the child from acquiring it. The
//    parent now has to release it, or read operations on the read end of
//    the pipe will not return when the child terminates.
// 5. The parent reads child's output through the pipe (outcome code and
//    any possible error messages) from the pipe, and its stderr and then
//    determines whether to fail the test.
//
// Note: to distinguish Win32 API calls from the local method and function
// calls, the former are explicitly resolved in the global namespace.
//
class WindowsDeathTest : public DeathTestImpl {
 public:
  WindowsDeathTest(const char* a_statement,
                   const RE* a_regex,
                   const char* file,
                   int line)
      : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}

  // All of these virtual functions are inherited from DeathTest.
  virtual int Wait();
  virtual TestRole AssumeRole();

 private:
  // The name of the file in which the death test is located.
  const char* const file_;
  // The line number on which the death test is located.
  const int line_;
  // Handle to the write end of the pipe to the child process.
  AutoHandle write_handle_;
  // Child process handle.
  AutoHandle child_handle_;
  // Event the child process uses to signal the parent that it has
  // acquired the handle to the write end of the pipe. After seeing this
  // event the parent can release its own handles to make sure its
  // ReadFile() calls return when the child terminates.
  AutoHandle event_handle_;
};

// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists.  As a side effect, sets the
// outcome data member.
int WindowsDeathTest::Wait() {
  if (!spawned())
    return 0;

  // Wait until the child either signals that it has acquired the write end
  // of the pipe or it dies.
  const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
  switch (::WaitForMultipleObjects(2,
                                   wait_handles,
                                   FALSE,  // Waits for any of the handles.
                                   INFINITE)) {
    case WAIT_OBJECT_0:
    case WAIT_OBJECT_0 + 1:
      break;
    default:
      GTEST_DEATH_TEST_CHECK_(false);  // Should not get here.
  }

  // The child has acquired the write end of the pipe or exited.
  // We release the handle on our side and continue.
  write_handle_.Reset();
  event_handle_.Reset();

  ReadAndInterpretStatusByte();

  // Waits for the child process to exit if it haven't already. This
  // returns immediately if the child has already exited, regardless of
  // whether previous calls to WaitForMultipleObjects synchronized on this
  // handle or not.
  GTEST_DEATH_TEST_CHECK_(
      WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
                                             INFINITE));
  DWORD status_code;
  GTEST_DEATH_TEST_CHECK_(
      ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
  child_handle_.Reset();
  set_status(static_cast<int>(status_code));
  return status();
}

// The AssumeRole process for a Windows death test.  It creates a child
// process with the same executable as the current process to run the
// death test.  The child process is given the --gtest_filter and
// --gtest_internal_run_death_test flags such that it knows to run the
// current death test only.
DeathTest::TestRole WindowsDeathTest::AssumeRole() {
  const UnitTestImpl* const impl = GetUnitTestImpl();
  const InternalRunDeathTestFlag* const flag =
      impl->internal_run_death_test_flag();
  const TestInfo* const info = impl->current_test_info();
  const int death_test_index = info->result()->death_test_count();

  if (flag != NULL) {
    // ParseInternalRunDeathTestFlag() has performed all the necessary
    // processing.
    set_write_fd(flag->write_fd());
    return EXECUTE_TEST;
  }

  // WindowsDeathTest uses an anonymous pipe to communicate results of
  // a death test.
  SECURITY_ATTRIBUTES handles_are_inheritable = {
    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  HANDLE read_handle, write_handle;
  GTEST_DEATH_TEST_CHECK_(
      ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
                   0)  // Default buffer size.
      != FALSE);
  set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
                                O_RDONLY));
  write_handle_.Reset(write_handle);
  event_handle_.Reset(::CreateEvent(
      &handles_are_inheritable,
      TRUE,    // The event will automatically reset to non-signaled state.
      FALSE,   // The initial state is non-signalled.
      NULL));  // The even is unnamed.
  GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
  const std::string filter_flag =
      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
      info->test_case_name() + "." + info->name();
  const std::string internal_flag =
      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
      "=" + file_ + "|" + StreamableToString(line_) + "|" +
      StreamableToString(death_test_index) + "|" +
      StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
      // size_t has the same width as pointers on both 32-bit and 64-bit
      // Windows platforms.
      // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
      "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
      "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));

  char executable_path[_MAX_PATH + 1];  // NOLINT
  GTEST_DEATH_TEST_CHECK_(
      _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
                                            executable_path,
                                            _MAX_PATH));

  std::string command_line =
      std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
      internal_flag + "\"";

  DeathTest::set_last_death_test_message("");

  CaptureStderr();
  // Flush the log buffers since the log streams are shared with the child.
  FlushInfoLog();

  // The child process will share the standard handles with the parent.
  STARTUPINFOA startup_info;
  memset(&startup_info, 0, sizeof(STARTUPINFO));
  startup_info.dwFlags = STARTF_USESTDHANDLES;
  startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
  startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);

  PROCESS_INFORMATION process_info;
  GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
      executable_path,
      const_cast<char*>(command_line.c_str()),
      NULL,   // Retuned process handle is not inheritable.
      NULL,   // Retuned thread handle is not inheritable.
      TRUE,   // Child inherits all inheritable handles (for write_handle_).
      0x0,    // Default creation flags.
      NULL,   // Inherit the parent's environment.
      UnitTest::GetInstance()->original_working_dir(),
      &startup_info,
      &process_info) != FALSE);
  child_handle_.Reset(process_info.hProcess);
  ::CloseHandle(process_info.hThread);
  set_spawned(true);
  return OVERSEE_TEST;
}
# else  // We are not on Windows.

// ForkingDeathTest provides implementations for most of the abstract
// methods of the DeathTest interface.  Only the AssumeRole method is
// left undefined.
class ForkingDeathTest : public DeathTestImpl {
 public:
  ForkingDeathTest(const char* statement, const RE* regex);

  // All of these virtual functions are inherited from DeathTest.
  virtual int Wait();

 protected:
  void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }

 private:
  // PID of child process during death test; 0 in the child process itself.
  pid_t child_pid_;
};

// Constructs a ForkingDeathTest.
ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
    : DeathTestImpl(a_statement, a_regex),
      child_pid_(-1) {}

// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists.  As a side effect, sets the
// outcome data member.
int ForkingDeathTest::Wait() {
  if (!spawned())
    return 0;

  ReadAndInterpretStatusByte();

  int status_value;
  GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
  set_status(status_value);
  return status_value;
}

// A concrete death test class that forks, then immediately runs the test
// in the child process.
class NoExecDeathTest : public ForkingDeathTest {
 public:
  NoExecDeathTest(const char* a_statement, const RE* a_regex) :
      ForkingDeathTest(a_statement, a_regex) { }
  virtual TestRole AssumeRole();
};

// The AssumeRole process for a fork-and-run death test.  It implements a
// straightforward fork, with a simple pipe to transmit the status byte.
DeathTest::TestRole NoExecDeathTest::AssumeRole() {
  const size_t thread_count = GetThreadCount();
  if (thread_count != 1) {
    GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
  }

  int pipe_fd[2];
  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);

  DeathTest::set_last_death_test_message("");
  CaptureStderr();
  // When we fork the process below, the log file buffers are copied, but the
  // file descriptors are shared.  We flush all log files here so that closing
  // the file descriptors in the child process doesn't throw off the
  // synchronization between descriptors and buffers in the parent process.
  // This is as close to the fork as possible to avoid a race condition in case
  // there are multiple threads running before the death test, and another
  // thread writes to the log file.
  FlushInfoLog();

  const pid_t child_pid = fork();
  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
  set_child_pid(child_pid);
  if (child_pid == 0) {
    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
    set_write_fd(pipe_fd[1]);
    // Redirects all logging to stderr in the child process to prevent
    // concurrent writes to the log files.  We capture stderr in the parent
    // process and append the child process' output to a log.
    LogToStderr();
    // Event forwarding to the listeners of event listener API mush be shut
    // down in death test subprocesses.
    GetUnitTestImpl()->listeners()->SuppressEventForwarding();
    g_in_fast_death_test_child = true;
    return EXECUTE_TEST;
  } else {
    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
    set_read_fd(pipe_fd[0]);
    set_spawned(true);
    return OVERSEE_TEST;
  }
}

// A concrete death test class that forks and re-executes the main
// program from the beginning, with command-line flags set that cause
// only this specific death test to be run.
class ExecDeathTest : public ForkingDeathTest {
 public:
  ExecDeathTest(const char* a_statement, const RE* a_regex,
                const char* file, int line) :
      ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
  virtual TestRole AssumeRole();
 private:
  static ::std::vector<testing::internal::string>
  GetArgvsForDeathTestChildProcess() {
    ::std::vector<testing::internal::string> args = GetInjectableArgvs();
    return args;
  }
  // The name of the file in which the death test is located.
  const char* const file_;
  // The line number on which the death test is located.
  const int line_;
};

// Utility class for accumulating command-line arguments.
class Arguments {
 public:
  Arguments() {
    args_.push_back(NULL);
  }

  ~Arguments() {
    for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
         ++i) {
      free(*i);
    }
  }
  void AddArgument(const char* argument) {
    args_.insert(args_.end() - 1, posix::StrDup(argument));
  }

  template <typename Str>
  void AddArguments(const ::std::vector<Str>& arguments) {
    for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
         i != arguments.end();
         ++i) {
      args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
    }
  }
  char* const* Argv() {
    return &args_[0];
  }

 private:
  std::vector<char*> args_;
};

// A struct that encompasses the arguments to the child process of a
// threadsafe-style death test process.
struct ExecDeathTestArgs {
  char* const* argv;  // Command-line arguments for the child's call to exec
  int close_fd;       // File descriptor to close; the read end of a pipe
};

#  if GTEST_OS_MAC
inline char** GetEnviron() {
  // When Google Test is built as a framework on MacOS X, the environ variable
  // is unavailable. Apple's documentation (man environ) recommends using
  // _NSGetEnviron() instead.
  return *_NSGetEnviron();
}
#  else
// Some POSIX platforms expect you to declare environ. extern "C" makes
// it reside in the global namespace.
extern "C" char** environ;
inline char** GetEnviron() { return environ; }
#  endif  // GTEST_OS_MAC

#  if !GTEST_OS_QNX
// The main function for a threadsafe-style death test child process.
// This function is called in a clone()-ed process and thus must avoid
// any potentially unsafe operations like malloc or libc functions.
static int ExecDeathTestChildMain(void* child_arg) {
  ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));

  // We need to execute the test program in the same environment where
  // it was originally invoked.  Therefore we change to the original
  // working directory first.
  const char* const original_dir =
      UnitTest::GetInstance()->original_working_dir();
  // We can safely call chdir() as it's a direct system call.
  if (chdir(original_dir) != 0) {
    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
                   GetLastErrnoDescription());
    return EXIT_FAILURE;
  }

  // We can safely call execve() as it's a direct system call.  We
  // cannot use execvp() as it's a libc function and thus potentially
  // unsafe.  Since execve() doesn't search the PATH, the user must
  // invoke the test program via a valid path that contains at least
  // one path separator.
  execve(args->argv[0], args->argv, GetEnviron());
  DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
                 original_dir + " failed: " +
                 GetLastErrnoDescription());
  return EXIT_FAILURE;
}
#  endif  // !GTEST_OS_QNX

// Two utility routines that together determine the direction the stack
// grows.
// This could be accomplished more elegantly by a single recursive
// function, but we want to guard against the unlikely possibility of
// a smart compiler optimizing the recursion away.
//
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
// StackLowerThanAddress into StackGrowsDown, which then doesn't give
// correct answer.
void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
void StackLowerThanAddress(const void* ptr, bool* result) {
  int dummy;
  *result = (&dummy < ptr);
}

bool StackGrowsDown() {
  int dummy;
  bool result;
  StackLowerThanAddress(&dummy, &result);
  return result;
}

// Spawns a child process with the same executable as the current process in
// a thread-safe manner and instructs it to run the death test.  The
// implementation uses fork(2) + exec.  On systems where clone(2) is
// available, it is used instead, being slightly more thread-safe.  On QNX,
// fork supports only single-threaded environments, so this function uses
// spawn(2) there instead.  The function dies with an error message if
// anything goes wrong.
static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
  ExecDeathTestArgs args = { argv, close_fd };
  pid_t child_pid = -1;

#  if GTEST_OS_QNX
  // Obtains the current directory and sets it to be closed in the child
  // process.
  const int cwd_fd = open(".", O_RDONLY);
  GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
  // We need to execute the test program in the same environment where
  // it was originally invoked.  Therefore we change to the original
  // working directory first.
  const char* const original_dir =
      UnitTest::GetInstance()->original_working_dir();
  // We can safely call chdir() as it's a direct system call.
  if (chdir(original_dir) != 0) {
    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
                   GetLastErrnoDescription());
    return EXIT_FAILURE;
  }

  int fd_flags;
  // Set close_fd to be closed after spawn.
  GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
                                        fd_flags | FD_CLOEXEC));
  struct inheritance inherit = {0};
  // spawn is a system call.
  child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
  // Restores the current working directory.
  GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));

#  else   // GTEST_OS_QNX
#   if GTEST_OS_LINUX
  // When a SIGPROF signal is received while fork() or clone() are executing,
  // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
  // it after the call to fork()/clone() is complete.
  struct sigaction saved_sigprof_action;
  struct sigaction ignore_sigprof_action;
  memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
  sigemptyset(&ignore_sigprof_action.sa_mask);
  ignore_sigprof_action.sa_handler = SIG_IGN;
  GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
      SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
#   endif  // GTEST_OS_LINUX

#   if GTEST_HAS_CLONE
  const bool use_fork = GTEST_FLAG(death_test_use_fork);

  if (!use_fork) {
    static const bool stack_grows_down = StackGrowsDown();
    const size_t stack_size = getpagesize();
    // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
    void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
                             MAP_ANON | MAP_PRIVATE, -1, 0);
    GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);

    // Maximum stack alignment in bytes:  For a downward-growing stack, this
    // amount is subtracted from size of the stack space to get an address
    // that is within the stack space and is aligned on all systems we care
    // about.  As far as I know there is no ABI with stack alignment greater
    // than 64.  We assume stack and stack_size already have alignment of
    // kMaxStackAlignment.
    const size_t kMaxStackAlignment = 64;
    void* const stack_top =
        static_cast<char*>(stack) +
            (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
    GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
        reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);

    child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);

    GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
  }
#   else
  const bool use_fork = true;
#   endif  // GTEST_HAS_CLONE

  if (use_fork && (child_pid = fork()) == 0) {
      ExecDeathTestChildMain(&args);
      _exit(0);
  }
#  endif  // GTEST_OS_QNX
#  if GTEST_OS_LINUX
  GTEST_DEATH_TEST_CHECK_SYSCALL_(
      sigaction(SIGPROF, &saved_sigprof_action, NULL));
#  endif  // GTEST_OS_LINUX

  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
  return child_pid;
}

// The AssumeRole process for a fork-and-exec death test.  It re-executes the
// main program from the beginning, setting the --gtest_filter
// and --gtest_internal_run_death_test flags to cause only the current
// death test to be re-run.
DeathTest::TestRole ExecDeathTest::AssumeRole() {
  const UnitTestImpl* const impl = GetUnitTestImpl();
  const InternalRunDeathTestFlag* const flag =
      impl->internal_run_death_test_flag();
  const TestInfo* const info = impl->current_test_info();
  const int death_test_index = info->result()->death_test_count();

  if (flag != NULL) {
    set_write_fd(flag->write_fd());
    return EXECUTE_TEST;
  }

  int pipe_fd[2];
  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
  // Clear the close-on-exec flag on the write end of the pipe, lest
  // it be closed when the child process does an exec:
  GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);

  const std::string filter_flag =
      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
      + info->test_case_name() + "." + info->name();
  const std::string internal_flag =
      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
      + file_ + "|" + StreamableToString(line_) + "|"
      + StreamableToString(death_test_index) + "|"
      + StreamableToString(pipe_fd[1]);
  Arguments args;
  args.AddArguments(GetArgvsForDeathTestChildProcess());
  args.AddArgument(filter_flag.c_str());
  args.AddArgument(internal_flag.c_str());

  DeathTest::set_last_death_test_message("");

  CaptureStderr();
  // See the comment in NoExecDeathTest::AssumeRole for why the next line
  // is necessary.
  FlushInfoLog();

  const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
  set_child_pid(child_pid);
  set_read_fd(pipe_fd[0]);
  set_spawned(true);
  return OVERSEE_TEST;
}

# endif  // !GTEST_OS_WINDOWS

// Creates a concrete DeathTest-derived class that depends on the
// --gtest_death_test_style flag, and sets the pointer pointed to
// by the "test" argument to its address.  If the test should be
// skipped, sets that pointer to NULL.  Returns true, unless the
// flag is set to an invalid value.
bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
                                     const char* file, int line,
                                     DeathTest** test) {
  UnitTestImpl* const impl = GetUnitTestImpl();
  const InternalRunDeathTestFlag* const flag =
      impl->internal_run_death_test_flag();
  const int death_test_index = impl->current_test_info()
      ->increment_death_test_count();

  if (flag != NULL) {
    if (death_test_index > flag->index()) {
      DeathTest::set_last_death_test_message(
          "Death test count (" + StreamableToString(death_test_index)
          + ") somehow exceeded expected maximum ("
          + StreamableToString(flag->index()) + ")");
      return false;
    }

    if (!(flag->file() == file && flag->line() == line &&
          flag->index() == death_test_index)) {
      *test = NULL;
      return true;
    }
  }

# if GTEST_OS_WINDOWS

  if (GTEST_FLAG(death_test_style) == "threadsafe" ||
      GTEST_FLAG(death_test_style) == "fast") {
    *test = new WindowsDeathTest(statement, regex, file, line);
  }

# else

  if (GTEST_FLAG(death_test_style) == "threadsafe") {
    *test = new ExecDeathTest(statement, regex, file, line);
  } else if (GTEST_FLAG(death_test_style) == "fast") {
    *test = new NoExecDeathTest(statement, regex);
  }

# endif  // GTEST_OS_WINDOWS

  else {  // NOLINT - this is more readable than unbalanced brackets inside #if.
    DeathTest::set_last_death_test_message(
        "Unknown death test style \"" + GTEST_FLAG(death_test_style)
        + "\" encountered");
    return false;
  }

  return true;
}

// Splits a given string on a given delimiter, populating a given
// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have
// ::std::string, so we can use it here.
static void SplitString(const ::std::string& str, char delimiter,
                        ::std::vector< ::std::string>* dest) {
  ::std::vector< ::std::string> parsed;
  ::std::string::size_type pos = 0;
  while (::testing::internal::AlwaysTrue()) {
    const ::std::string::size_type colon = str.find(delimiter, pos);
    if (colon == ::std::string::npos) {
      parsed.push_back(str.substr(pos));
      break;
    } else {
      parsed.push_back(str.substr(pos, colon - pos));
      pos = colon + 1;
    }
  }
  dest->swap(parsed);
}

# if GTEST_OS_WINDOWS
// Recreates the pipe and event handles from the provided parameters,
// signals the event, and returns a file descriptor wrapped around the pipe
// handle. This function is called in the child process only.
int GetStatusFileDescriptor(unsigned int parent_process_id,
                            size_t write_handle_as_size_t,
                            size_t event_handle_as_size_t) {
  AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
                                                   FALSE,  // Non-inheritable.
                                                   parent_process_id));
  if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
    DeathTestAbort("Unable to open parent process " +
                   StreamableToString(parent_process_id));
  }

  // TODO(vladl@google.com): Replace the following check with a
  // compile-time assertion when available.
  GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));

  const HANDLE write_handle =
      reinterpret_cast<HANDLE>(write_handle_as_size_t);
  HANDLE dup_write_handle;

  // The newly initialized handle is accessible only in in the parent
  // process. To obtain one accessible within the child, we need to use
  // DuplicateHandle.
  if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
                         ::GetCurrentProcess(), &dup_write_handle,
                         0x0,    // Requested privileges ignored since
                                 // DUPLICATE_SAME_ACCESS is used.
                         FALSE,  // Request non-inheritable handler.
                         DUPLICATE_SAME_ACCESS)) {
    DeathTestAbort("Unable to duplicate the pipe handle " +
                   StreamableToString(write_handle_as_size_t) +
                   " from the parent process " +
                   StreamableToString(parent_process_id));
  }

  const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
  HANDLE dup_event_handle;

  if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
                         ::GetCurrentProcess(), &dup_event_handle,
                         0x0,
                         FALSE,
                         DUPLICATE_SAME_ACCESS)) {
    DeathTestAbort("Unable to duplicate the event handle " +
                   StreamableToString(event_handle_as_size_t) +
                   " from the parent process " +
                   StreamableToString(parent_process_id));
  }

  const int write_fd =
      ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
  if (write_fd == -1) {
    DeathTestAbort("Unable to convert pipe handle " +
                   StreamableToString(write_handle_as_size_t) +
                   " to a file descriptor");
  }

  // Signals the parent that the write end of the pipe has been acquired
  // so the parent can release its own write end.
  ::SetEvent(dup_event_handle);

  return write_fd;
}
# endif  // GTEST_OS_WINDOWS

// Returns a newly created InternalRunDeathTestFlag object with fields
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
// the flag is specified; otherwise returns NULL.
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
  if (GTEST_FLAG(internal_run_death_test) == "") return NULL;

  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
  // can use it here.
  int line = -1;
  int index = -1;
  ::std::vector< ::std::string> fields;
  SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
  int write_fd = -1;

# if GTEST_OS_WINDOWS

  unsigned int parent_process_id = 0;
  size_t write_handle_as_size_t = 0;
  size_t event_handle_as_size_t = 0;

  if (fields.size() != 6
      || !ParseNaturalNumber(fields[1], &line)
      || !ParseNaturalNumber(fields[2], &index)
      || !ParseNaturalNumber(fields[3], &parent_process_id)
      || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
      || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
    DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
                   GTEST_FLAG(internal_run_death_test));
  }
  write_fd = GetStatusFileDescriptor(parent_process_id,
                                     write_handle_as_size_t,
                                     event_handle_as_size_t);
# else

  if (fields.size() != 4
      || !ParseNaturalNumber(fields[1], &line)
      || !ParseNaturalNumber(fields[2], &index)
      || !ParseNaturalNumber(fields[3], &write_fd)) {
    DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
        + GTEST_FLAG(internal_run_death_test));
  }

# endif  // GTEST_OS_WINDOWS

  return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
}

}  // namespace internal

#endif  // GTEST_HAS_DEATH_TEST

}  // namespace testing
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: keith.ray@gmail.com (Keith Ray)


#include <stdlib.h>

#if GTEST_OS_WINDOWS_MOBILE
# include <windows.h>
#elif GTEST_OS_WINDOWS
# include <direct.h>
# include <io.h>
#elif GTEST_OS_SYMBIAN
// Symbian OpenC has PATH_MAX in sys/syslimits.h
# include <sys/syslimits.h>
#else
# include <limits.h>
# include <climits>  // Some Linux distributions define PATH_MAX here.
#endif  // GTEST_OS_WINDOWS_MOBILE

#if GTEST_OS_WINDOWS
# define GTEST_PATH_MAX_ _MAX_PATH
#elif defined(PATH_MAX)
# define GTEST_PATH_MAX_ PATH_MAX
#elif defined(_XOPEN_PATH_MAX)
# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
#else
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
#endif  // GTEST_OS_WINDOWS


namespace testing {
namespace internal {

#if GTEST_OS_WINDOWS
// On Windows, '\\' is the standard path separator, but many tools and the
// Windows API also accept '/' as an alternate path separator. Unless otherwise
// noted, a file path can contain either kind of path separators, or a mixture
// of them.
const char kPathSeparator = '\\';
const char kAlternatePathSeparator = '/';
const char kPathSeparatorString[] = "\\";
const char kAlternatePathSeparatorString[] = "/";
# if GTEST_OS_WINDOWS_MOBILE
// Windows CE doesn't have a current directory. You should not use
// the current directory in tests on Windows CE, but this at least
// provides a reasonable fallback.
const char kCurrentDirectoryString[] = "\\";
// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
const DWORD kInvalidFileAttributes = 0xffffffff;
# else
const char kCurrentDirectoryString[] = ".\\";
# endif  // GTEST_OS_WINDOWS_MOBILE
#else
const char kPathSeparator = '/';
const char kPathSeparatorString[] = "/";
const char kCurrentDirectoryString[] = "./";
#endif  // GTEST_OS_WINDOWS

// Returns whether the given character is a valid path separator.
static bool IsPathSeparator(char c) {
#if GTEST_HAS_ALT_PATH_SEP_
  return (c == kPathSeparator) || (c == kAlternatePathSeparator);
#else
  return c == kPathSeparator;
#endif
}

// Returns the current working directory, or "" if unsuccessful.
FilePath FilePath::GetCurrentDir() {
#if GTEST_OS_WINDOWS_MOBILE
  // Windows CE doesn't have a current directory, so we just return
  // something reasonable.
  return FilePath(kCurrentDirectoryString);
#elif GTEST_OS_WINDOWS
  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
#else
  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
#endif  // GTEST_OS_WINDOWS_MOBILE
}

// Returns a copy of the FilePath with the case-insensitive extension removed.
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
// FilePath("dir/file"). If a case-insensitive extension is not
// found, returns a copy of the original FilePath.
FilePath FilePath::RemoveExtension(const char* extension) const {
  const std::string dot_extension = std::string(".") + extension;
  if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
    return FilePath(pathname_.substr(
        0, pathname_.length() - dot_extension.length()));
  }
  return *this;
}

// Returns a pointer to the last occurence of a valid path separator in
// the FilePath. On Windows, for example, both '/' and '\' are valid path
// separators. Returns NULL if no path separator was found.
const char* FilePath::FindLastPathSeparator() const {
  const char* const last_sep = strrchr(c_str(), kPathSeparator);
#if GTEST_HAS_ALT_PATH_SEP_
  const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
  // Comparing two pointers of which only one is NULL is undefined.
  if (last_alt_sep != NULL &&
      (last_sep == NULL || last_alt_sep > last_sep)) {
    return last_alt_sep;
  }
#endif
  return last_sep;
}

// Returns a copy of the FilePath with the directory part removed.
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
// returns an empty FilePath ("").
// On Windows platform, '\' is the path separator, otherwise it is '/'.
FilePath FilePath::RemoveDirectoryName() const {
  const char* const last_sep = FindLastPathSeparator();
  return last_sep ? FilePath(last_sep + 1) : *this;
}

// RemoveFileName returns the directory path with the filename removed.
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
// On Windows platform, '\' is the path separator, otherwise it is '/'.
FilePath FilePath::RemoveFileName() const {
  const char* const last_sep = FindLastPathSeparator();
  std::string dir;
  if (last_sep) {
    dir = std::string(c_str(), last_sep + 1 - c_str());
  } else {
    dir = kCurrentDirectoryString;
  }
  return FilePath(dir);
}

// Helper functions for naming files in a directory for xml output.

// Given directory = "dir", base_name = "test", number = 0,
// extension = "xml", returns "dir/test.xml". If number is greater
// than zero (e.g., 12), returns "dir/test_12.xml".
// On Windows platform, uses \ as the separator rather than /.
FilePath FilePath::MakeFileName(const FilePath& directory,
                                const FilePath& base_name,
                                int number,
                                const char* extension) {
  std::string file;
  if (number == 0) {
    file = base_name.string() + "." + extension;
  } else {
    file = base_name.string() + "_" + StreamableToString(number)
        + "." + extension;
  }
  return ConcatPaths(directory, FilePath(file));
}

// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
// On Windows, uses \ as the separator rather than /.
FilePath FilePath::ConcatPaths(const FilePath& directory,
                               const FilePath& relative_path) {
  if (directory.IsEmpty())
    return relative_path;
  const FilePath dir(directory.RemoveTrailingPathSeparator());
  return FilePath(dir.string() + kPathSeparator + relative_path.string());
}

// Returns true if pathname describes something findable in the file-system,
// either a file, directory, or whatever.
bool FilePath::FileOrDirectoryExists() const {
#if GTEST_OS_WINDOWS_MOBILE
  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
  const DWORD attributes = GetFileAttributes(unicode);
  delete [] unicode;
  return attributes != kInvalidFileAttributes;
#else
  posix::StatStruct file_stat;
  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
#endif  // GTEST_OS_WINDOWS_MOBILE
}

// Returns true if pathname describes a directory in the file-system
// that exists.
bool FilePath::DirectoryExists() const {
  bool result = false;
#if GTEST_OS_WINDOWS
  // Don't strip off trailing separator if path is a root directory on
  // Windows (like "C:\\").
  const FilePath& path(IsRootDirectory() ? *this :
                                           RemoveTrailingPathSeparator());
#else
  const FilePath& path(*this);
#endif

#if GTEST_OS_WINDOWS_MOBILE
  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
  const DWORD attributes = GetFileAttributes(unicode);
  delete [] unicode;
  if ((attributes != kInvalidFileAttributes) &&
      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
    result = true;
  }
#else
  posix::StatStruct file_stat;
  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
      posix::IsDir(file_stat);
#endif  // GTEST_OS_WINDOWS_MOBILE

  return result;
}

// Returns true if pathname describes a root directory. (Windows has one
// root directory per disk drive.)
bool FilePath::IsRootDirectory() const {
#if GTEST_OS_WINDOWS
  // TODO(wan@google.com): on Windows a network share like
  // \\server\share can be a root directory, although it cannot be the
  // current directory.  Handle this properly.
  return pathname_.length() == 3 && IsAbsolutePath();
#else
  return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
#endif
}

// Returns true if pathname describes an absolute path.
bool FilePath::IsAbsolutePath() const {
  const char* const name = pathname_.c_str();
#if GTEST_OS_WINDOWS
  return pathname_.length() >= 3 &&
     ((name[0] >= 'a' && name[0] <= 'z') ||
      (name[0] >= 'A' && name[0] <= 'Z')) &&
     name[1] == ':' &&
     IsPathSeparator(name[2]);
#else
  return IsPathSeparator(name[0]);
#endif
}

// Returns a pathname for a file that does not currently exist. The pathname
// will be directory/base_name.extension or
// directory/base_name_<number>.extension if directory/base_name.extension
// already exists. The number will be incremented until a pathname is found
// that does not already exist.
// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
// There could be a race condition if two or more processes are calling this
// function at the same time -- they could both pick the same filename.
FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
                                          const FilePath& base_name,
                                          const char* extension) {
  FilePath full_pathname;
  int number = 0;
  do {
    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
  } while (full_pathname.FileOrDirectoryExists());
  return full_pathname;
}

// Returns true if FilePath ends with a path separator, which indicates that
// it is intended to represent a directory. Returns false otherwise.
// This does NOT check that a directory (or file) actually exists.
bool FilePath::IsDirectory() const {
  return !pathname_.empty() &&
         IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
}

// Create directories so that path exists. Returns true if successful or if
// the directories already exist; returns false if unable to create directories
// for any reason.
bool FilePath::CreateDirectoriesRecursively() const {
  if (!this->IsDirectory()) {
    return false;
  }

  if (pathname_.length() == 0 || this->DirectoryExists()) {
    return true;
  }

  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
}

// Create the directory so that path exists. Returns true if successful or
// if the directory already exists; returns false if unable to create the
// directory for any reason, including if the parent directory does not
// exist. Not named "CreateDirectory" because that's a macro on Windows.
bool FilePath::CreateFolder() const {
#if GTEST_OS_WINDOWS_MOBILE
  FilePath removed_sep(this->RemoveTrailingPathSeparator());
  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
  int result = CreateDirectory(unicode, NULL) ? 0 : -1;
  delete [] unicode;
#elif GTEST_OS_WINDOWS
  int result = _mkdir(pathname_.c_str());
#else
  int result = mkdir(pathname_.c_str(), 0777);
#endif  // GTEST_OS_WINDOWS_MOBILE

  if (result == -1) {
    return this->DirectoryExists();  // An error is OK if the directory exists.
  }
  return true;  // No error.
}

// If input name has a trailing separator character, remove it and return the
// name, otherwise return the name string unmodified.
// On Windows platform, uses \ as the separator, other platforms use /.
FilePath FilePath::RemoveTrailingPathSeparator() const {
  return IsDirectory()
      ? FilePath(pathname_.substr(0, pathname_.length() - 1))
      : *this;
}

// Removes any redundant separators that might be in the pathname.
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
// redundancies that might be in a pathname involving "." or "..".
// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
void FilePath::Normalize() {
  if (pathname_.c_str() == NULL) {
    pathname_ = "";
    return;
  }
  const char* src = pathname_.c_str();
  char* const dest = new char[pathname_.length() + 1];
  char* dest_ptr = dest;
  memset(dest_ptr, 0, pathname_.length() + 1);

  while (*src != '\0') {
    *dest_ptr = *src;
    if (!IsPathSeparator(*src)) {
      src++;
    } else {
#if GTEST_HAS_ALT_PATH_SEP_
      if (*dest_ptr == kAlternatePathSeparator) {
        *dest_ptr = kPathSeparator;
      }
#endif
      while (IsPathSeparator(*src))
        src++;
    }
    dest_ptr++;
  }
  *dest_ptr = '\0';
  pathname_ = dest;
  delete[] dest;
}

}  // namespace internal
}  // namespace testing
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)


#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#if GTEST_OS_WINDOWS_MOBILE
# include <windows.h>  // For TerminateProcess()
#elif GTEST_OS_WINDOWS
# include <io.h>
# include <sys/stat.h>
#else
# include <unistd.h>
#endif  // GTEST_OS_WINDOWS_MOBILE

#if GTEST_OS_MAC
# include <mach/mach_init.h>
# include <mach/task.h>
# include <mach/vm_map.h>
#endif  // GTEST_OS_MAC

#if GTEST_OS_QNX
# include <devctl.h>
# include <sys/procfs.h>
#endif  // GTEST_OS_QNX


// Indicates that this translation unit is part of Google Test's
// implementation.  It must come before gtest-internal-inl.h is
// included, or there will be a compiler error.  This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
#undef GTEST_IMPLEMENTATION_

namespace testing {
namespace internal {

#if defined(_MSC_VER) || defined(__BORLANDC__)
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
const int kStdOutFileno = 1;
const int kStdErrFileno = 2;
#else
const int kStdOutFileno = STDOUT_FILENO;
const int kStdErrFileno = STDERR_FILENO;
#endif  // _MSC_VER

#if GTEST_OS_MAC

// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
size_t GetThreadCount() {
  const task_t task = mach_task_self();
  mach_msg_type_number_t thread_count;
  thread_act_array_t thread_list;
  const kern_return_t status = task_threads(task, &thread_list, &thread_count);
  if (status == KERN_SUCCESS) {
    // task_threads allocates resources in thread_list and we need to free them
    // to avoid leaks.
    vm_deallocate(task,
                  reinterpret_cast<vm_address_t>(thread_list),
                  sizeof(thread_t) * thread_count);
    return static_cast<size_t>(thread_count);
  } else {
    return 0;
  }
}

#elif GTEST_OS_QNX

// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
size_t GetThreadCount() {
  const int fd = open("/proc/self/as", O_RDONLY);
  if (fd < 0) {
    return 0;
  }
  procfs_info process_info;
  const int status =
      devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
  close(fd);
  if (status == EOK) {
    return static_cast<size_t>(process_info.num_threads);
  } else {
    return 0;
  }
}

#else

size_t GetThreadCount() {
  // There's no portable way to detect the number of threads, so we just
  // return 0 to indicate that we cannot detect it.
  return 0;
}

#endif  // GTEST_OS_MAC

#if GTEST_USES_POSIX_RE

// Implements RE.  Currently only needed for death tests.

RE::~RE() {
  if (is_valid_) {
    // regfree'ing an invalid regex might crash because the content
    // of the regex is undefined. Since the regex's are essentially
    // the same, one cannot be valid (or invalid) without the other
    // being so too.
    regfree(&partial_regex_);
    regfree(&full_regex_);
  }
  free(const_cast<char*>(pattern_));
}

// Returns true iff regular expression re matches the entire str.
bool RE::FullMatch(const char* str, const RE& re) {
  if (!re.is_valid_) return false;

  regmatch_t match;
  return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
}

// Returns true iff regular expression re matches a substring of str
// (including str itself).
bool RE::PartialMatch(const char* str, const RE& re) {
  if (!re.is_valid_) return false;

  regmatch_t match;
  return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
}

// Initializes an RE from its string representation.
void RE::Init(const char* regex) {
  pattern_ = posix::StrDup(regex);

  // Reserves enough bytes to hold the regular expression used for a
  // full match.
  const size_t full_regex_len = strlen(regex) + 10;
  char* const full_pattern = new char[full_regex_len];

  snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
  is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
  // We want to call regcomp(&partial_regex_, ...) even if the
  // previous expression returns false.  Otherwise partial_regex_ may
  // not be properly initialized can may cause trouble when it's
  // freed.
  //
  // Some implementation of POSIX regex (e.g. on at least some
  // versions of Cygwin) doesn't accept the empty string as a valid
  // regex.  We change it to an equivalent form "()" to be safe.
  if (is_valid_) {
    const char* const partial_regex = (*regex == '\0') ? "()" : regex;
    is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
  }
  EXPECT_TRUE(is_valid_)
      << "Regular expression \"" << regex
      << "\" is not a valid POSIX Extended regular expression.";

  delete[] full_pattern;
}

#elif GTEST_USES_SIMPLE_RE

// Returns true iff ch appears anywhere in str (excluding the
// terminating '\0' character).
bool IsInSet(char ch, const char* str) {
  return ch != '\0' && strchr(str, ch) != NULL;
}

// Returns true iff ch belongs to the given classification.  Unlike
// similar functions in <ctype.h>, these aren't affected by the
// current locale.
bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
bool IsAsciiPunct(char ch) {
  return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
}
bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
bool IsAsciiWordChar(char ch) {
  return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
      ('0' <= ch && ch <= '9') || ch == '_';
}

// Returns true iff "\\c" is a supported escape sequence.
bool IsValidEscape(char c) {
  return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
}

// Returns true iff the given atom (specified by escaped and pattern)
// matches ch.  The result is undefined if the atom is invalid.
bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
  if (escaped) {  // "\\p" where p is pattern_char.
    switch (pattern_char) {
      case 'd': return IsAsciiDigit(ch);
      case 'D': return !IsAsciiDigit(ch);
      case 'f': return ch == '\f';
      case 'n': return ch == '\n';
      case 'r': return ch == '\r';
      case 's': return IsAsciiWhiteSpace(ch);
      case 'S': return !IsAsciiWhiteSpace(ch);
      case 't': return ch == '\t';
      case 'v': return ch == '\v';
      case 'w': return IsAsciiWordChar(ch);
      case 'W': return !IsAsciiWordChar(ch);
    }
    return IsAsciiPunct(pattern_char) && pattern_char == ch;
  }

  return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
}

// Helper function used by ValidateRegex() to format error messages.
std::string FormatRegexSyntaxError(const char* regex, int index) {
  return (Message() << "Syntax error at index " << index
          << " in simple regular expression \"" << regex << "\": ").GetString();
}

// Generates non-fatal failures and returns false if regex is invalid;
// otherwise returns true.
bool ValidateRegex(const char* regex) {
  if (regex == NULL) {
    // TODO(wan@google.com): fix the source file location in the
    // assertion failures to match where the regex is used in user
    // code.
    ADD_FAILURE() << "NULL is not a valid simple regular expression.";
    return false;
  }

  bool is_valid = true;

  // True iff ?, *, or + can follow the previous atom.
  bool prev_repeatable = false;
  for (int i = 0; regex[i]; i++) {
    if (regex[i] == '\\') {  // An escape sequence
      i++;
      if (regex[i] == '\0') {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
                      << "'\\' cannot appear at the end.";
        return false;
      }

      if (!IsValidEscape(regex[i])) {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
                      << "invalid escape sequence \"\\" << regex[i] << "\".";
        is_valid = false;
      }
      prev_repeatable = true;
    } else {  // Not an escape sequence.
      const char ch = regex[i];

      if (ch == '^' && i > 0) {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
                      << "'^' can only appear at the beginning.";
        is_valid = false;
      } else if (ch == '$' && regex[i + 1] != '\0') {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
                      << "'$' can only appear at the end.";
        is_valid = false;
      } else if (IsInSet(ch, "()[]{}|")) {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
                      << "'" << ch << "' is unsupported.";
        is_valid = false;
      } else if (IsRepeat(ch) && !prev_repeatable) {
        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
                      << "'" << ch << "' can only follow a repeatable token.";
        is_valid = false;
      }

      prev_repeatable = !IsInSet(ch, "^$?*+");
    }
  }

  return is_valid;
}

// Matches a repeated regex atom followed by a valid simple regular
// expression.  The regex atom is defined as c if escaped is false,
// or \c otherwise.  repeat is the repetition meta character (?, *,
// or +).  The behavior is undefined if str contains too many
// characters to be indexable by size_t, in which case the test will
// probably time out anyway.  We are fine with this limitation as
// std::string has it too.
bool MatchRepetitionAndRegexAtHead(
    bool escaped, char c, char repeat, const char* regex,
    const char* str) {
  const size_t min_count = (repeat == '+') ? 1 : 0;
  const size_t max_count = (repeat == '?') ? 1 :
      static_cast<size_t>(-1) - 1;
  // We cannot call numeric_limits::max() as it conflicts with the
  // max() macro on Windows.

  for (size_t i = 0; i <= max_count; ++i) {
    // We know that the atom matches each of the first i characters in str.
    if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
      // We have enough matches at the head, and the tail matches too.
      // Since we only care about *whether* the pattern matches str
      // (as opposed to *how* it matches), there is no need to find a
      // greedy match.
      return true;
    }
    if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
      return false;
  }
  return false;
}

// Returns true iff regex matches a prefix of str.  regex must be a
// valid simple regular expression and not start with "^", or the
// result is undefined.
bool MatchRegexAtHead(const char* regex, const char* str) {
  if (*regex == '\0')  // An empty regex matches a prefix of anything.
    return true;

  // "$" only matches the end of a string.  Note that regex being
  // valid guarantees that there's nothing after "$" in it.
  if (*regex == '$')
    return *str == '\0';

  // Is the first thing in regex an escape sequence?
  const bool escaped = *regex == '\\';
  if (escaped)
    ++regex;
  if (IsRepeat(regex[1])) {
    // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
    // here's an indirect recursion.  It terminates as the regex gets
    // shorter in each recursion.
    return MatchRepetitionAndRegexAtHead(
        escaped, regex[0], regex[1], regex + 2, str);
  } else {
    // regex isn't empty, isn't "$", and doesn't start with a
    // repetition.  We match the first atom of regex with the first
    // character of str and recurse.
    return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
        MatchRegexAtHead(regex + 1, str + 1);
  }
}

// Returns true iff regex matches any substring of str.  regex must be
// a valid simple regular expression, or the result is undefined.
//
// The algorithm is recursive, but the recursion depth doesn't exceed
// the regex length, so we won't need to worry about running out of
// stack space normally.  In rare cases the time complexity can be
// exponential with respect to the regex length + the string length,
// but usually it's must faster (often close to linear).
bool MatchRegexAnywhere(const char* regex, const char* str) {
  if (regex == NULL || str == NULL)
    return false;

  if (*regex == '^')
    return MatchRegexAtHead(regex + 1, str);

  // A successful match can be anywhere in str.
  do {
    if (MatchRegexAtHead(regex, str))
      return true;
  } while (*str++ != '\0');
  return false;
}

// Implements the RE class.

RE::~RE() {
  free(const_cast<char*>(pattern_));
  free(const_cast<char*>(full_pattern_));
}

// Returns true iff regular expression re matches the entire str.
bool RE::FullMatch(const char* str, const RE& re) {
  return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
}

// Returns true iff regular expression re matches a substring of str
// (including str itself).
bool RE::PartialMatch(const char* str, const RE& re) {
  return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
}

// Initializes an RE from its string representation.
void RE::Init(const char* regex) {
  pattern_ = full_pattern_ = NULL;
  if (regex != NULL) {
    pattern_ = posix::StrDup(regex);
  }

  is_valid_ = ValidateRegex(regex);
  if (!is_valid_) {
    // No need to calculate the full pattern when the regex is invalid.
    return;
  }

  const size_t len = strlen(regex);
  // Reserves enough bytes to hold the regular expression used for a
  // full match: we need space to prepend a '^', append a '$', and
  // terminate the string with '\0'.
  char* buffer = static_cast<char*>(malloc(len + 3));
  full_pattern_ = buffer;

  if (*regex != '^')
    *buffer++ = '^';  // Makes sure full_pattern_ starts with '^'.

  // We don't use snprintf or strncpy, as they trigger a warning when
  // compiled with VC++ 8.0.
  memcpy(buffer, regex, len);
  buffer += len;

  if (len == 0 || regex[len - 1] != '$')
    *buffer++ = '$';  // Makes sure full_pattern_ ends with '$'.

  *buffer = '\0';
}

#endif  // GTEST_USES_POSIX_RE

const char kUnknownFile[] = "unknown file";

// Formats a source file path and a line number as they would appear
// in an error message from the compiler used to compile this code.
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
  const std::string file_name(file == NULL ? kUnknownFile : file);

  if (line < 0) {
    return file_name + ":";
  }
#ifdef _MSC_VER
  return file_name + "(" + StreamableToString(line) + "):";
#else
  return file_name + ":" + StreamableToString(line) + ":";
#endif  // _MSC_VER
}

// Formats a file location for compiler-independent XML output.
// Although this function is not platform dependent, we put it next to
// FormatFileLocation in order to contrast the two functions.
// Note that FormatCompilerIndependentFileLocation() does NOT append colon
// to the file location it produces, unlike FormatFileLocation().
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
    const char* file, int line) {
  const std::string file_name(file == NULL ? kUnknownFile : file);

  if (line < 0)
    return file_name;
  else
    return file_name + ":" + StreamableToString(line);
}


GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
    : severity_(severity) {
  const char* const marker =
      severity == GTEST_INFO ?    "[  INFO ]" :
      severity == GTEST_WARNING ? "[WARNING]" :
      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
  GetStream() << ::std::endl << marker << " "
              << FormatFileLocation(file, line).c_str() << ": ";
}

// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
GTestLog::~GTestLog() {
  GetStream() << ::std::endl;
  if (severity_ == GTEST_FATAL) {
    fflush(stderr);
    posix::Abort();
  }
}
// Disable Microsoft deprecation warnings for POSIX functions called from
// this class (creat, dup, dup2, and close)
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4996)
#endif  // _MSC_VER

#if GTEST_HAS_STREAM_REDIRECTION

// Object that captures an output stream (stdout/stderr).
class CapturedStream {
 public:
  // The ctor redirects the stream to a temporary file.
  explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
# if GTEST_OS_WINDOWS
    char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT
    char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT

    ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
    const UINT success = ::GetTempFileNameA(temp_dir_path,
                                            "gtest_redir",
                                            0,  // Generate unique file name.
                                            temp_file_path);
    GTEST_CHECK_(success != 0)
        << "Unable to create a temporary file in " << temp_dir_path;
    const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
    GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
                                    << temp_file_path;
    filename_ = temp_file_path;
# else
    // There's no guarantee that a test has write access to the current
    // directory, so we create the temporary file in the /tmp directory
    // instead. We use /tmp on most systems, and /sdcard on Android.
    // That's because Android doesn't have /tmp.
#  if GTEST_OS_LINUX_ANDROID
    // Note: Android applications are expected to call the framework's
    // Context.getExternalStorageDirectory() method through JNI to get
    // the location of the world-writable SD Card directory. However,
    // this requires a Context handle, which cannot be retrieved
    // globally from native code. Doing so also precludes running the
    // code as part of a regular standalone executable, which doesn't
    // run in a Dalvik process (e.g. when running it through 'adb shell').
    //
    // The location /sdcard is directly accessible from native code
    // and is the only location (unofficially) supported by the Android
    // team. It's generally a symlink to the real SD Card mount point
    // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
    // other OEM-customized locations. Never rely on these, and always
    // use /sdcard.
    char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
#  else
    char name_template[] = "/tmp/captured_stream.XXXXXX";
#  endif  // GTEST_OS_LINUX_ANDROID
    const int captured_fd = mkstemp(name_template);
    filename_ = name_template;
# endif  // GTEST_OS_WINDOWS
    fflush(NULL);
    dup2(captured_fd, fd_);
    close(captured_fd);
  }

  ~CapturedStream() {
    remove(filename_.c_str());
  }

  std::string GetCapturedString() {
    if (uncaptured_fd_ != -1) {
      // Restores the original stream.
      fflush(NULL);
      dup2(uncaptured_fd_, fd_);
      close(uncaptured_fd_);
      uncaptured_fd_ = -1;
    }

    FILE* const file = posix::FOpen(filename_.c_str(), "r");
    const std::string content = ReadEntireFile(file);
    posix::FClose(file);
    return content;
  }

 private:
  // Reads the entire content of a file as an std::string.
  static std::string ReadEntireFile(FILE* file);

  // Returns the size (in bytes) of a file.
  static size_t GetFileSize(FILE* file);

  const int fd_;  // A stream to capture.
  int uncaptured_fd_;
  // Name of the temporary file holding the stderr output.
  ::std::string filename_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
};

// Returns the size (in bytes) of a file.
size_t CapturedStream::GetFileSize(FILE* file) {
  fseek(file, 0, SEEK_END);
  return static_cast<size_t>(ftell(file));
}

// Reads the entire content of a file as a string.
std::string CapturedStream::ReadEntireFile(FILE* file) {
  const size_t file_size = GetFileSize(file);
  char* const buffer = new char[file_size];

  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
  size_t bytes_read = 0;       // # of bytes read so far

  fseek(file, 0, SEEK_SET);

  // Keeps reading the file until we cannot read further or the
  // pre-determined file size is reached.
  do {
    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
    bytes_read += bytes_last_read;
  } while (bytes_last_read > 0 && bytes_read < file_size);

  const std::string content(buffer, bytes_read);
  delete[] buffer;

  return content;
}

# ifdef _MSC_VER
#  pragma warning(pop)
# endif  // _MSC_VER

static CapturedStream* g_captured_stderr = NULL;
static CapturedStream* g_captured_stdout = NULL;

// Starts capturing an output stream (stdout/stderr).
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
  if (*stream != NULL) {
    GTEST_LOG_(FATAL) << "Only one " << stream_name
                      << " capturer can exist at a time.";
  }
  *stream = new CapturedStream(fd);
}

// Stops capturing the output stream and returns the captured string.
std::string GetCapturedStream(CapturedStream** captured_stream) {
  const std::string content = (*captured_stream)->GetCapturedString();

  delete *captured_stream;
  *captured_stream = NULL;

  return content;
}

// Starts capturing stdout.
void CaptureStdout() {
  CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
}

// Starts capturing stderr.
void CaptureStderr() {
  CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
}

// Stops capturing stdout and returns the captured string.
std::string GetCapturedStdout() {
  return GetCapturedStream(&g_captured_stdout);
}

// Stops capturing stderr and returns the captured string.
std::string GetCapturedStderr() {
  return GetCapturedStream(&g_captured_stderr);
}

#endif  // GTEST_HAS_STREAM_REDIRECTION

#if GTEST_HAS_DEATH_TEST

// A copy of all command line arguments.  Set by InitGoogleTest().
::std::vector<testing::internal::string> g_argvs;

static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
                                        NULL;  // Owned.

void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
  if (g_injected_test_argvs != argvs)
    delete g_injected_test_argvs;
  g_injected_test_argvs = argvs;
}

const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
  if (g_injected_test_argvs != NULL) {
    return *g_injected_test_argvs;
  }
  return g_argvs;
}
#endif  // GTEST_HAS_DEATH_TEST

#if GTEST_OS_WINDOWS_MOBILE
namespace posix {
void Abort() {
  DebugBreak();
  TerminateProcess(GetCurrentProcess(), 1);
}
}  // namespace posix
#endif  // GTEST_OS_WINDOWS_MOBILE

// Returns the name of the environment variable corresponding to the
// given flag.  For example, FlagToEnvVar("foo") will return
// "GTEST_FOO" in the open-source version.
static std::string FlagToEnvVar(const char* flag) {
  const std::string full_flag =
      (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();

  Message env_var;
  for (size_t i = 0; i != full_flag.length(); i++) {
    env_var << ToUpper(full_flag.c_str()[i]);
  }

  return env_var.GetString();
}

// Parses 'str' for a 32-bit signed integer.  If successful, writes
// the result to *value and returns true; otherwise leaves *value
// unchanged and returns false.
bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
  // Parses the environment variable as a decimal integer.
  char* end = NULL;
  const long long_value = strtol(str, &end, 10);  // NOLINT

  // Has strtol() consumed all characters in the string?
  if (*end != '\0') {
    // No - an invalid character was encountered.
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value \"" << str << "\".\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  // Is the parsed value in the range of an Int32?
  const Int32 result = static_cast<Int32>(long_value);
  if (long_value == LONG_MAX || long_value == LONG_MIN ||
      // The parsed value overflows as a long.  (strtol() returns
      // LONG_MAX or LONG_MIN when the input overflows.)
      result != long_value
      // The parsed value overflows as an Int32.
      ) {
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value " << str << ", which overflows.\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  *value = result;
  return true;
}

// Reads and returns the Boolean environment variable corresponding to
// the given flag; if it's not set, returns default_value.
//
// The value is considered true iff it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) {
  const std::string env_var = FlagToEnvVar(flag);
  const char* const string_value = posix::GetEnv(env_var.c_str());
  return string_value == NULL ?
      default_value : strcmp(string_value, "0") != 0;
}

// Reads and returns a 32-bit integer stored in the environment
// variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value.
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
  const std::string env_var = FlagToEnvVar(flag);
  const char* const string_value = posix::GetEnv(env_var.c_str());
  if (string_value == NULL) {
    // The environment variable is not set.
    return default_value;
  }

  Int32 result = default_value;
  if (!ParseInt32(Message() << "Environment variable " << env_var,
                  string_value, &result)) {
    printf("The default value %s is used.\n",
           (Message() << default_value).GetString().c_str());
    fflush(stdout);
    return default_value;
  }

  return result;
}

// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
const char* StringFromGTestEnv(const char* flag, const char* default_value) {
  const std::string env_var = FlagToEnvVar(flag);
  const char* const value = posix::GetEnv(env_var.c_str());
  return value == NULL ? default_value : value;
}

}  // namespace internal
}  // namespace testing
// Copyright 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)

// Google Test - The Google C++ Testing Framework
//
// This file implements a universal value printer that can print a
// value of any type T:
//
//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
//
// It uses the << operator when possible, and prints the bytes in the
// object otherwise.  A user can override its behavior for a class
// type Foo by defining either operator<<(::std::ostream&, const Foo&)
// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
// defines Foo.

#include <ctype.h>
#include <stdio.h>
#include <ostream>  // NOLINT
#include <string>

namespace testing {

namespace {

using ::std::ostream;

// Prints a segment of bytes in the given object.
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
                                size_t count, ostream* os) {
  char text[5] = "";
  for (size_t i = 0; i != count; i++) {
    const size_t j = start + i;
    if (i != 0) {
      // Organizes the bytes into groups of 2 for easy parsing by
      // human.
      if ((j % 2) == 0)
        *os << ' ';
      else
        *os << '-';
    }
    GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
    *os << text;
  }
}

// Prints the bytes in the given value to the given ostream.
void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
                              ostream* os) {
  // Tells the user how big the object is.
  *os << count << "-byte object <";

  const size_t kThreshold = 132;
  const size_t kChunkSize = 64;
  // If the object size is bigger than kThreshold, we'll have to omit
  // some details by printing only the first and the last kChunkSize
  // bytes.
  // TODO(wan): let the user control the threshold using a flag.
  if (count < kThreshold) {
    PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
  } else {
    PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
    *os << " ... ";
    // Rounds up to 2-byte boundary.
    const size_t resume_pos = (count - kChunkSize + 1)/2*2;
    PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
  }
  *os << ">";
}

}  // namespace

namespace internal2 {

// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
// given object.  The delegation simplifies the implementation, which
// uses the << operator and thus is easier done outside of the
// ::testing::internal namespace, which contains a << operator that
// sometimes conflicts with the one in STL.
void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
                          ostream* os) {
  PrintBytesInObjectToImpl(obj_bytes, count, os);
}

}  // namespace internal2

namespace internal {

// Depending on the value of a char (or wchar_t), we print it in one
// of three formats:
//   - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
//   - as a hexidecimal escape sequence (e.g. '\x7F'), or
//   - as a special escape sequence (e.g. '\r', '\n').
enum CharFormat {
  kAsIs,
  kHexEscape,
  kSpecialEscape
};

// Returns true if c is a printable ASCII character.  We test the
// value of c directly instead of calling isprint(), which is buggy on
// Windows Mobile.
inline bool IsPrintableAscii(wchar_t c) {
  return 0x20 <= c && c <= 0x7E;
}

// Prints a wide or narrow char c as a character literal without the
// quotes, escaping it when necessary; returns how c was formatted.
// The template argument UnsignedChar is the unsigned version of Char,
// which is the type of c.
template <typename UnsignedChar, typename Char>
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
  switch (static_cast<wchar_t>(c)) {
    case L'\0':
      *os << "\\0";
      break;
    case L'\'':
      *os << "\\'";
      break;
    case L'\\':
      *os << "\\\\";
      break;
    case L'\a':
      *os << "\\a";
      break;
    case L'\b':
      *os << "\\b";
      break;
    case L'\f':
      *os << "\\f";
      break;
    case L'\n':
      *os << "\\n";
      break;
    case L'\r':
      *os << "\\r";
      break;
    case L'\t':
      *os << "\\t";
      break;
    case L'\v':
      *os << "\\v";
      break;
    default:
      if (IsPrintableAscii(c)) {
        *os << static_cast<char>(c);
        return kAsIs;
      } else {
        *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
        return kHexEscape;
      }
  }
  return kSpecialEscape;
}

// Prints a wchar_t c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted.
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
  switch (c) {
    case L'\'':
      *os << "'";
      return kAsIs;
    case L'"':
      *os << "\\\"";
      return kSpecialEscape;
    default:
      return PrintAsCharLiteralTo<wchar_t>(c, os);
  }
}

// Prints a char c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted.
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
  return PrintAsStringLiteralTo(
      static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
}

// Prints a wide or narrow character c and its code.  '\0' is printed
// as "'\\0'", other unprintable characters are also properly escaped
// using the standard C++ escape sequence.  The template argument
// UnsignedChar is the unsigned version of Char, which is the type of c.
template <typename UnsignedChar, typename Char>
void PrintCharAndCodeTo(Char c, ostream* os) {
  // First, print c as a literal in the most readable form we can find.
  *os << ((sizeof(c) > 1) ? "L'" : "'");
  const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
  *os << "'";

  // To aid user debugging, we also print c's code in decimal, unless
  // it's 0 (in which case c was printed as '\\0', making the code
  // obvious).
  if (c == 0)
    return;
  *os << " (" << static_cast<int>(c);

  // For more convenience, we print c's code again in hexidecimal,
  // unless c was already printed in the form '\x##' or the code is in
  // [1, 9].
  if (format == kHexEscape || (1 <= c && c <= 9)) {
    // Do nothing.
  } else {
    *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
  }
  *os << ")";
}

void PrintTo(unsigned char c, ::std::ostream* os) {
  PrintCharAndCodeTo<unsigned char>(c, os);
}
void PrintTo(signed char c, ::std::ostream* os) {
  PrintCharAndCodeTo<unsigned char>(c, os);
}

// Prints a wchar_t as a symbol if it is printable or as its internal
// code otherwise and also as its code.  L'\0' is printed as "L'\\0'".
void PrintTo(wchar_t wc, ostream* os) {
  PrintCharAndCodeTo<wchar_t>(wc, os);
}

// Prints the given array of characters to the ostream.  CharType must be either
// char or wchar_t.
// The array starts at begin, the length is len, it may include '\0' characters
// and may not be NUL-terminated.
template <typename CharType>
static void PrintCharsAsStringTo(
    const CharType* begin, size_t len, ostream* os) {
  const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
  *os << kQuoteBegin;
  bool is_previous_hex = false;
  for (size_t index = 0; index < len; ++index) {
    const CharType cur = begin[index];
    if (is_previous_hex && IsXDigit(cur)) {
      // Previous character is of '\x..' form and this character can be
      // interpreted as another hexadecimal digit in its number. Break string to
      // disambiguate.
      *os << "\" " << kQuoteBegin;
    }
    is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
  }
  *os << "\"";
}

// Prints a (const) char/wchar_t array of 'len' elements, starting at address
// 'begin'.  CharType must be either char or wchar_t.
template <typename CharType>
static void UniversalPrintCharArray(
    const CharType* begin, size_t len, ostream* os) {
  // The code
  //   const char kFoo[] = "foo";
  // generates an array of 4, not 3, elements, with the last one being '\0'.
  //
  // Therefore when printing a char array, we don't print the last element if
  // it's '\0', such that the output matches the string literal as it's
  // written in the source code.
  if (len > 0 && begin[len - 1] == '\0') {
    PrintCharsAsStringTo(begin, len - 1, os);
    return;
  }

  // If, however, the last element in the array is not '\0', e.g.
  //    const char kFoo[] = { 'f', 'o', 'o' };
  // we must print the entire array.  We also print a message to indicate
  // that the array is not NUL-terminated.
  PrintCharsAsStringTo(begin, len, os);
  *os << " (no terminating NUL)";
}

// Prints a (const) char array of 'len' elements, starting at address 'begin'.
void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
  UniversalPrintCharArray(begin, len, os);
}

// Prints a (const) wchar_t array of 'len' elements, starting at address
// 'begin'.
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
  UniversalPrintCharArray(begin, len, os);
}

// Prints the given C string to the ostream.
void PrintTo(const char* s, ostream* os) {
  if (s == NULL) {
    *os << "NULL";
  } else {
    *os << ImplicitCast_<const void*>(s) << " pointing to ";
    PrintCharsAsStringTo(s, strlen(s), os);
  }
}

// MSVC compiler can be configured to define whar_t as a typedef
// of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings,
// possibly accessing more memory than intended and causing invalid
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
// wchar_t is implemented as a native type.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Prints the given wide C string to the ostream.
void PrintTo(const wchar_t* s, ostream* os) {
  if (s == NULL) {
    *os << "NULL";
  } else {
    *os << ImplicitCast_<const void*>(s) << " pointing to ";
    PrintCharsAsStringTo(s, wcslen(s), os);
  }
}
#endif  // wchar_t is native

// Prints a ::string object.
#if GTEST_HAS_GLOBAL_STRING
void PrintStringTo(const ::string& s, ostream* os) {
  PrintCharsAsStringTo(s.data(), s.size(), os);
}
#endif  // GTEST_HAS_GLOBAL_STRING

void PrintStringTo(const ::std::string& s, ostream* os) {
  PrintCharsAsStringTo(s.data(), s.size(), os);
}

// Prints a ::wstring object.
#if GTEST_HAS_GLOBAL_WSTRING
void PrintWideStringTo(const ::wstring& s, ostream* os) {
  PrintCharsAsStringTo(s.data(), s.size(), os);
}
#endif  // GTEST_HAS_GLOBAL_WSTRING

#if GTEST_HAS_STD_WSTRING
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
  PrintCharsAsStringTo(s.data(), s.size(), os);
}
#endif  // GTEST_HAS_STD_WSTRING

}  // namespace internal

}  // namespace testing
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: mheule@google.com (Markus Heule)
//
// The Google C++ Testing Framework (Google Test)


// Indicates that this translation unit is part of Google Test's
// implementation.  It must come before gtest-internal-inl.h is
// included, or there will be a compiler error.  This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
#undef GTEST_IMPLEMENTATION_

namespace testing {

using internal::GetUnitTestImpl;

// Gets the summary of the failure message by omitting the stack trace
// in it.
std::string TestPartResult::ExtractSummary(const char* message) {
  const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
  return stack_trace == NULL ? message :
      std::string(message, stack_trace);
}

// Prints a TestPartResult object.
std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
  return os
      << result.file_name() << ":" << result.line_number() << ": "
      << (result.type() == TestPartResult::kSuccess ? "Success" :
          result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
          "Non-fatal failure") << ":\n"
      << result.message() << std::endl;
}

// Appends a TestPartResult to the array.
void TestPartResultArray::Append(const TestPartResult& result) {
  array_.push_back(result);
}

// Returns the TestPartResult at the given index (0-based).
const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
  if (index < 0 || index >= size()) {
    printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
    internal::posix::Abort();
  }

  return array_[index];
}

// Returns the number of TestPartResult objects in the array.
int TestPartResultArray::size() const {
  return static_cast<int>(array_.size());
}

namespace internal {

HasNewFatalFailureHelper::HasNewFatalFailureHelper()
    : has_new_fatal_failure_(false),
      original_reporter_(GetUnitTestImpl()->
                         GetTestPartResultReporterForCurrentThread()) {
  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
}

HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
      original_reporter_);
}

void HasNewFatalFailureHelper::ReportTestPartResult(
    const TestPartResult& result) {
  if (result.fatally_failed())
    has_new_fatal_failure_ = true;
  original_reporter_->ReportTestPartResult(result);
}

}  // namespace internal

}  // namespace testing
// Copyright 2008 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)


namespace testing {
namespace internal {

#if GTEST_HAS_TYPED_TEST_P

// Skips to the first non-space char in str. Returns an empty string if str
// contains only whitespace characters.
static const char* SkipSpaces(const char* str) {
  while (IsSpace(*str))
    str++;
  return str;
}

// Verifies that registered_tests match the test names in
// defined_test_names_; returns registered_tests if successful, or
// aborts the program otherwise.
const char* TypedTestCasePState::VerifyRegisteredTestNames(
    const char* file, int line, const char* registered_tests) {
  typedef ::std::set<const char*>::const_iterator DefinedTestIter;
  registered_ = true;

  // Skip initial whitespace in registered_tests since some
  // preprocessors prefix stringizied literals with whitespace.
  registered_tests = SkipSpaces(registered_tests);

  Message errors;
  ::std::set<std::string> tests;
  for (const char* names = registered_tests; names != NULL;
       names = SkipComma(names)) {
    const std::string name = GetPrefixUntilComma(names);
    if (tests.count(name) != 0) {
      errors << "Test " << name << " is listed more than once.\n";
      continue;
    }

    bool found = false;
    for (DefinedTestIter it = defined_test_names_.begin();
         it != defined_test_names_.end();
         ++it) {
      if (name == *it) {
        found = true;
        break;
      }
    }

    if (found) {
      tests.insert(name);
    } else {
      errors << "No test named " << name
             << " can be found in this test case.\n";
    }
  }

  for (DefinedTestIter it = defined_test_names_.begin();
       it != defined_test_names_.end();
       ++it) {
    if (tests.count(*it) == 0) {
      errors << "You forgot to list test " << *it << ".\n";
    }
  }

  const std::string& errors_str = errors.GetString();
  if (errors_str != "") {
    fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
            errors_str.c_str());
    fflush(stderr);
    posix::Abort();
  }

  return registered_tests;
}

#endif  // GTEST_HAS_TYPED_TEST_P

}  // namespace internal
}  // namespace testing
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file defines the public API for Google Test.  It should be
// included by any test program that uses Google Test.
//
// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
// leave some internal implementation details in this header file.
// They are clearly marked by comments like this:
//
//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
//
// Such code is NOT meant to be used by a user directly, and is subject
// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
// program!
//
// Acknowledgment: Google Test borrowed the idea of automatic test
// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
// easyUnit framework.

#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_H_

#include <limits>
#include <ostream>
#include <vector>

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file declares functions and macros used internally by
// Google Test.  They are subject to change without notice.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan)
//
// Low-level types and utilities for porting Google Test to various
// platforms.  They are subject to change without notice.  DO NOT USE
// THEM IN USER CODE.
//
// This file is fundamental to Google Test.  All other Google Test source
// files are expected to #include this.  Therefore, it cannot #include
// any other Google Test header.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

// The user can define the following macros in the build script to
// control Google Test's behavior.  If the user doesn't define a macro
// in this list, Google Test will define it.
//
//   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)
//                              is/isn't available.
//   GTEST_HAS_EXCEPTIONS     - Define it to 1/0 to indicate that exceptions
//                              are enabled.
//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string
//                              is/isn't available (some systems define
//                              ::string, which is different to std::string).
//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
//                              is/isn't available (some systems define
//                              ::wstring, which is different to std::wstring).
//   GTEST_HAS_POSIX_RE       - Define it to 1/0 to indicate that POSIX regular
//                              expressions are/aren't available.
//   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>
//                              is/isn't available.
//   GTEST_HAS_RTTI           - Define it to 1/0 to indicate that RTTI is/isn't
//                              enabled.
//   GTEST_HAS_STD_WSTRING    - Define it to 1/0 to indicate that
//                              std::wstring does/doesn't work (Google Test can
//                              be used where std::wstring is unavailable).
//   GTEST_HAS_TR1_TUPLE      - Define it to 1/0 to indicate tr1::tuple
//                              is/isn't available.
//   GTEST_HAS_SEH            - Define it to 1/0 to indicate whether the
//                              compiler supports Microsoft's "Structured
//                              Exception Handling".
//   GTEST_HAS_STREAM_REDIRECTION
//                            - Define it to 1/0 to indicate whether the
//                              platform supports I/O stream redirection using
//                              dup() and dup2().
//   GTEST_USE_OWN_TR1_TUPLE  - Define it to 1/0 to indicate whether Google
//                              Test's own tr1 tuple implementation should be
//                              used.  Unused when the user sets
//                              GTEST_HAS_TR1_TUPLE to 0.
//   GTEST_LANG_CXX11         - Define it to 1/0 to indicate that Google Test
//                              is building in C++11/C++98 mode.
//   GTEST_LINKED_AS_SHARED_LIBRARY
//                            - Define to 1 when compiling tests that use
//                              Google Test as a shared library (known as
//                              DLL on Windows).
//   GTEST_CREATE_SHARED_LIBRARY
//                            - Define to 1 when compiling Google Test itself
//                              as a shared library.

// This header defines the following utilities:
//
// Macros indicating the current platform (defined to 1 if compiled on
// the given platform; otherwise undefined):
//   GTEST_OS_AIX      - IBM AIX
//   GTEST_OS_CYGWIN   - Cygwin
//   GTEST_OS_HPUX     - HP-UX
//   GTEST_OS_LINUX    - Linux
//     GTEST_OS_LINUX_ANDROID - Google Android
//   GTEST_OS_MAC      - Mac OS X
//     GTEST_OS_IOS    - iOS
//       GTEST_OS_IOS_SIMULATOR - iOS simulator
//   GTEST_OS_NACL     - Google Native Client (NaCl)
//   GTEST_OS_OPENBSD  - OpenBSD
//   GTEST_OS_QNX      - QNX
//   GTEST_OS_SOLARIS  - Sun Solaris
//   GTEST_OS_SYMBIAN  - Symbian
//   GTEST_OS_WINDOWS  - Windows (Desktop, MinGW, or Mobile)
//     GTEST_OS_WINDOWS_DESKTOP  - Windows Desktop
//     GTEST_OS_WINDOWS_MINGW    - MinGW
//     GTEST_OS_WINDOWS_MOBILE   - Windows Mobile
//   GTEST_OS_ZOS      - z/OS
//
// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
// most stable support.  Since core members of the Google Test project
// don't have access to other platforms, support for them may be less
// stable.  If you notice any problems on your platform, please notify
// googletestframework@googlegroups.com (patches for fixing them are
// even more welcome!).
//
// Note that it is possible that none of the GTEST_OS_* macros are defined.
//
// Macros indicating available Google Test features (defined to 1 if
// the corresponding feature is supported; otherwise undefined):
//   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized
//                            tests)
//   GTEST_HAS_DEATH_TEST   - death tests
//   GTEST_HAS_PARAM_TEST   - value-parameterized tests
//   GTEST_HAS_TYPED_TEST   - typed tests
//   GTEST_HAS_TYPED_TEST_P - type-parameterized tests
//   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used. Do not confuse with
//                            GTEST_HAS_POSIX_RE (see above) which users can
//                            define themselves.
//   GTEST_USES_SIMPLE_RE   - our own simple regex is used;
//                            the above two are mutually exclusive.
//   GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
//
// Macros for basic C++ coding:
//   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
//   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a
//                              variable don't have to be used.
//   GTEST_DISALLOW_ASSIGN_   - disables operator=.
//   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
//   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
//
// Synchronization:
//   Mutex, MutexLock, ThreadLocal, GetThreadCount()
//                  - synchronization primitives.
//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
//                         synchronization primitives have real implementations
//                         and Google Test is thread-safe; or 0 otherwise.
//
// Template meta programming:
//   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.
//   IteratorTraits - partial implementation of std::iterator_traits, which
//                    is not available in libCstd when compiled with Sun C++.
//
// Smart pointers:
//   scoped_ptr     - as in TR2.
//
// Regular expressions:
//   RE             - a simple regular expression class using the POSIX
//                    Extended Regular Expression syntax on UNIX-like
//                    platforms, or a reduced regular exception syntax on
//                    other platforms, including Windows.
//
// Logging:
//   GTEST_LOG_()   - logs messages at the specified severity level.
//   LogToStderr()  - directs all log messages to stderr.
//   FlushInfoLog() - flushes informational log messages.
//
// Stdout and stderr capturing:
//   CaptureStdout()     - starts capturing stdout.
//   GetCapturedStdout() - stops capturing stdout and returns the captured
//                         string.
//   CaptureStderr()     - starts capturing stderr.
//   GetCapturedStderr() - stops capturing stderr and returns the captured
//                         string.
//
// Integer types:
//   TypeWithSize   - maps an integer to a int type.
//   Int32, UInt32, Int64, UInt64, TimeInMillis
//                  - integers of known sizes.
//   BiggestInt     - the biggest signed integer type.
//
// Command-line utilities:
//   GTEST_FLAG()       - references a flag.
//   GTEST_DECLARE_*()  - declares a flag.
//   GTEST_DEFINE_*()   - defines a flag.
//   GetInjectableArgvs() - returns the command line as a vector of strings.
//
// Environment variable utilities:
//   GetEnv()             - gets the value of an environment variable.
//   BoolFromGTestEnv()   - parses a bool environment variable.
//   Int32FromGTestEnv()  - parses an Int32 environment variable.
//   StringFromGTestEnv() - parses a string environment variable.

#include <ctype.h>   // for isspace, etc
#include <stddef.h>  // for ptrdiff_t
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef _WIN32_WCE
# include <sys/types.h>
# include <sys/stat.h>
#endif  // !_WIN32_WCE

#if defined __APPLE__
# include <AvailabilityMacros.h>
# include <TargetConditionals.h>
#endif

#include <iostream>  // NOLINT
#include <sstream>  // NOLINT
#include <string>  // NOLINT

#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
#define GTEST_FLAG_PREFIX_ "gtest_"
#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
#define GTEST_NAME_ "Google Test"
#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"

// Determines the version of gcc that is used to compile this.
#ifdef __GNUC__
// 40302 means version 4.3.2.
# define GTEST_GCC_VER_ \
    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
#endif  // __GNUC__

// Determines the platform on which Google Test is compiled.
#ifdef __CYGWIN__
# define GTEST_OS_CYGWIN 1
#elif defined __SYMBIAN32__
# define GTEST_OS_SYMBIAN 1
#elif defined _WIN32
# define GTEST_OS_WINDOWS 1
# ifdef _WIN32_WCE
#  define GTEST_OS_WINDOWS_MOBILE 1
# elif defined(__MINGW__) || defined(__MINGW32__)
#  define GTEST_OS_WINDOWS_MINGW 1
# else
#  define GTEST_OS_WINDOWS_DESKTOP 1
# endif  // _WIN32_WCE
#elif defined __APPLE__
# define GTEST_OS_MAC 1
# if TARGET_OS_IPHONE
#  define GTEST_OS_IOS 1
#  if TARGET_IPHONE_SIMULATOR
#   define GTEST_OS_IOS_SIMULATOR 1
#  endif
# endif
#elif defined __linux__
# define GTEST_OS_LINUX 1
# if defined __ANDROID__
#  define GTEST_OS_LINUX_ANDROID 1
# endif
#elif defined __MVS__
# define GTEST_OS_ZOS 1
#elif defined(__sun) && defined(__SVR4)
# define GTEST_OS_SOLARIS 1
#elif defined(_AIX)
# define GTEST_OS_AIX 1
#elif defined(__hpux)
# define GTEST_OS_HPUX 1
#elif defined __native_client__
# define GTEST_OS_NACL 1
#elif defined __OpenBSD__
# define GTEST_OS_OPENBSD 1
#elif defined __QNX__
# define GTEST_OS_QNX 1
#endif  // __CYGWIN__

#ifndef GTEST_LANG_CXX11
// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
// -std={c,gnu}++{0x,11} is passed.  The C++11 standard specifies a
// value for __cplusplus, and recent versions of clang, gcc, and
// probably other compilers set that too in C++11 mode.
# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
// Compiling in at least C++11 mode.
#  define GTEST_LANG_CXX11 1
# else
#  define GTEST_LANG_CXX11 0
# endif
#endif

// Brings in definitions for functions used in the testing::internal::posix
// namespace (read, write, close, chdir, isatty, stat). We do not currently
// use them on Windows Mobile.
#if !GTEST_OS_WINDOWS
// This assumes that non-Windows OSes provide unistd.h. For OSes where this
// is not the case, we need to include headers that provide the functions
// mentioned above.
# include <unistd.h>
# include <strings.h>
#elif !GTEST_OS_WINDOWS_MOBILE
# include <direct.h>
# include <io.h>
#endif

#if GTEST_OS_LINUX_ANDROID
// Used to define __ANDROID_API__ matching the target NDK API level.
#  include <android/api-level.h>  // NOLINT
#endif

// Defines this to true iff Google Test can use POSIX regular expressions.
#ifndef GTEST_HAS_POSIX_RE
# if GTEST_OS_LINUX_ANDROID
// On Android, <regex.h> is only available starting with Gingerbread.
#  define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
# else
#  define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
# endif
#endif

#if GTEST_HAS_POSIX_RE

// On some platforms, <regex.h> needs someone to define size_t, and
// won't compile otherwise.  We can #include it here as we already
// included <stdlib.h>, which is guaranteed to define size_t through
// <stddef.h>.
# include <regex.h>  // NOLINT

# define GTEST_USES_POSIX_RE 1

#elif GTEST_OS_WINDOWS

// <regex.h> is not available on Windows.  Use our own simple regex
// implementation instead.
# define GTEST_USES_SIMPLE_RE 1

#else

// <regex.h> may not be available on this platform.  Use our own
// simple regex implementation instead.
# define GTEST_USES_SIMPLE_RE 1

#endif  // GTEST_HAS_POSIX_RE

#ifndef GTEST_HAS_EXCEPTIONS
// The user didn't tell us whether exceptions are enabled, so we need
// to figure it out.
# if defined(_MSC_VER) || defined(__BORLANDC__)
// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
// macro to enable exceptions, so we'll do the same.
// Assumes that exceptions are enabled by default.
#  ifndef _HAS_EXCEPTIONS
#   define _HAS_EXCEPTIONS 1
#  endif  // _HAS_EXCEPTIONS
#  define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
# elif defined(__GNUC__) && __EXCEPTIONS
// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
#  define GTEST_HAS_EXCEPTIONS 1
# elif defined(__SUNPRO_CC)
// Sun Pro CC supports exceptions.  However, there is no compile-time way of
// detecting whether they are enabled or not.  Therefore, we assume that
// they are enabled unless the user tells us otherwise.
#  define GTEST_HAS_EXCEPTIONS 1
# elif defined(__IBMCPP__) && __EXCEPTIONS
// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
#  define GTEST_HAS_EXCEPTIONS 1
# elif defined(__HP_aCC)
// Exception handling is in effect by default in HP aCC compiler. It has to
// be turned of by +noeh compiler option if desired.
#  define GTEST_HAS_EXCEPTIONS 1
# else
// For other compilers, we assume exceptions are disabled to be
// conservative.
#  define GTEST_HAS_EXCEPTIONS 0
# endif  // defined(_MSC_VER) || defined(__BORLANDC__)
#endif  // GTEST_HAS_EXCEPTIONS

#if !defined(GTEST_HAS_STD_STRING)
// Even though we don't use this macro any longer, we keep it in case
// some clients still depend on it.
# define GTEST_HAS_STD_STRING 1
#elif !GTEST_HAS_STD_STRING
// The user told us that ::std::string isn't available.
# error "Google Test cannot be used where ::std::string isn't available."
#endif  // !defined(GTEST_HAS_STD_STRING)

#ifndef GTEST_HAS_GLOBAL_STRING
// The user didn't tell us whether ::string is available, so we need
// to figure it out.

# define GTEST_HAS_GLOBAL_STRING 0

#endif  // GTEST_HAS_GLOBAL_STRING

#ifndef GTEST_HAS_STD_WSTRING
// The user didn't tell us whether ::std::wstring is available, so we need
// to figure it out.
// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
//   is available.

// Cygwin 1.7 and below doesn't support ::std::wstring.
// Solaris' libc++ doesn't support it either.  Android has
// no support for it at least as recent as Froyo (2.2).
# define GTEST_HAS_STD_WSTRING \
    (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))

#endif  // GTEST_HAS_STD_WSTRING

#ifndef GTEST_HAS_GLOBAL_WSTRING
// The user didn't tell us whether ::wstring is available, so we need
// to figure it out.
# define GTEST_HAS_GLOBAL_WSTRING \
    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
#endif  // GTEST_HAS_GLOBAL_WSTRING

// Determines whether RTTI is available.
#ifndef GTEST_HAS_RTTI
// The user didn't tell us whether RTTI is enabled, so we need to
// figure it out.

# ifdef _MSC_VER

#  ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.
#   define GTEST_HAS_RTTI 1
#  else
#   define GTEST_HAS_RTTI 0
#  endif

// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)

#  ifdef __GXX_RTTI
// When building against STLport with the Android NDK and with
// -frtti -fno-exceptions, the build fails at link time with undefined
// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
// so disable RTTI when detected.
#   if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
       !defined(__EXCEPTIONS)
#    define GTEST_HAS_RTTI 0
#   else
#    define GTEST_HAS_RTTI 1
#   endif  // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
#  else
#   define GTEST_HAS_RTTI 0
#  endif  // __GXX_RTTI

// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
// first version with C++ support.
# elif defined(__clang__)

#  define GTEST_HAS_RTTI __has_feature(cxx_rtti)

// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
// both the typeid and dynamic_cast features are present.
# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)

#  ifdef __RTTI_ALL__
#   define GTEST_HAS_RTTI 1
#  else
#   define GTEST_HAS_RTTI 0
#  endif

# else

// For all other compilers, we assume RTTI is enabled.
#  define GTEST_HAS_RTTI 1

# endif  // _MSC_VER

#endif  // GTEST_HAS_RTTI

// It's this header's responsibility to #include <typeinfo> when RTTI
// is enabled.
#if GTEST_HAS_RTTI
# include <typeinfo>
#endif

// Determines whether Google Test can use the pthreads library.
#ifndef GTEST_HAS_PTHREAD
// The user didn't tell us explicitly, so we assume pthreads support is
// available on Linux and Mac.
//
// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
// to your compiler flags.
# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
    || GTEST_OS_QNX)
#endif  // GTEST_HAS_PTHREAD

#if GTEST_HAS_PTHREAD
// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
// true.
# include <pthread.h>  // NOLINT

// For timespec and nanosleep, used below.
# include <time.h>  // NOLINT
#endif

// Determines whether Google Test can use tr1/tuple.  You can define
// this macro to 0 to prevent Google Test from using tuple (any
// feature depending on tuple with be disabled in this mode).
#ifndef GTEST_HAS_TR1_TUPLE
# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
#  define GTEST_HAS_TR1_TUPLE 0
# else
// The user didn't tell us not to do it, so we assume it's OK.
#  define GTEST_HAS_TR1_TUPLE 1
# endif
#endif  // GTEST_HAS_TR1_TUPLE

// Determines whether Google Test's own tr1 tuple implementation
// should be used.
#ifndef GTEST_USE_OWN_TR1_TUPLE
// The user didn't tell us, so we need to figure it out.

// We use our own TR1 tuple if we aren't sure the user has an
// implementation of it already.  At this time, libstdc++ 4.0.0+ and
// MSVC 2010 are the only mainstream standard libraries that come
// with a TR1 tuple implementation.  NVIDIA's CUDA NVCC compiler
// pretends to be GCC by defining __GNUC__ and friends, but cannot
// compile GCC's tuple implementation.  MSVC 2008 (9.0) provides TR1
// tuple in a 323 MB Feature Pack download, which we cannot assume the
// user has.  QNX's QCC compiler is a modified GCC but it doesn't
// support TR1 tuple.  libc++ only provides std::tuple, in C++11 mode,
// and it can be used with some compilers that define __GNUC__.
# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
      && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
#  define GTEST_ENV_HAS_TR1_TUPLE_ 1
# endif

// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
// can build with clang but need to use gcc4.2's libstdc++).
# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
#  define GTEST_ENV_HAS_STD_TUPLE_ 1
# endif

# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
#  define GTEST_USE_OWN_TR1_TUPLE 0
# else
#  define GTEST_USE_OWN_TR1_TUPLE 1
# endif

#endif  // GTEST_USE_OWN_TR1_TUPLE

// To avoid conditional compilation everywhere, we make it
// gtest-port.h's responsibility to #include the header implementing
// tr1/tuple.
#if GTEST_HAS_TR1_TUPLE

# if GTEST_USE_OWN_TR1_TUPLE
// This file was GENERATED by command:
//     pump.py gtest-tuple.h.pump
// DO NOT EDIT BY HAND!!!

// Copyright 2009 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)

// Implements a subset of TR1 tuple needed by Google Test and Google Mock.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_

#include <utility>  // For ::std::pair.

// The compiler used in Symbian has a bug that prevents us from declaring the
// tuple template as a friend (it complains that tuple is redefined).  This
// hack bypasses the bug by declaring the members that should otherwise be
// private as public.
// Sun Studio versions < 12 also have the above bug.
#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
#else
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
    template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
   private:
#endif

// GTEST_n_TUPLE_(T) is the type of an n-tuple.
#define GTEST_0_TUPLE_(T) tuple<>
#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
    void, void, void>
#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
    void, void, void>
#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
    void, void, void>
#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
    void, void, void>
#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
    void, void, void>
#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
    void, void, void>
#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
    void, void, void>
#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
    T##7, void, void>
#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
    T##7, T##8, void>
#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
    T##7, T##8, T##9>

// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
#define GTEST_0_TYPENAMES_(T)
#define GTEST_1_TYPENAMES_(T) typename T##0
#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3
#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4
#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4, typename T##5
#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4, typename T##5, typename T##6
#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4, typename T##5, typename T##6, \
    typename T##7, typename T##8
#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
    typename T##3, typename T##4, typename T##5, typename T##6, \
    typename T##7, typename T##8, typename T##9

// In theory, defining stuff in the ::std namespace is undefined
// behavior.  We can do this as we are playing the role of a standard
// library vendor.
namespace std {
namespace tr1 {

template <typename T0 = void, typename T1 = void, typename T2 = void,
    typename T3 = void, typename T4 = void, typename T5 = void,
    typename T6 = void, typename T7 = void, typename T8 = void,
    typename T9 = void>
class tuple;

// Anything in namespace gtest_internal is Google Test's INTERNAL
// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
namespace gtest_internal {

// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
template <typename T>
struct ByRef { typedef const T& type; };  // NOLINT
template <typename T>
struct ByRef<T&> { typedef T& type; };  // NOLINT

// A handy wrapper for ByRef.
#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type

// AddRef<T>::type is T if T is a reference; otherwise it's T&.  This
// is the same as tr1::add_reference<T>::type.
template <typename T>
struct AddRef { typedef T& type; };  // NOLINT
template <typename T>
struct AddRef<T&> { typedef T& type; };  // NOLINT

// A handy wrapper for AddRef.
#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type

// A helper for implementing get<k>().
template <int k> class Get;

// A helper for implementing tuple_element<k, T>.  kIndexValid is true
// iff k < the number of fields in tuple type T.
template <bool kIndexValid, int kIndex, class Tuple>
struct TupleElement;

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
  typedef T0 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
  typedef T1 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
  typedef T2 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
  typedef T3 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
  typedef T4 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
  typedef T5 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
  typedef T6 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
  typedef T7 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
  typedef T8 type;
};

template <GTEST_10_TYPENAMES_(T)>
struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
  typedef T9 type;
};

}  // namespace gtest_internal

template <>
class tuple<> {
 public:
  tuple() {}
  tuple(const tuple& /* t */)  {}
  tuple& operator=(const tuple& /* t */) { return *this; }
};

template <GTEST_1_TYPENAMES_(T)>
class GTEST_1_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}

  tuple(const tuple& t) : f0_(t.f0_) {}

  template <GTEST_1_TYPENAMES_(U)>
  tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_1_TYPENAMES_(U)>
  tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_1_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
    f0_ = t.f0_;
    return *this;
  }

  T0 f0_;
};

template <GTEST_2_TYPENAMES_(T)>
class GTEST_2_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
      f1_(f1) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}

  template <GTEST_2_TYPENAMES_(U)>
  tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
  template <typename U0, typename U1>
  tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_2_TYPENAMES_(U)>
  tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
    return CopyFrom(t);
  }
  template <typename U0, typename U1>
  tuple& operator=(const ::std::pair<U0, U1>& p) {
    f0_ = p.first;
    f1_ = p.second;
    return *this;
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_2_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
};

template <GTEST_3_TYPENAMES_(T)>
class GTEST_3_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}

  template <GTEST_3_TYPENAMES_(U)>
  tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_3_TYPENAMES_(U)>
  tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_3_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
};

template <GTEST_4_TYPENAMES_(T)>
class GTEST_4_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
      f3_(f3) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}

  template <GTEST_4_TYPENAMES_(U)>
  tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_4_TYPENAMES_(U)>
  tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_4_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
};

template <GTEST_5_TYPENAMES_(T)>
class GTEST_5_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
      GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_) {}

  template <GTEST_5_TYPENAMES_(U)>
  tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_5_TYPENAMES_(U)>
  tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_5_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
};

template <GTEST_6_TYPENAMES_(T)>
class GTEST_6_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
      GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
      f5_(f5) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_), f5_(t.f5_) {}

  template <GTEST_6_TYPENAMES_(U)>
  tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_6_TYPENAMES_(U)>
  tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_6_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    f5_ = t.f5_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
  T5 f5_;
};

template <GTEST_7_TYPENAMES_(T)>
class GTEST_7_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
      f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}

  template <GTEST_7_TYPENAMES_(U)>
  tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_7_TYPENAMES_(U)>
  tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_7_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    f5_ = t.f5_;
    f6_ = t.f6_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
  T5 f5_;
  T6 f6_;
};

template <GTEST_8_TYPENAMES_(T)>
class GTEST_8_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
      GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
      f5_(f5), f6_(f6), f7_(f7) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}

  template <GTEST_8_TYPENAMES_(U)>
  tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_8_TYPENAMES_(U)>
  tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_8_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    f5_ = t.f5_;
    f6_ = t.f6_;
    f7_ = t.f7_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
  T5 f5_;
  T6 f6_;
  T7 f7_;
};

template <GTEST_9_TYPENAMES_(T)>
class GTEST_9_TUPLE_(T) {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
      GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
      f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}

  template <GTEST_9_TYPENAMES_(U)>
  tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_9_TYPENAMES_(U)>
  tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_9_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    f5_ = t.f5_;
    f6_ = t.f6_;
    f7_ = t.f7_;
    f8_ = t.f8_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
  T5 f5_;
  T6 f6_;
  T7 f7_;
  T8 f8_;
};

template <GTEST_10_TYPENAMES_(T)>
class tuple {
 public:
  template <int k> friend class gtest_internal::Get;

  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
      f9_() {}

  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
      GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
      f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}

  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}

  template <GTEST_10_TYPENAMES_(U)>
  tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
      f9_(t.f9_) {}

  tuple& operator=(const tuple& t) { return CopyFrom(t); }

  template <GTEST_10_TYPENAMES_(U)>
  tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
    return CopyFrom(t);
  }

  GTEST_DECLARE_TUPLE_AS_FRIEND_

  template <GTEST_10_TYPENAMES_(U)>
  tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
    f0_ = t.f0_;
    f1_ = t.f1_;
    f2_ = t.f2_;
    f3_ = t.f3_;
    f4_ = t.f4_;
    f5_ = t.f5_;
    f6_ = t.f6_;
    f7_ = t.f7_;
    f8_ = t.f8_;
    f9_ = t.f9_;
    return *this;
  }

  T0 f0_;
  T1 f1_;
  T2 f2_;
  T3 f3_;
  T4 f4_;
  T5 f5_;
  T6 f6_;
  T7 f7_;
  T8 f8_;
  T9 f9_;
};

// 6.1.3.2 Tuple creation functions.

// Known limitations: we don't support passing an
// std::tr1::reference_wrapper<T> to make_tuple().  And we don't
// implement tie().

inline tuple<> make_tuple() { return tuple<>(); }

template <GTEST_1_TYPENAMES_(T)>
inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
  return GTEST_1_TUPLE_(T)(f0);
}

template <GTEST_2_TYPENAMES_(T)>
inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
  return GTEST_2_TUPLE_(T)(f0, f1);
}

template <GTEST_3_TYPENAMES_(T)>
inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
  return GTEST_3_TUPLE_(T)(f0, f1, f2);
}

template <GTEST_4_TYPENAMES_(T)>
inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3) {
  return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
}

template <GTEST_5_TYPENAMES_(T)>
inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4) {
  return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
}

template <GTEST_6_TYPENAMES_(T)>
inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4, const T5& f5) {
  return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
}

template <GTEST_7_TYPENAMES_(T)>
inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
  return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
}

template <GTEST_8_TYPENAMES_(T)>
inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
  return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
}

template <GTEST_9_TYPENAMES_(T)>
inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
    const T8& f8) {
  return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
}

template <GTEST_10_TYPENAMES_(T)>
inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
    const T8& f8, const T9& f9) {
  return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
}

// 6.1.3.3 Tuple helper classes.

template <typename Tuple> struct tuple_size;

template <GTEST_0_TYPENAMES_(T)>
struct tuple_size<GTEST_0_TUPLE_(T) > {
  static const int value = 0;
};

template <GTEST_1_TYPENAMES_(T)>
struct tuple_size<GTEST_1_TUPLE_(T) > {
  static const int value = 1;
};

template <GTEST_2_TYPENAMES_(T)>
struct tuple_size<GTEST_2_TUPLE_(T) > {
  static const int value = 2;
};

template <GTEST_3_TYPENAMES_(T)>
struct tuple_size<GTEST_3_TUPLE_(T) > {
  static const int value = 3;
};

template <GTEST_4_TYPENAMES_(T)>
struct tuple_size<GTEST_4_TUPLE_(T) > {
  static const int value = 4;
};

template <GTEST_5_TYPENAMES_(T)>
struct tuple_size<GTEST_5_TUPLE_(T) > {
  static const int value = 5;
};

template <GTEST_6_TYPENAMES_(T)>
struct tuple_size<GTEST_6_TUPLE_(T) > {
  static const int value = 6;
};

template <GTEST_7_TYPENAMES_(T)>
struct tuple_size<GTEST_7_TUPLE_(T) > {
  static const int value = 7;
};

template <GTEST_8_TYPENAMES_(T)>
struct tuple_size<GTEST_8_TUPLE_(T) > {
  static const int value = 8;
};

template <GTEST_9_TYPENAMES_(T)>
struct tuple_size<GTEST_9_TUPLE_(T) > {
  static const int value = 9;
};

template <GTEST_10_TYPENAMES_(T)>
struct tuple_size<GTEST_10_TUPLE_(T) > {
  static const int value = 10;
};

template <int k, class Tuple>
struct tuple_element {
  typedef typename gtest_internal::TupleElement<
      k < (tuple_size<Tuple>::value), k, Tuple>::type type;
};

#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type

// 6.1.3.4 Element access.

namespace gtest_internal {

template <>
class Get<0> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
  Field(Tuple& t) { return t.f0_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
  ConstField(const Tuple& t) { return t.f0_; }
};

template <>
class Get<1> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
  Field(Tuple& t) { return t.f1_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
  ConstField(const Tuple& t) { return t.f1_; }
};

template <>
class Get<2> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
  Field(Tuple& t) { return t.f2_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
  ConstField(const Tuple& t) { return t.f2_; }
};

template <>
class Get<3> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
  Field(Tuple& t) { return t.f3_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
  ConstField(const Tuple& t) { return t.f3_; }
};

template <>
class Get<4> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
  Field(Tuple& t) { return t.f4_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
  ConstField(const Tuple& t) { return t.f4_; }
};

template <>
class Get<5> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
  Field(Tuple& t) { return t.f5_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
  ConstField(const Tuple& t) { return t.f5_; }
};

template <>
class Get<6> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
  Field(Tuple& t) { return t.f6_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
  ConstField(const Tuple& t) { return t.f6_; }
};

template <>
class Get<7> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
  Field(Tuple& t) { return t.f7_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
  ConstField(const Tuple& t) { return t.f7_; }
};

template <>
class Get<8> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
  Field(Tuple& t) { return t.f8_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
  ConstField(const Tuple& t) { return t.f8_; }
};

template <>
class Get<9> {
 public:
  template <class Tuple>
  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
  Field(Tuple& t) { return t.f9_; }  // NOLINT

  template <class Tuple>
  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
  ConstField(const Tuple& t) { return t.f9_; }
};

}  // namespace gtest_internal

template <int k, GTEST_10_TYPENAMES_(T)>
GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
get(GTEST_10_TUPLE_(T)& t) {
  return gtest_internal::Get<k>::Field(t);
}

template <int k, GTEST_10_TYPENAMES_(T)>
GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k,  GTEST_10_TUPLE_(T)))
get(const GTEST_10_TUPLE_(T)& t) {
  return gtest_internal::Get<k>::ConstField(t);
}

// 6.1.3.5 Relational operators

// We only implement == and !=, as we don't have a need for the rest yet.

namespace gtest_internal {

// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
// first k fields of t1 equals the first k fields of t2.
// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
// k1 != k2.
template <int kSize1, int kSize2>
struct SameSizeTuplePrefixComparator;

template <>
struct SameSizeTuplePrefixComparator<0, 0> {
  template <class Tuple1, class Tuple2>
  static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
    return true;
  }
};

template <int k>
struct SameSizeTuplePrefixComparator<k, k> {
  template <class Tuple1, class Tuple2>
  static bool Eq(const Tuple1& t1, const Tuple2& t2) {
    return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
        ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
  }
};

}  // namespace gtest_internal

template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
inline bool operator==(const GTEST_10_TUPLE_(T)& t,
                       const GTEST_10_TUPLE_(U)& u) {
  return gtest_internal::SameSizeTuplePrefixComparator<
      tuple_size<GTEST_10_TUPLE_(T) >::value,
      tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
}

template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
                       const GTEST_10_TUPLE_(U)& u) { return !(t == u); }

// 6.1.4 Pairs.
// Unimplemented.

}  // namespace tr1
}  // namespace std

#undef GTEST_0_TUPLE_
#undef GTEST_1_TUPLE_
#undef GTEST_2_TUPLE_
#undef GTEST_3_TUPLE_
#undef GTEST_4_TUPLE_
#undef GTEST_5_TUPLE_
#undef GTEST_6_TUPLE_
#undef GTEST_7_TUPLE_
#undef GTEST_8_TUPLE_
#undef GTEST_9_TUPLE_
#undef GTEST_10_TUPLE_

#undef GTEST_0_TYPENAMES_
#undef GTEST_1_TYPENAMES_
#undef GTEST_2_TYPENAMES_
#undef GTEST_3_TYPENAMES_
#undef GTEST_4_TYPENAMES_
#undef GTEST_5_TYPENAMES_
#undef GTEST_6_TYPENAMES_
#undef GTEST_7_TYPENAMES_
#undef GTEST_8_TYPENAMES_
#undef GTEST_9_TYPENAMES_
#undef GTEST_10_TYPENAMES_

#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
#undef GTEST_BY_REF_
#undef GTEST_ADD_REF_
#undef GTEST_TUPLE_ELEMENT_

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
# elif GTEST_ENV_HAS_STD_TUPLE_
#  include <tuple>
// C++11 puts its tuple into the ::std namespace rather than
// ::std::tr1.  gtest expects tuple to live in ::std::tr1, so put it there.
// This causes undefined behavior, but supported compilers react in
// the way we intend.
namespace std {
namespace tr1 {
using ::std::get;
using ::std::make_tuple;
using ::std::tuple;
using ::std::tuple_element;
using ::std::tuple_size;
}
}

# elif GTEST_OS_SYMBIAN

// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
// use STLport's tuple implementation, which unfortunately doesn't
// work as the copy of STLport distributed with Symbian is incomplete.
// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
// use its own tuple implementation.
#  ifdef BOOST_HAS_TR1_TUPLE
#   undef BOOST_HAS_TR1_TUPLE
#  endif  // BOOST_HAS_TR1_TUPLE

// This prevents <boost/tr1/detail/config.hpp>, which defines
// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
#  define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
#  include <tuple>

# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does
// not conform to the TR1 spec, which requires the header to be <tuple>.

#  if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
// which is #included by <tr1/tuple>, to not compile when RTTI is
// disabled.  _TR1_FUNCTIONAL is the header guard for
// <tr1/functional>.  Hence the following #define is a hack to prevent
// <tr1/functional> from being included.
#   define _TR1_FUNCTIONAL 1
#   include <tr1/tuple>
#   undef _TR1_FUNCTIONAL  // Allows the user to #include
                        // <tr1/functional> if he chooses to.
#  else
#   include <tr1/tuple>  // NOLINT
#  endif  // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302

# else
// If the compiler is not GCC 4.0+, we assume the user is using a
// spec-conforming TR1 implementation.
#  include <tuple>  // NOLINT
# endif  // GTEST_USE_OWN_TR1_TUPLE

#endif  // GTEST_HAS_TR1_TUPLE

// Determines whether clone(2) is supported.
// Usually it will only be available on Linux, excluding
// Linux on the Itanium architecture.
// Also see http://linux.die.net/man/2/clone.
#ifndef GTEST_HAS_CLONE
// The user didn't tell us, so we need to figure it out.

# if GTEST_OS_LINUX && !defined(__ia64__)
#  if GTEST_OS_LINUX_ANDROID
// On Android, clone() is only available on ARM starting with Gingerbread.
#    if defined(__arm__) && __ANDROID_API__ >= 9
#     define GTEST_HAS_CLONE 1
#    else
#     define GTEST_HAS_CLONE 0
#    endif
#  else
#   define GTEST_HAS_CLONE 1
#  endif
# else
#  define GTEST_HAS_CLONE 0
# endif  // GTEST_OS_LINUX && !defined(__ia64__)

#endif  // GTEST_HAS_CLONE

// Determines whether to support stream redirection. This is used to test
// output correctness and to implement death tests.
#ifndef GTEST_HAS_STREAM_REDIRECTION
// By default, we assume that stream redirection is supported on all
// platforms except known mobile ones.
# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
#  define GTEST_HAS_STREAM_REDIRECTION 0
# else
#  define GTEST_HAS_STREAM_REDIRECTION 1
# endif  // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
#endif  // GTEST_HAS_STREAM_REDIRECTION

// Determines whether to support death tests.
// Google Test does not support death tests for VC 7.1 and earlier as
// abort() in a VC 7.1 application compiled as GUI in debug config
// pops up a dialog window that cannot be suppressed programmatically.
#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
     (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
     (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
     GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
     GTEST_OS_OPENBSD || GTEST_OS_QNX)
# define GTEST_HAS_DEATH_TEST 1
# include <vector>  // NOLINT
#endif

// We don't support MSVC 7.1 with exceptions disabled now.  Therefore
// all the compilers we care about are adequate for supporting
// value-parameterized tests.
#define GTEST_HAS_PARAM_TEST 1

// Determines whether to support type-driven tests.

// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
// Sun Pro CC, IBM Visual Age, and HP aCC support.
#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
    defined(__IBMCPP__) || defined(__HP_aCC)
# define GTEST_HAS_TYPED_TEST 1
# define GTEST_HAS_TYPED_TEST_P 1
#endif

// Determines whether to support Combine(). This only makes sense when
// value-parameterized tests are enabled.  The implementation doesn't
// work on Sun Studio since it doesn't understand templated conversion
// operators.
#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
# define GTEST_HAS_COMBINE 1
#endif

// Determines whether the system compiler uses UTF-16 for encoding wide strings.
#define GTEST_WIDE_STRING_USES_UTF16_ \
    (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)

// Determines whether test results can be streamed to a socket.
#if GTEST_OS_LINUX
# define GTEST_CAN_STREAM_RESULTS_ 1
#endif

// Defines some utility macros.

// The GNU compiler emits a warning if nested "if" statements are followed by
// an "else" statement and braces are not used to explicitly disambiguate the
// "else" binding.  This leads to problems with code like:
//
//   if (gate)
//     ASSERT_*(condition) << "Some message";
//
// The "switch (0) case 0:" idiom is used to suppress this.
#ifdef __INTEL_COMPILER
# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
#else
# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default:  // NOLINT
#endif

// Use this annotation at the end of a struct/class definition to
// prevent the compiler from optimizing away instances that are never
// used.  This is useful when all interesting logic happens inside the
// c'tor and / or d'tor.  Example:
//
//   struct Foo {
//     Foo() { ... }
//   } GTEST_ATTRIBUTE_UNUSED_;
//
// Also use it after a variable or parameter declaration to tell the
// compiler the variable/parameter does not have to be used.
#if defined(__GNUC__) && !defined(COMPILER_ICC)
# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
#else
# define GTEST_ATTRIBUTE_UNUSED_
#endif

// A macro to disallow operator=
// This should be used in the private: declarations for a class.
#define GTEST_DISALLOW_ASSIGN_(type)\
  void operator=(type const &)

// A macro to disallow copy constructor and operator=
// This should be used in the private: declarations for a class.
#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
  type(type const &);\
  GTEST_DISALLOW_ASSIGN_(type)

// Tell the compiler to warn about unused return values for functions declared
// with this macro.  The macro should be used on function declarations
// following the argument list:
//
//   Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
#else
# define GTEST_MUST_USE_RESULT_
#endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC

// Determine whether the compiler supports Microsoft's Structured Exception
// Handling.  This is supported by several Windows compilers but generally
// does not exist on any other system.
#ifndef GTEST_HAS_SEH
// The user didn't tell us, so we need to figure it out.

# if defined(_MSC_VER) || defined(__BORLANDC__)
// These two compilers are known to support SEH.
#  define GTEST_HAS_SEH 1
# else
// Assume no SEH.
#  define GTEST_HAS_SEH 0
# endif

#endif  // GTEST_HAS_SEH

#ifdef _MSC_VER

# if GTEST_LINKED_AS_SHARED_LIBRARY
#  define GTEST_API_ __declspec(dllimport)
# elif GTEST_CREATE_SHARED_LIBRARY
#  define GTEST_API_ __declspec(dllexport)
# endif

#endif  // _MSC_VER

#ifndef GTEST_API_
# define GTEST_API_
#endif

#ifdef __GNUC__
// Ask the compiler to never inline a given function.
# define GTEST_NO_INLINE_ __attribute__((noinline))
#else
# define GTEST_NO_INLINE_
#endif

// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
# define GTEST_HAS_CXXABI_H_ 1
#else
# define GTEST_HAS_CXXABI_H_ 0
#endif

namespace testing {

class Message;

namespace internal {

// A secret type that Google Test users don't know about.  It has no
// definition on purpose.  Therefore it's impossible to create a
// Secret object, which is what we want.
class Secret;

// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
//
//   GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
//                         content_type_names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
//   GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
//
// The second argument to the macro is the name of the variable. If
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.

template <bool>
struct CompileAssert {
};

#define GTEST_COMPILE_ASSERT_(expr, msg) \
  typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
      msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_

// Implementation details of GTEST_COMPILE_ASSERT_:
//
// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
//   elements (and thus is invalid) when the expression is false.
//
// - The simpler definition
//
//    #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
//
//   does not work, as gcc supports variable-length arrays whose sizes
//   are determined at run-time (this is gcc's extension and not part
//   of the C++ standard).  As a result, gcc fails to reject the
//   following code with the simple definition:
//
//     int foo;
//     GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
//                                      // not a compile-time constant.
//
// - By using the type CompileAssert<(bool(expr))>, we ensures that
//   expr is a compile-time constant.  (Template arguments must be
//   determined at compile-time.)
//
// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
//
//     CompileAssert<bool(expr)>
//
//   instead, these compilers will refuse to compile
//
//     GTEST_COMPILE_ASSERT_(5 > 0, some_message);
//
//   (They seem to think the ">" in "5 > 0" marks the end of the
//   template argument list.)
//
// - The array size is (bool(expr) ? 1 : -1), instead of simply
//
//     ((expr) ? 1 : -1).
//
//   This is to avoid running into a bug in MS VC 7.1, which
//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.

// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
//
// This template is declared, but intentionally undefined.
template <typename T1, typename T2>
struct StaticAssertTypeEqHelper;

template <typename T>
struct StaticAssertTypeEqHelper<T, T> {};

#if GTEST_HAS_GLOBAL_STRING
typedef ::string string;
#else
typedef ::std::string string;
#endif  // GTEST_HAS_GLOBAL_STRING

#if GTEST_HAS_GLOBAL_WSTRING
typedef ::wstring wstring;
#elif GTEST_HAS_STD_WSTRING
typedef ::std::wstring wstring;
#endif  // GTEST_HAS_GLOBAL_WSTRING

// A helper for suppressing warnings on constant condition.  It just
// returns 'condition'.
GTEST_API_ bool IsTrue(bool condition);

// Defines scoped_ptr.

// This implementation of scoped_ptr is PARTIAL - it only contains
// enough stuff to satisfy Google Test's need.
template <typename T>
class scoped_ptr {
 public:
  typedef T element_type;

  explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
  ~scoped_ptr() { reset(); }

  T& operator*() const { return *ptr_; }
  T* operator->() const { return ptr_; }
  T* get() const { return ptr_; }

  T* release() {
    T* const ptr = ptr_;
    ptr_ = NULL;
    return ptr;
  }

  void reset(T* p = NULL) {
    if (p != ptr_) {
      if (IsTrue(sizeof(T) > 0)) {  // Makes sure T is a complete type.
        delete ptr_;
      }
      ptr_ = p;
    }
  }

 private:
  T* ptr_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
};

// Defines RE.

// A simple C++ wrapper for <regex.h>.  It uses the POSIX Extended
// Regular Expression syntax.
class GTEST_API_ RE {
 public:
  // A copy constructor is required by the Standard to initialize object
  // references from r-values.
  RE(const RE& other) { Init(other.pattern()); }

  // Constructs an RE from a string.
  RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT

#if GTEST_HAS_GLOBAL_STRING

  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT

#endif  // GTEST_HAS_GLOBAL_STRING

  RE(const char* regex) { Init(regex); }  // NOLINT
  ~RE();

  // Returns the string representation of the regex.
  const char* pattern() const { return pattern_; }

  // FullMatch(str, re) returns true iff regular expression re matches
  // the entire str.
  // PartialMatch(str, re) returns true iff regular expression re
  // matches a substring of str (including str itself).
  //
  // TODO(wan@google.com): make FullMatch() and PartialMatch() work
  // when str contains NUL characters.
  static bool FullMatch(const ::std::string& str, const RE& re) {
    return FullMatch(str.c_str(), re);
  }
  static bool PartialMatch(const ::std::string& str, const RE& re) {
    return PartialMatch(str.c_str(), re);
  }

#if GTEST_HAS_GLOBAL_STRING

  static bool FullMatch(const ::string& str, const RE& re) {
    return FullMatch(str.c_str(), re);
  }
  static bool PartialMatch(const ::string& str, const RE& re) {
    return PartialMatch(str.c_str(), re);
  }

#endif  // GTEST_HAS_GLOBAL_STRING

  static bool FullMatch(const char* str, const RE& re);
  static bool PartialMatch(const char* str, const RE& re);

 private:
  void Init(const char* regex);

  // We use a const char* instead of an std::string, as Google Test used to be
  // used where std::string is not available.  TODO(wan@google.com): change to
  // std::string.
  const char* pattern_;
  bool is_valid_;

#if GTEST_USES_POSIX_RE

  regex_t full_regex_;     // For FullMatch().
  regex_t partial_regex_;  // For PartialMatch().

#else  // GTEST_USES_SIMPLE_RE

  const char* full_pattern_;  // For FullMatch();

#endif

  GTEST_DISALLOW_ASSIGN_(RE);
};

// Formats a source file path and a line number as they would appear
// in an error message from the compiler used to compile this code.
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);

// Formats a file location for compiler-independent XML output.
// Although this function is not platform dependent, we put it next to
// FormatFileLocation in order to contrast the two functions.
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
                                                               int line);

// Defines logging utilities:
//   GTEST_LOG_(severity) - logs messages at the specified severity level. The
//                          message itself is streamed into the macro.
//   LogToStderr()  - directs all log messages to stderr.
//   FlushInfoLog() - flushes informational log messages.

enum GTestLogSeverity {
  GTEST_INFO,
  GTEST_WARNING,
  GTEST_ERROR,
  GTEST_FATAL
};

// Formats log entry severity, provides a stream object for streaming the
// log message, and terminates the message with a newline when going out of
// scope.
class GTEST_API_ GTestLog {
 public:
  GTestLog(GTestLogSeverity severity, const char* file, int line);

  // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
  ~GTestLog();

  ::std::ostream& GetStream() { return ::std::cerr; }

 private:
  const GTestLogSeverity severity_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
};

#define GTEST_LOG_(severity) \
    ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
                                  __FILE__, __LINE__).GetStream()

inline void LogToStderr() {}
inline void FlushInfoLog() { fflush(NULL); }

// INTERNAL IMPLEMENTATION - DO NOT USE.
//
// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
// is not satisfied.
//  Synopsys:
//    GTEST_CHECK_(boolean_condition);
//     or
//    GTEST_CHECK_(boolean_condition) << "Additional message";
//
//    This checks the condition and if the condition is not satisfied
//    it prints message about the condition violation, including the
//    condition itself, plus additional message streamed into it, if any,
//    and then it aborts the program. It aborts the program irrespective of
//    whether it is built in the debug mode or not.
#define GTEST_CHECK_(condition) \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
    if (::testing::internal::IsTrue(condition)) \
      ; \
    else \
      GTEST_LOG_(FATAL) << "Condition " #condition " failed. "

// An all-mode assert to verify that the given POSIX-style function
// call returns 0 (indicating success).  Known limitation: this
// doesn't expand to a balanced 'if' statement, so enclose the macro
// in {} if you need to use it as the only statement in an 'if'
// branch.
#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
  if (const int gtest_error = (posix_call)) \
    GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
                      << gtest_error

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Use ImplicitCast_ as a safe version of static_cast for upcasting in
// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
// const Foo*).  When you use ImplicitCast_, the compiler checks that
// the cast is safe.  Such explicit ImplicitCast_s are necessary in
// surprisingly many situations where C++ demands an exact type match
// instead of an argument type convertable to a target type.
//
// The syntax for using ImplicitCast_ is the same as for static_cast:
//
//   ImplicitCast_<ToType>(expr)
//
// ImplicitCast_ would have been part of the C++ standard library,
// but the proposal was submitted too late.  It will probably make
// its way into the language in the future.
//
// This relatively ugly name is intentional. It prevents clashes with
// similar functions users may have (e.g., implicit_cast). The internal
// namespace alone is not enough because the function can be found by ADL.
template<typename To>
inline To ImplicitCast_(To x) { return x; }

// When you upcast (that is, cast a pointer from type Foo to type
// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
// always succeed.  When you downcast (that is, cast a pointer from
// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
// how do you know the pointer is really of type SubclassOfFoo?  It
// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
// when you downcast, you should use this macro.  In debug mode, we
// use dynamic_cast<> to double-check the downcast is legal (we die
// if it's not).  In normal mode, we do the efficient static_cast<>
// instead.  Thus, it's important to test in debug mode to make sure
// the cast is legal!
//    This is the only place in the code we should use dynamic_cast<>.
// In particular, you SHOULDN'T be using dynamic_cast<> in order to
// do RTTI (eg code like this:
//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
// You should design the code some other way not to need this.
//
// This relatively ugly name is intentional. It prevents clashes with
// similar functions users may have (e.g., down_cast). The internal
// namespace alone is not enough because the function can be found by ADL.
template<typename To, typename From>  // use like this: DownCast_<T*>(foo);
inline To DownCast_(From* f) {  // so we only accept pointers
  // Ensures that To is a sub-type of From *.  This test is here only
  // for compile-time type checking, and has no overhead in an
  // optimized build at run-time, as it will be optimized away
  // completely.
  if (false) {
    const To to = NULL;
    ::testing::internal::ImplicitCast_<From*>(to);
  }

#if GTEST_HAS_RTTI
  // RTTI: debug mode only!
  GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
#endif
  return static_cast<To>(f);
}

// Downcasts the pointer of type Base to Derived.
// Derived must be a subclass of Base. The parameter MUST
// point to a class of type Derived, not any subclass of it.
// When RTTI is available, the function performs a runtime
// check to enforce this.
template <class Derived, class Base>
Derived* CheckedDowncastToActualType(Base* base) {
#if GTEST_HAS_RTTI
  GTEST_CHECK_(typeid(*base) == typeid(Derived));
  return dynamic_cast<Derived*>(base);  // NOLINT
#else
  return static_cast<Derived*>(base);  // Poor man's downcast.
#endif
}

#if GTEST_HAS_STREAM_REDIRECTION

// Defines the stderr capturer:
//   CaptureStdout     - starts capturing stdout.
//   GetCapturedStdout - stops capturing stdout and returns the captured string.
//   CaptureStderr     - starts capturing stderr.
//   GetCapturedStderr - stops capturing stderr and returns the captured string.
//
GTEST_API_ void CaptureStdout();
GTEST_API_ std::string GetCapturedStdout();
GTEST_API_ void CaptureStderr();
GTEST_API_ std::string GetCapturedStderr();

#endif  // GTEST_HAS_STREAM_REDIRECTION


#if GTEST_HAS_DEATH_TEST

const ::std::vector<testing::internal::string>& GetInjectableArgvs();
void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
                             new_argvs);

// A copy of all command line arguments.  Set by InitGoogleTest().
extern ::std::vector<testing::internal::string> g_argvs;

#endif  // GTEST_HAS_DEATH_TEST

// Defines synchronization primitives.

#if GTEST_HAS_PTHREAD

// Sleeps for (roughly) n milli-seconds.  This function is only for
// testing Google Test's own constructs.  Don't use it in user tests,
// either directly or indirectly.
inline void SleepMilliseconds(int n) {
  const timespec time = {
    0,                  // 0 seconds.
    n * 1000L * 1000L,  // And n ms.
  };
  nanosleep(&time, NULL);
}

// Allows a controller thread to pause execution of newly created
// threads until notified.  Instances of this class must be created
// and destroyed in the controller thread.
//
// This class is only for testing Google Test's own constructs. Do not
// use it in user tests, either directly or indirectly.
class Notification {
 public:
  Notification() : notified_(false) {
    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
  }
  ~Notification() {
    pthread_mutex_destroy(&mutex_);
  }

  // Notifies all threads created with this notification to start. Must
  // be called from the controller thread.
  void Notify() {
    pthread_mutex_lock(&mutex_);
    notified_ = true;
    pthread_mutex_unlock(&mutex_);
  }

  // Blocks until the controller thread notifies. Must be called from a test
  // thread.
  void WaitForNotification() {
    for (;;) {
      pthread_mutex_lock(&mutex_);
      const bool notified = notified_;
      pthread_mutex_unlock(&mutex_);
      if (notified)
        break;
      SleepMilliseconds(10);
    }
  }

 private:
  pthread_mutex_t mutex_;
  bool notified_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
};

// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
// Consequently, it cannot select a correct instantiation of ThreadWithParam
// in order to call its Run(). Introducing ThreadWithParamBase as a
// non-templated base class for ThreadWithParam allows us to bypass this
// problem.
class ThreadWithParamBase {
 public:
  virtual ~ThreadWithParamBase() {}
  virtual void Run() = 0;
};

// pthread_create() accepts a pointer to a function type with the C linkage.
// According to the Standard (7.5/1), function types with different linkages
// are different even if they are otherwise identical.  Some compilers (for
// example, SunStudio) treat them as different types.  Since class methods
// cannot be defined with C-linkage we need to define a free C-function to
// pass into pthread_create().
extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
  static_cast<ThreadWithParamBase*>(thread)->Run();
  return NULL;
}

// Helper class for testing Google Test's multi-threading constructs.
// To use it, write:
//
//   void ThreadFunc(int param) { /* Do things with param */ }
//   Notification thread_can_start;
//   ...
//   // The thread_can_start parameter is optional; you can supply NULL.
//   ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
//   thread_can_start.Notify();
//
// These classes are only for testing Google Test's own constructs. Do
// not use them in user tests, either directly or indirectly.
template <typename T>
class ThreadWithParam : public ThreadWithParamBase {
 public:
  typedef void (*UserThreadFunc)(T);

  ThreadWithParam(
      UserThreadFunc func, T param, Notification* thread_can_start)
      : func_(func),
        param_(param),
        thread_can_start_(thread_can_start),
        finished_(false) {
    ThreadWithParamBase* const base = this;
    // The thread can be created only after all fields except thread_
    // have been initialized.
    GTEST_CHECK_POSIX_SUCCESS_(
        pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
  }
  ~ThreadWithParam() { Join(); }

  void Join() {
    if (!finished_) {
      GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
      finished_ = true;
    }
  }

  virtual void Run() {
    if (thread_can_start_ != NULL)
      thread_can_start_->WaitForNotification();
    func_(param_);
  }

 private:
  const UserThreadFunc func_;  // User-supplied thread function.
  const T param_;  // User-supplied parameter to the thread function.
  // When non-NULL, used to block execution until the controller thread
  // notifies.
  Notification* const thread_can_start_;
  bool finished_;  // true iff we know that the thread function has finished.
  pthread_t thread_;  // The native thread object.

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
};

// MutexBase and Mutex implement mutex on pthreads-based platforms. They
// are used in conjunction with class MutexLock:
//
//   Mutex mutex;
//   ...
//   MutexLock lock(&mutex);  // Acquires the mutex and releases it at the end
//                            // of the current scope.
//
// MutexBase implements behavior for both statically and dynamically
// allocated mutexes.  Do not use MutexBase directly.  Instead, write
// the following to define a static mutex:
//
//   GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
//
// You can forward declare a static mutex like this:
//
//   GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
//
// To create a dynamic mutex, just define an object of type Mutex.
class MutexBase {
 public:
  // Acquires this mutex.
  void Lock() {
    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
    owner_ = pthread_self();
    has_owner_ = true;
  }

  // Releases this mutex.
  void Unlock() {
    // Since the lock is being released the owner_ field should no longer be
    // considered valid. We don't protect writing to has_owner_ here, as it's
    // the caller's responsibility to ensure that the current thread holds the
    // mutex when this is called.
    has_owner_ = false;
    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
  }

  // Does nothing if the current thread holds the mutex. Otherwise, crashes
  // with high probability.
  void AssertHeld() const {
    GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
        << "The current thread is not holding the mutex @" << this;
  }

  // A static mutex may be used before main() is entered.  It may even
  // be used before the dynamic initialization stage.  Therefore we
  // must be able to initialize a static mutex object at link time.
  // This means MutexBase has to be a POD and its member variables
  // have to be public.
 public:
  pthread_mutex_t mutex_;  // The underlying pthread mutex.
  // has_owner_ indicates whether the owner_ field below contains a valid thread
  // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
  // accesses to the owner_ field should be protected by a check of this field.
  // An alternative might be to memset() owner_ to all zeros, but there's no
  // guarantee that a zero'd pthread_t is necessarily invalid or even different
  // from pthread_self().
  bool has_owner_;
  pthread_t owner_;  // The thread holding the mutex.
};

// Forward-declares a static mutex.
# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
    extern ::testing::internal::MutexBase mutex

// Defines and statically (i.e. at link time) initializes a static mutex.
// The initialization list here does not explicitly initialize each field,
// instead relying on default initialization for the unspecified fields. In
// particular, the owner_ field (a pthread_t) is not explicitly initialized.
// This allows initialization to work whether pthread_t is a scalar or struct.
// The flag -Wmissing-field-initializers must not be specified for this to work.
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
    ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }

// The Mutex class can only be used for mutexes created at runtime. It
// shares its API with MutexBase otherwise.
class Mutex : public MutexBase {
 public:
  Mutex() {
    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
    has_owner_ = false;
  }
  ~Mutex() {
    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
  }

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
};

// We cannot name this class MutexLock as the ctor declaration would
// conflict with a macro named MutexLock, which is defined on some
// platforms.  Hence the typedef trick below.
class GTestMutexLock {
 public:
  explicit GTestMutexLock(MutexBase* mutex)
      : mutex_(mutex) { mutex_->Lock(); }

  ~GTestMutexLock() { mutex_->Unlock(); }

 private:
  MutexBase* const mutex_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
};

typedef GTestMutexLock MutexLock;

// Helpers for ThreadLocal.

// pthread_key_create() requires DeleteThreadLocalValue() to have
// C-linkage.  Therefore it cannot be templatized to access
// ThreadLocal<T>.  Hence the need for class
// ThreadLocalValueHolderBase.
class ThreadLocalValueHolderBase {
 public:
  virtual ~ThreadLocalValueHolderBase() {}
};

// Called by pthread to delete thread-local data stored by
// pthread_setspecific().
extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
  delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
}

// Implements thread-local storage on pthreads-based systems.
//
//   // Thread 1
//   ThreadLocal<int> tl(100);  // 100 is the default value for each thread.
//
//   // Thread 2
//   tl.set(150);  // Changes the value for thread 2 only.
//   EXPECT_EQ(150, tl.get());
//
//   // Thread 1
//   EXPECT_EQ(100, tl.get());  // In thread 1, tl has the original value.
//   tl.set(200);
//   EXPECT_EQ(200, tl.get());
//
// The template type argument T must have a public copy constructor.
// In addition, the default ThreadLocal constructor requires T to have
// a public default constructor.
//
// An object managed for a thread by a ThreadLocal instance is deleted
// when the thread exits.  Or, if the ThreadLocal instance dies in
// that thread, when the ThreadLocal dies.  It's the user's
// responsibility to ensure that all other threads using a ThreadLocal
// have exited when it dies, or the per-thread objects for those
// threads will not be deleted.
//
// Google Test only uses global ThreadLocal objects.  That means they
// will die after main() has returned.  Therefore, no per-thread
// object managed by Google Test will be leaked as long as all threads
// using Google Test have exited when main() returns.
template <typename T>
class ThreadLocal {
 public:
  ThreadLocal() : key_(CreateKey()),
                  default_() {}
  explicit ThreadLocal(const T& value) : key_(CreateKey()),
                                         default_(value) {}

  ~ThreadLocal() {
    // Destroys the managed object for the current thread, if any.
    DeleteThreadLocalValue(pthread_getspecific(key_));

    // Releases resources associated with the key.  This will *not*
    // delete managed objects for other threads.
    GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
  }

  T* pointer() { return GetOrCreateValue(); }
  const T* pointer() const { return GetOrCreateValue(); }
  const T& get() const { return *pointer(); }
  void set(const T& value) { *pointer() = value; }

 private:
  // Holds a value of type T.
  class ValueHolder : public ThreadLocalValueHolderBase {
   public:
    explicit ValueHolder(const T& value) : value_(value) {}

    T* pointer() { return &value_; }

   private:
    T value_;
    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
  };

  static pthread_key_t CreateKey() {
    pthread_key_t key;
    // When a thread exits, DeleteThreadLocalValue() will be called on
    // the object managed for that thread.
    GTEST_CHECK_POSIX_SUCCESS_(
        pthread_key_create(&key, &DeleteThreadLocalValue));
    return key;
  }

  T* GetOrCreateValue() const {
    ThreadLocalValueHolderBase* const holder =
        static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
    if (holder != NULL) {
      return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
    }

    ValueHolder* const new_holder = new ValueHolder(default_);
    ThreadLocalValueHolderBase* const holder_base = new_holder;
    GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
    return new_holder->pointer();
  }

  // A key pthreads uses for looking up per-thread values.
  const pthread_key_t key_;
  const T default_;  // The default value for each thread.

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
};

# define GTEST_IS_THREADSAFE 1

#else  // GTEST_HAS_PTHREAD

// A dummy implementation of synchronization primitives (mutex, lock,
// and thread-local variable).  Necessary for compiling Google Test where
// mutex is not supported - using Google Test in multiple threads is not
// supported on such platforms.

class Mutex {
 public:
  Mutex() {}
  void Lock() {}
  void Unlock() {}
  void AssertHeld() const {}
};

# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
  extern ::testing::internal::Mutex mutex

# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex

class GTestMutexLock {
 public:
  explicit GTestMutexLock(Mutex*) {}  // NOLINT
};

typedef GTestMutexLock MutexLock;

template <typename T>
class ThreadLocal {
 public:
  ThreadLocal() : value_() {}
  explicit ThreadLocal(const T& value) : value_(value) {}
  T* pointer() { return &value_; }
  const T* pointer() const { return &value_; }
  const T& get() const { return value_; }
  void set(const T& value) { value_ = value; }
 private:
  T value_;
};

// The above synchronization primitives have dummy implementations.
// Therefore Google Test is not thread-safe.
# define GTEST_IS_THREADSAFE 0

#endif  // GTEST_HAS_PTHREAD

// Returns the number of threads running in the process, or 0 to indicate that
// we cannot detect it.
GTEST_API_ size_t GetThreadCount();

// Passing non-POD classes through ellipsis (...) crashes the ARM
// compiler and generates a warning in Sun Studio.  The Nokia Symbian
// and the IBM XL C/C++ compiler try to instantiate a copy constructor
// for objects passed through ellipsis (...), failing for uncopyable
// objects.  We define this to ensure that only POD is passed through
// ellipsis on these systems.
#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
// We lose support for NULL detection where the compiler doesn't like
// passing non-POD classes through ellipsis (...).
# define GTEST_ELLIPSIS_NEEDS_POD_ 1
#else
# define GTEST_CAN_COMPARE_NULL 1
#endif

// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
// const T& and const T* in a function template.  These compilers
// _can_ decide between class template specializations for T and T*,
// so a tr1::type_traits-like is_pointer works.
#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
# define GTEST_NEEDS_IS_POINTER_ 1
#endif

template <bool bool_value>
struct bool_constant {
  typedef bool_constant<bool_value> type;
  static const bool value = bool_value;
};
template <bool bool_value> const bool bool_constant<bool_value>::value;

typedef bool_constant<false> false_type;
typedef bool_constant<true> true_type;

template <typename T>
struct is_pointer : public false_type {};

template <typename T>
struct is_pointer<T*> : public true_type {};

template <typename Iterator>
struct IteratorTraits {
  typedef typename Iterator::value_type value_type;
};

template <typename T>
struct IteratorTraits<T*> {
  typedef T value_type;
};

template <typename T>
struct IteratorTraits<const T*> {
  typedef T value_type;
};

#if GTEST_OS_WINDOWS
# define GTEST_PATH_SEP_ "\\"
# define GTEST_HAS_ALT_PATH_SEP_ 1
// The biggest signed integer type the compiler supports.
typedef __int64 BiggestInt;
#else
# define GTEST_PATH_SEP_ "/"
# define GTEST_HAS_ALT_PATH_SEP_ 0
typedef long long BiggestInt;  // NOLINT
#endif  // GTEST_OS_WINDOWS

// Utilities for char.

// isspace(int ch) and friends accept an unsigned char or EOF.  char
// may be signed, depending on the compiler (or compiler flags).
// Therefore we need to cast a char to unsigned char before calling
// isspace(), etc.

inline bool IsAlpha(char ch) {
  return isalpha(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsAlNum(char ch) {
  return isalnum(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsDigit(char ch) {
  return isdigit(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsLower(char ch) {
  return islower(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsSpace(char ch) {
  return isspace(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsUpper(char ch) {
  return isupper(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsXDigit(char ch) {
  return isxdigit(static_cast<unsigned char>(ch)) != 0;
}
inline bool IsXDigit(wchar_t ch) {
  const unsigned char low_byte = static_cast<unsigned char>(ch);
  return ch == low_byte && isxdigit(low_byte) != 0;
}

inline char ToLower(char ch) {
  return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
}
inline char ToUpper(char ch) {
  return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
}

// The testing::internal::posix namespace holds wrappers for common
// POSIX functions.  These wrappers hide the differences between
// Windows/MSVC and POSIX systems.  Since some compilers define these
// standard functions as macros, the wrapper cannot have the same name
// as the wrapped function.

namespace posix {

// Functions with a different name on Windows.

#if GTEST_OS_WINDOWS

typedef struct _stat StatStruct;

# ifdef __BORLANDC__
inline int IsATTY(int fd) { return isatty(fd); }
inline int StrCaseCmp(const char* s1, const char* s2) {
  return stricmp(s1, s2);
}
inline char* StrDup(const char* src) { return strdup(src); }
# else  // !__BORLANDC__
#  if GTEST_OS_WINDOWS_MOBILE
inline int IsATTY(int /* fd */) { return 0; }
#  else
inline int IsATTY(int fd) { return _isatty(fd); }
#  endif  // GTEST_OS_WINDOWS_MOBILE
inline int StrCaseCmp(const char* s1, const char* s2) {
  return _stricmp(s1, s2);
}
inline char* StrDup(const char* src) { return _strdup(src); }
# endif  // __BORLANDC__

# if GTEST_OS_WINDOWS_MOBILE
inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
// time and thus not defined there.
# else
inline int FileNo(FILE* file) { return _fileno(file); }
inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
inline int RmDir(const char* dir) { return _rmdir(dir); }
inline bool IsDir(const StatStruct& st) {
  return (_S_IFDIR & st.st_mode) != 0;
}
# endif  // GTEST_OS_WINDOWS_MOBILE

#else

typedef struct stat StatStruct;

inline int FileNo(FILE* file) { return fileno(file); }
inline int IsATTY(int fd) { return isatty(fd); }
inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
inline int StrCaseCmp(const char* s1, const char* s2) {
  return strcasecmp(s1, s2);
}
inline char* StrDup(const char* src) { return strdup(src); }
inline int RmDir(const char* dir) { return rmdir(dir); }
inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

#endif  // GTEST_OS_WINDOWS

// Functions deprecated by MSVC 8.0.

#ifdef _MSC_VER
// Temporarily disable warning 4996 (deprecated function).
# pragma warning(push)
# pragma warning(disable:4996)
#endif

inline const char* StrNCpy(char* dest, const char* src, size_t n) {
  return strncpy(dest, src, n);
}

// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
// StrError() aren't needed on Windows CE at this time and thus not
// defined there.

#if !GTEST_OS_WINDOWS_MOBILE
inline int ChDir(const char* dir) { return chdir(dir); }
#endif
inline FILE* FOpen(const char* path, const char* mode) {
  return fopen(path, mode);
}
#if !GTEST_OS_WINDOWS_MOBILE
inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
  return freopen(path, mode, stream);
}
inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
#endif
inline int FClose(FILE* fp) { return fclose(fp); }
#if !GTEST_OS_WINDOWS_MOBILE
inline int Read(int fd, void* buf, unsigned int count) {
  return static_cast<int>(read(fd, buf, count));
}
inline int Write(int fd, const void* buf, unsigned int count) {
  return static_cast<int>(write(fd, buf, count));
}
inline int Close(int fd) { return close(fd); }
inline const char* StrError(int errnum) { return strerror(errnum); }
#endif
inline const char* GetEnv(const char* name) {
#if GTEST_OS_WINDOWS_MOBILE
  // We are on Windows CE, which has no environment variables.
  return NULL;
#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
  // Environment variables which we programmatically clear will be set to the
  // empty string rather than unset (NULL).  Handle that case.
  const char* const env = getenv(name);
  return (env != NULL && env[0] != '\0') ? env : NULL;
#else
  return getenv(name);
#endif
}

#ifdef _MSC_VER
# pragma warning(pop)  // Restores the warning state.
#endif

#if GTEST_OS_WINDOWS_MOBILE
// Windows CE has no C library. The abort() function is used in
// several places in Google Test. This implementation provides a reasonable
// imitation of standard behaviour.
void Abort();
#else
inline void Abort() { abort(); }
#endif  // GTEST_OS_WINDOWS_MOBILE

}  // namespace posix

// MSVC "deprecates" snprintf and issues warnings wherever it is used.  In
// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
// MSVC-based platforms.  We map the GTEST_SNPRINTF_ macro to the appropriate
// function in order to achieve that.  We use macro definition here because
// snprintf is a variadic function.
#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
// MSVC 2005 and above support variadic macros.
# define GTEST_SNPRINTF_(buffer, size, format, ...) \
     _snprintf_s(buffer, size, size, format, __VA_ARGS__)
#elif defined(_MSC_VER)
// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
// complain about _snprintf.
# define GTEST_SNPRINTF_ _snprintf
#else
# define GTEST_SNPRINTF_ snprintf
#endif

// The maximum number a BiggestInt can represent.  This definition
// works no matter BiggestInt is represented in one's complement or
// two's complement.
//
// We cannot rely on numeric_limits in STL, as __int64 and long long
// are not part of standard C++ and numeric_limits doesn't need to be
// defined for them.
const BiggestInt kMaxBiggestInt =
    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));

// This template class serves as a compile-time function from size to
// type.  It maps a size in bytes to a primitive type with that
// size. e.g.
//
//   TypeWithSize<4>::UInt
//
// is typedef-ed to be unsigned int (unsigned integer made up of 4
// bytes).
//
// Such functionality should belong to STL, but I cannot find it
// there.
//
// Google Test uses this class in the implementation of floating-point
// comparison.
//
// For now it only handles UInt (unsigned int) as that's all Google Test
// needs.  Other types can be easily added in the future if need
// arises.
template <size_t size>
class TypeWithSize {
 public:
  // This prevents the user from using TypeWithSize<N> with incorrect
  // values of N.
  typedef void UInt;
};

// The specialization for size 4.
template <>
class TypeWithSize<4> {
 public:
  // unsigned int has size 4 in both gcc and MSVC.
  //
  // As base/basictypes.h doesn't compile on Windows, we cannot use
  // uint32, uint64, and etc here.
  typedef int Int;
  typedef unsigned int UInt;
};

// The specialization for size 8.
template <>
class TypeWithSize<8> {
 public:
#if GTEST_OS_WINDOWS
  typedef __int64 Int;
  typedef unsigned __int64 UInt;
#else
  typedef long long Int;  // NOLINT
  typedef unsigned long long UInt;  // NOLINT
#endif  // GTEST_OS_WINDOWS
};

// Integer types of known sizes.
typedef TypeWithSize<4>::Int Int32;
typedef TypeWithSize<4>::UInt UInt32;
typedef TypeWithSize<8>::Int Int64;
typedef TypeWithSize<8>::UInt UInt64;
typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.

// Utilities for command line flags and environment variables.

// Macro for referencing flags.
#define GTEST_FLAG(name) FLAGS_gtest_##name

// Macros for declaring flags.
#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
#define GTEST_DECLARE_int32_(name) \
    GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
#define GTEST_DECLARE_string_(name) \
    GTEST_API_ extern ::std::string GTEST_FLAG(name)

// Macros for defining flags.
#define GTEST_DEFINE_bool_(name, default_val, doc) \
    GTEST_API_ bool GTEST_FLAG(name) = (default_val)
#define GTEST_DEFINE_int32_(name, default_val, doc) \
    GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
#define GTEST_DEFINE_string_(name, default_val, doc) \
    GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)

// Thread annotations
#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
#define GTEST_LOCK_EXCLUDED_(locks)

// Parses 'str' for a 32-bit signed integer.  If successful, writes the result
// to *value and returns true; otherwise leaves *value unchanged and returns
// false.
// TODO(chandlerc): Find a better way to refactor flag and environment parsing
// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
// function.
bool ParseInt32(const Message& src_text, const char* str, Int32* value);

// Parses a bool/Int32/string from the environment variable
// corresponding to the given Google Test flag.
bool BoolFromGTestEnv(const char* flag, bool default_val);
GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
const char* StringFromGTestEnv(const char* flag, const char* default_val);

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

#if GTEST_OS_LINUX
# include <stdlib.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
#endif  // GTEST_OS_LINUX

#if GTEST_HAS_EXCEPTIONS
# include <stdexcept>
#endif

#include <ctype.h>
#include <float.h>
#include <string.h>
#include <iomanip>
#include <limits>
#include <set>

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file defines the Message class.
//
// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
// leave some internal implementation details in this header file.
// They are clearly marked by comments like this:
//
//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
//
// Such code is NOT meant to be used by a user directly, and is subject
// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
// program!

#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_

#include <limits>


// Ensures that there is at least one operator<< in the global namespace.
// See Message& operator<<(...) below for why.
void operator<<(const testing::internal::Secret&, int);

namespace testing {

// The Message class works like an ostream repeater.
//
// Typical usage:
//
//   1. You stream a bunch of values to a Message object.
//      It will remember the text in a stringstream.
//   2. Then you stream the Message object to an ostream.
//      This causes the text in the Message to be streamed
//      to the ostream.
//
// For example;
//
//   testing::Message foo;
//   foo << 1 << " != " << 2;
//   std::cout << foo;
//
// will print "1 != 2".
//
// Message is not intended to be inherited from.  In particular, its
// destructor is not virtual.
//
// Note that stringstream behaves differently in gcc and in MSVC.  You
// can stream a NULL char pointer to it in the former, but not in the
// latter (it causes an access violation if you do).  The Message
// class hides this difference by treating a NULL char pointer as
// "(null)".
class GTEST_API_ Message {
 private:
  // The type of basic IO manipulators (endl, ends, and flush) for
  // narrow streams.
  typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);

 public:
  // Constructs an empty Message.
  Message();

  // Copy constructor.
  Message(const Message& msg) : ss_(new ::std::stringstream) {  // NOLINT
    *ss_ << msg.GetString();
  }

  // Constructs a Message from a C-string.
  explicit Message(const char* str) : ss_(new ::std::stringstream) {
    *ss_ << str;
  }

#if GTEST_OS_SYMBIAN
  // Streams a value (either a pointer or not) to this object.
  template <typename T>
  inline Message& operator <<(const T& value) {
    StreamHelper(typename internal::is_pointer<T>::type(), value);
    return *this;
  }
#else
  // Streams a non-pointer value to this object.
  template <typename T>
  inline Message& operator <<(const T& val) {
    // Some libraries overload << for STL containers.  These
    // overloads are defined in the global namespace instead of ::std.
    //
    // C++'s symbol lookup rule (i.e. Koenig lookup) says that these
    // overloads are visible in either the std namespace or the global
    // namespace, but not other namespaces, including the testing
    // namespace which Google Test's Message class is in.
    //
    // To allow STL containers (and other types that has a << operator
    // defined in the global namespace) to be used in Google Test
    // assertions, testing::Message must access the custom << operator
    // from the global namespace.  With this using declaration,
    // overloads of << defined in the global namespace and those
    // visible via Koenig lookup are both exposed in this function.
    using ::operator <<;
    *ss_ << val;
    return *this;
  }

  // Streams a pointer value to this object.
  //
  // This function is an overload of the previous one.  When you
  // stream a pointer to a Message, this definition will be used as it
  // is more specialized.  (The C++ Standard, section
  // [temp.func.order].)  If you stream a non-pointer, then the
  // previous definition will be used.
  //
  // The reason for this overload is that streaming a NULL pointer to
  // ostream is undefined behavior.  Depending on the compiler, you
  // may get "0", "(nil)", "(null)", or an access violation.  To
  // ensure consistent result across compilers, we always treat NULL
  // as "(null)".
  template <typename T>
  inline Message& operator <<(T* const& pointer) {  // NOLINT
    if (pointer == NULL) {
      *ss_ << "(null)";
    } else {
      *ss_ << pointer;
    }
    return *this;
  }
#endif  // GTEST_OS_SYMBIAN

  // Since the basic IO manipulators are overloaded for both narrow
  // and wide streams, we have to provide this specialized definition
  // of operator <<, even though its body is the same as the
  // templatized version above.  Without this definition, streaming
  // endl or other basic IO manipulators to Message will confuse the
  // compiler.
  Message& operator <<(BasicNarrowIoManip val) {
    *ss_ << val;
    return *this;
  }

  // Instead of 1/0, we want to see true/false for bool values.
  Message& operator <<(bool b) {
    return *this << (b ? "true" : "false");
  }

  // These two overloads allow streaming a wide C string to a Message
  // using the UTF-8 encoding.
  Message& operator <<(const wchar_t* wide_c_str);
  Message& operator <<(wchar_t* wide_c_str);

#if GTEST_HAS_STD_WSTRING
  // Converts the given wide string to a narrow string using the UTF-8
  // encoding, and streams the result to this Message object.
  Message& operator <<(const ::std::wstring& wstr);
#endif  // GTEST_HAS_STD_WSTRING

#if GTEST_HAS_GLOBAL_WSTRING
  // Converts the given wide string to a narrow string using the UTF-8
  // encoding, and streams the result to this Message object.
  Message& operator <<(const ::wstring& wstr);
#endif  // GTEST_HAS_GLOBAL_WSTRING

  // Gets the text streamed to this object so far as an std::string.
  // Each '\0' character in the buffer is replaced with "\\0".
  //
  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
  std::string GetString() const;

 private:

#if GTEST_OS_SYMBIAN
  // These are needed as the Nokia Symbian Compiler cannot decide between
  // const T& and const T* in a function template. The Nokia compiler _can_
  // decide between class template specializations for T and T*, so a
  // tr1::type_traits-like is_pointer works, and we can overload on that.
  template <typename T>
  inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
    if (pointer == NULL) {
      *ss_ << "(null)";
    } else {
      *ss_ << pointer;
    }
  }
  template <typename T>
  inline void StreamHelper(internal::false_type /*is_pointer*/,
                           const T& value) {
    // See the comments in Message& operator <<(const T&) above for why
    // we need this using statement.
    using ::operator <<;
    *ss_ << value;
  }
#endif  // GTEST_OS_SYMBIAN

  // We'll hold the text streamed to this object here.
  const internal::scoped_ptr< ::std::stringstream> ss_;

  // We declare (but don't implement) this to prevent the compiler
  // from implementing the assignment operator.
  void operator=(const Message&);
};

// Streams a Message to an ostream.
inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
  return os << sb.GetString();
}

namespace internal {

// Converts a streamable value to an std::string.  A NULL pointer is
// converted to "(null)".  When the input value is a ::string,
// ::std::string, ::wstring, or ::std::wstring object, each NUL
// character in it is replaced with "\\0".
template <typename T>
std::string StreamableToString(const T& streamable) {
  return (Message() << streamable).GetString();
}

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file declares the String class and functions used internally by
// Google Test.  They are subject to change without notice. They should not used
// by code external to Google Test.
//
// This header file is #included by <gtest/internal/gtest-internal.h>.
// It should not be #included by other files.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_

#ifdef __BORLANDC__
// string.h is not guaranteed to provide strcpy on C++ Builder.
# include <mem.h>
#endif

#include <string.h>
#include <string>


namespace testing {
namespace internal {

// String - an abstract class holding static string utilities.
class GTEST_API_ String {
 public:
  // Static utility methods

  // Clones a 0-terminated C string, allocating memory using new.  The
  // caller is responsible for deleting the return value using
  // delete[].  Returns the cloned string, or NULL if the input is
  // NULL.
  //
  // This is different from strdup() in string.h, which allocates
  // memory using malloc().
  static const char* CloneCString(const char* c_str);

#if GTEST_OS_WINDOWS_MOBILE
  // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
  // able to pass strings to Win32 APIs on CE we need to convert them
  // to 'Unicode', UTF-16.

  // Creates a UTF-16 wide string from the given ANSI string, allocating
  // memory using new. The caller is responsible for deleting the return
  // value using delete[]. Returns the wide string, or NULL if the
  // input is NULL.
  //
  // The wide string is created using the ANSI codepage (CP_ACP) to
  // match the behaviour of the ANSI versions of Win32 calls and the
  // C runtime.
  static LPCWSTR AnsiToUtf16(const char* c_str);

  // Creates an ANSI string from the given wide string, allocating
  // memory using new. The caller is responsible for deleting the return
  // value using delete[]. Returns the ANSI string, or NULL if the
  // input is NULL.
  //
  // The returned string is created using the ANSI codepage (CP_ACP) to
  // match the behaviour of the ANSI versions of Win32 calls and the
  // C runtime.
  static const char* Utf16ToAnsi(LPCWSTR utf16_str);
#endif

  // Compares two C strings.  Returns true iff they have the same content.
  //
  // Unlike strcmp(), this function can handle NULL argument(s).  A
  // NULL C string is considered different to any non-NULL C string,
  // including the empty string.
  static bool CStringEquals(const char* lhs, const char* rhs);

  // Converts a wide C string to a String using the UTF-8 encoding.
  // NULL will be converted to "(null)".  If an error occurred during
  // the conversion, "(failed to convert from wide string)" is
  // returned.
  static std::string ShowWideCString(const wchar_t* wide_c_str);

  // Compares two wide C strings.  Returns true iff they have the same
  // content.
  //
  // Unlike wcscmp(), this function can handle NULL argument(s).  A
  // NULL C string is considered different to any non-NULL C string,
  // including the empty string.
  static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);

  // Compares two C strings, ignoring case.  Returns true iff they
  // have the same content.
  //
  // Unlike strcasecmp(), this function can handle NULL argument(s).
  // A NULL C string is considered different to any non-NULL C string,
  // including the empty string.
  static bool CaseInsensitiveCStringEquals(const char* lhs,
                                           const char* rhs);

  // Compares two wide C strings, ignoring case.  Returns true iff they
  // have the same content.
  //
  // Unlike wcscasecmp(), this function can handle NULL argument(s).
  // A NULL C string is considered different to any non-NULL wide C string,
  // including the empty string.
  // NB: The implementations on different platforms slightly differ.
  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
  // environment variable. On GNU platform this method uses wcscasecmp
  // which compares according to LC_CTYPE category of the current locale.
  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
  // current locale.
  static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
                                               const wchar_t* rhs);

  // Returns true iff the given string ends with the given suffix, ignoring
  // case. Any string is considered to end with an empty suffix.
  static bool EndsWithCaseInsensitive(
      const std::string& str, const std::string& suffix);

  // Formats an int value as "%02d".
  static std::string FormatIntWidth2(int value);  // "%02d" for width == 2

  // Formats an int value as "%X".
  static std::string FormatHexInt(int value);

  // Formats a byte as "%02X".
  static std::string FormatByte(unsigned char value);

 private:
  String();  // Not meant to be instantiated.
};  // class String

// Gets the content of the stringstream's buffer as an std::string.  Each '\0'
// character in the buffer is replaced with "\\0".
GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: keith.ray@gmail.com (Keith Ray)
//
// Google Test filepath utilities
//
// This header file declares classes and functions used internally by
// Google Test.  They are subject to change without notice.
//
// This file is #included in <gtest/internal/gtest-internal.h>.
// Do not include this header file separately!

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_


namespace testing {
namespace internal {

// FilePath - a class for file and directory pathname manipulation which
// handles platform-specific conventions (like the pathname separator).
// Used for helper functions for naming files in a directory for xml output.
// Except for Set methods, all methods are const or static, which provides an
// "immutable value object" -- useful for peace of mind.
// A FilePath with a value ending in a path separator ("like/this/") represents
// a directory, otherwise it is assumed to represent a file. In either case,
// it may or may not represent an actual file or directory in the file system.
// Names are NOT checked for syntax correctness -- no checking for illegal
// characters, malformed paths, etc.

class GTEST_API_ FilePath {
 public:
  FilePath() : pathname_("") { }
  FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }

  explicit FilePath(const std::string& pathname) : pathname_(pathname) {
    Normalize();
  }

  FilePath& operator=(const FilePath& rhs) {
    Set(rhs);
    return *this;
  }

  void Set(const FilePath& rhs) {
    pathname_ = rhs.pathname_;
  }

  const std::string& string() const { return pathname_; }
  const char* c_str() const { return pathname_.c_str(); }

  // Returns the current working directory, or "" if unsuccessful.
  static FilePath GetCurrentDir();

  // Given directory = "dir", base_name = "test", number = 0,
  // extension = "xml", returns "dir/test.xml". If number is greater
  // than zero (e.g., 12), returns "dir/test_12.xml".
  // On Windows platform, uses \ as the separator rather than /.
  static FilePath MakeFileName(const FilePath& directory,
                               const FilePath& base_name,
                               int number,
                               const char* extension);

  // Given directory = "dir", relative_path = "test.xml",
  // returns "dir/test.xml".
  // On Windows, uses \ as the separator rather than /.
  static FilePath ConcatPaths(const FilePath& directory,
                              const FilePath& relative_path);

  // Returns a pathname for a file that does not currently exist. The pathname
  // will be directory/base_name.extension or
  // directory/base_name_<number>.extension if directory/base_name.extension
  // already exists. The number will be incremented until a pathname is found
  // that does not already exist.
  // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
  // There could be a race condition if two or more processes are calling this
  // function at the same time -- they could both pick the same filename.
  static FilePath GenerateUniqueFileName(const FilePath& directory,
                                         const FilePath& base_name,
                                         const char* extension);

  // Returns true iff the path is "".
  bool IsEmpty() const { return pathname_.empty(); }

  // If input name has a trailing separator character, removes it and returns
  // the name, otherwise return the name string unmodified.
  // On Windows platform, uses \ as the separator, other platforms use /.
  FilePath RemoveTrailingPathSeparator() const;

  // Returns a copy of the FilePath with the directory part removed.
  // Example: FilePath("path/to/file").RemoveDirectoryName() returns
  // FilePath("file"). If there is no directory part ("just_a_file"), it returns
  // the FilePath unmodified. If there is no file part ("just_a_dir/") it
  // returns an empty FilePath ("").
  // On Windows platform, '\' is the path separator, otherwise it is '/'.
  FilePath RemoveDirectoryName() const;

  // RemoveFileName returns the directory path with the filename removed.
  // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
  // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
  // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
  // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
  // On Windows platform, '\' is the path separator, otherwise it is '/'.
  FilePath RemoveFileName() const;

  // Returns a copy of the FilePath with the case-insensitive extension removed.
  // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
  // FilePath("dir/file"). If a case-insensitive extension is not
  // found, returns a copy of the original FilePath.
  FilePath RemoveExtension(const char* extension) const;

  // Creates directories so that path exists. Returns true if successful or if
  // the directories already exist; returns false if unable to create
  // directories for any reason. Will also return false if the FilePath does
  // not represent a directory (that is, it doesn't end with a path separator).
  bool CreateDirectoriesRecursively() const;

  // Create the directory so that path exists. Returns true if successful or
  // if the directory already exists; returns false if unable to create the
  // directory for any reason, including if the parent directory does not
  // exist. Not named "CreateDirectory" because that's a macro on Windows.
  bool CreateFolder() const;

  // Returns true if FilePath describes something in the file-system,
  // either a file, directory, or whatever, and that something exists.
  bool FileOrDirectoryExists() const;

  // Returns true if pathname describes a directory in the file-system
  // that exists.
  bool DirectoryExists() const;

  // Returns true if FilePath ends with a path separator, which indicates that
  // it is intended to represent a directory. Returns false otherwise.
  // This does NOT check that a directory (or file) actually exists.
  bool IsDirectory() const;

  // Returns true if pathname describes a root directory. (Windows has one
  // root directory per disk drive.)
  bool IsRootDirectory() const;

  // Returns true if pathname describes an absolute path.
  bool IsAbsolutePath() const;

 private:
  // Replaces multiple consecutive separators with a single separator.
  // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
  // redundancies that might be in a pathname involving "." or "..".
  //
  // A pathname with multiple consecutive separators may occur either through
  // user error or as a result of some scripts or APIs that generate a pathname
  // with a trailing separator. On other platforms the same API or script
  // may NOT generate a pathname with a trailing "/". Then elsewhere that
  // pathname may have another "/" and pathname components added to it,
  // without checking for the separator already being there.
  // The script language and operating system may allow paths like "foo//bar"
  // but some of the functions in FilePath will not handle that correctly. In
  // particular, RemoveTrailingPathSeparator() only removes one separator, and
  // it is called in CreateDirectoriesRecursively() assuming that it will change
  // a pathname from directory syntax (trailing separator) to filename syntax.
  //
  // On Windows this method also replaces the alternate path separator '/' with
  // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
  // "bar\\foo".

  void Normalize();

  // Returns a pointer to the last occurence of a valid path separator in
  // the FilePath. On Windows, for example, both '/' and '\' are valid path
  // separators. Returns NULL if no path separator was found.
  const char* FindLastPathSeparator() const;

  std::string pathname_;
};  // class FilePath

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
// This file was GENERATED by command:
//     pump.py gtest-type-util.h.pump
// DO NOT EDIT BY HAND!!!

// Copyright 2008 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)

// Type utilities needed for implementing typed and type-parameterized
// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
//
// Currently we support at most 50 types in a list, and at most 50
// type-parameterized tests in one type-parameterized test case.
// Please contact googletestframework@googlegroups.com if you need
// more.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_


// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
// libstdc++ (which is where cxxabi.h comes from).
# if GTEST_HAS_CXXABI_H_
#  include <cxxabi.h>
# elif defined(__HP_aCC)
#  include <acxx_demangle.h>
# endif  // GTEST_HASH_CXXABI_H_

namespace testing {
namespace internal {

// GetTypeName<T>() returns a human-readable name of type T.
// NB: This function is also used in Google Mock, so don't move it inside of
// the typed-test-only section below.
template <typename T>
std::string GetTypeName() {
# if GTEST_HAS_RTTI

  const char* const name = typeid(T).name();
#  if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
  int status = 0;
  // gcc's implementation of typeid(T).name() mangles the type name,
  // so we have to demangle it.
#   if GTEST_HAS_CXXABI_H_
  using abi::__cxa_demangle;
#   endif  // GTEST_HAS_CXXABI_H_
  char* const readable_name = __cxa_demangle(name, 0, 0, &status);
  const std::string name_str(status == 0 ? readable_name : name);
  free(readable_name);
  return name_str;
#  else
  return name;
#  endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC

# else

  return "<type>";

# endif  // GTEST_HAS_RTTI
}

#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
// type.  This can be used as a compile-time assertion to ensure that
// two types are equal.

template <typename T1, typename T2>
struct AssertTypeEq;

template <typename T>
struct AssertTypeEq<T, T> {
  typedef bool type;
};

// A unique type used as the default value for the arguments of class
// template Types.  This allows us to simulate variadic templates
// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
// support directly.
struct None {};

// The following family of struct and struct templates are used to
// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
// represents a type list with N types (T1, T2, ..., and TN) in it.
// Except for Types0, every struct in the family has two member types:
// Head for the first type in the list, and Tail for the rest of the
// list.

// The empty type list.
struct Types0 {};

// Type lists of length 1, 2, 3, and so on.

template <typename T1>
struct Types1 {
  typedef T1 Head;
  typedef Types0 Tail;
};
template <typename T1, typename T2>
struct Types2 {
  typedef T1 Head;
  typedef Types1<T2> Tail;
};

template <typename T1, typename T2, typename T3>
struct Types3 {
  typedef T1 Head;
  typedef Types2<T2, T3> Tail;
};

template <typename T1, typename T2, typename T3, typename T4>
struct Types4 {
  typedef T1 Head;
  typedef Types3<T2, T3, T4> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5>
struct Types5 {
  typedef T1 Head;
  typedef Types4<T2, T3, T4, T5> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6>
struct Types6 {
  typedef T1 Head;
  typedef Types5<T2, T3, T4, T5, T6> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7>
struct Types7 {
  typedef T1 Head;
  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8>
struct Types8 {
  typedef T1 Head;
  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9>
struct Types9 {
  typedef T1 Head;
  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10>
struct Types10 {
  typedef T1 Head;
  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11>
struct Types11 {
  typedef T1 Head;
  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12>
struct Types12 {
  typedef T1 Head;
  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13>
struct Types13 {
  typedef T1 Head;
  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14>
struct Types14 {
  typedef T1 Head;
  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15>
struct Types15 {
  typedef T1 Head;
  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16>
struct Types16 {
  typedef T1 Head;
  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17>
struct Types17 {
  typedef T1 Head;
  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18>
struct Types18 {
  typedef T1 Head;
  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19>
struct Types19 {
  typedef T1 Head;
  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20>
struct Types20 {
  typedef T1 Head;
  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21>
struct Types21 {
  typedef T1 Head;
  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22>
struct Types22 {
  typedef T1 Head;
  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23>
struct Types23 {
  typedef T1 Head;
  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24>
struct Types24 {
  typedef T1 Head;
  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25>
struct Types25 {
  typedef T1 Head;
  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26>
struct Types26 {
  typedef T1 Head;
  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27>
struct Types27 {
  typedef T1 Head;
  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28>
struct Types28 {
  typedef T1 Head;
  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29>
struct Types29 {
  typedef T1 Head;
  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30>
struct Types30 {
  typedef T1 Head;
  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31>
struct Types31 {
  typedef T1 Head;
  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32>
struct Types32 {
  typedef T1 Head;
  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33>
struct Types33 {
  typedef T1 Head;
  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34>
struct Types34 {
  typedef T1 Head;
  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35>
struct Types35 {
  typedef T1 Head;
  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36>
struct Types36 {
  typedef T1 Head;
  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37>
struct Types37 {
  typedef T1 Head;
  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38>
struct Types38 {
  typedef T1 Head;
  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39>
struct Types39 {
  typedef T1 Head;
  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40>
struct Types40 {
  typedef T1 Head;
  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41>
struct Types41 {
  typedef T1 Head;
  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42>
struct Types42 {
  typedef T1 Head;
  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43>
struct Types43 {
  typedef T1 Head;
  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44>
struct Types44 {
  typedef T1 Head;
  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45>
struct Types45 {
  typedef T1 Head;
  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46>
struct Types46 {
  typedef T1 Head;
  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45, T46> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47>
struct Types47 {
  typedef T1 Head;
  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45, T46, T47> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48>
struct Types48 {
  typedef T1 Head;
  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45, T46, T47, T48> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49>
struct Types49 {
  typedef T1 Head;
  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45, T46, T47, T48, T49> Tail;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49, typename T50>
struct Types50 {
  typedef T1 Head;
  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
      T44, T45, T46, T47, T48, T49, T50> Tail;
};


}  // namespace internal

// We don't want to require the users to write TypesN<...> directly,
// as that would require them to count the length.  Types<...> is much
// easier to write, but generates horrible messages when there is a
// compiler error, as gcc insists on printing out each template
// argument, even if it has the default value (this means Types<int>
// will appear as Types<int, None, None, ..., None> in the compiler
// errors).
//
// Our solution is to combine the best part of the two approaches: a
// user would write Types<T1, ..., TN>, and Google Test will translate
// that to TypesN<T1, ..., TN> internally to make error messages
// readable.  The translation is done by the 'type' member of the
// Types template.
template <typename T1 = internal::None, typename T2 = internal::None,
    typename T3 = internal::None, typename T4 = internal::None,
    typename T5 = internal::None, typename T6 = internal::None,
    typename T7 = internal::None, typename T8 = internal::None,
    typename T9 = internal::None, typename T10 = internal::None,
    typename T11 = internal::None, typename T12 = internal::None,
    typename T13 = internal::None, typename T14 = internal::None,
    typename T15 = internal::None, typename T16 = internal::None,
    typename T17 = internal::None, typename T18 = internal::None,
    typename T19 = internal::None, typename T20 = internal::None,
    typename T21 = internal::None, typename T22 = internal::None,
    typename T23 = internal::None, typename T24 = internal::None,
    typename T25 = internal::None, typename T26 = internal::None,
    typename T27 = internal::None, typename T28 = internal::None,
    typename T29 = internal::None, typename T30 = internal::None,
    typename T31 = internal::None, typename T32 = internal::None,
    typename T33 = internal::None, typename T34 = internal::None,
    typename T35 = internal::None, typename T36 = internal::None,
    typename T37 = internal::None, typename T38 = internal::None,
    typename T39 = internal::None, typename T40 = internal::None,
    typename T41 = internal::None, typename T42 = internal::None,
    typename T43 = internal::None, typename T44 = internal::None,
    typename T45 = internal::None, typename T46 = internal::None,
    typename T47 = internal::None, typename T48 = internal::None,
    typename T49 = internal::None, typename T50 = internal::None>
struct Types {
  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
};

template <>
struct Types<internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types0 type;
};
template <typename T1>
struct Types<T1, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types1<T1> type;
};
template <typename T1, typename T2>
struct Types<T1, T2, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types2<T1, T2> type;
};
template <typename T1, typename T2, typename T3>
struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types3<T1, T2, T3> type;
};
template <typename T1, typename T2, typename T3, typename T4>
struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types4<T1, T2, T3, T4> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5>
struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types5<T1, T2, T3, T4, T5> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6>
struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7>
struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None, internal::None> {
  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    internal::None, internal::None, internal::None, internal::None,
    internal::None, internal::None> {
  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
    internal::None, internal::None, internal::None, internal::None,
    internal::None> {
  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
    T46, internal::None, internal::None, internal::None, internal::None> {
  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
    T46, T47, internal::None, internal::None, internal::None> {
  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46, T47> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
    T46, T47, T48, internal::None, internal::None> {
  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46, T47, T48> type;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49>
struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
    T46, T47, T48, T49, internal::None> {
  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
};

namespace internal {

# define GTEST_TEMPLATE_ template <typename T> class

// The template "selector" struct TemplateSel<Tmpl> is used to
// represent Tmpl, which must be a class template with one type
// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined
// as the type Tmpl<T>.  This allows us to actually instantiate the
// template "selected" by TemplateSel<Tmpl>.
//
// This trick is necessary for simulating typedef for class templates,
// which C++ doesn't support directly.
template <GTEST_TEMPLATE_ Tmpl>
struct TemplateSel {
  template <typename T>
  struct Bind {
    typedef Tmpl<T> type;
  };
};

# define GTEST_BIND_(TmplSel, T) \
  TmplSel::template Bind<T>::type

// A unique struct template used as the default value for the
// arguments of class template Templates.  This allows us to simulate
// variadic templates (e.g. Templates<int>, Templates<int, double>,
// and etc), which C++ doesn't support directly.
template <typename T>
struct NoneT {};

// The following family of struct and struct templates are used to
// represent template lists.  In particular, TemplatesN<T1, T2, ...,
// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
// for Templates0, every struct in the family has two member types:
// Head for the selector of the first template in the list, and Tail
// for the rest of the list.

// The empty template list.
struct Templates0 {};

// Template lists of length 1, 2, 3, and so on.

template <GTEST_TEMPLATE_ T1>
struct Templates1 {
  typedef TemplateSel<T1> Head;
  typedef Templates0 Tail;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
struct Templates2 {
  typedef TemplateSel<T1> Head;
  typedef Templates1<T2> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
struct Templates3 {
  typedef TemplateSel<T1> Head;
  typedef Templates2<T2, T3> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4>
struct Templates4 {
  typedef TemplateSel<T1> Head;
  typedef Templates3<T2, T3, T4> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
struct Templates5 {
  typedef TemplateSel<T1> Head;
  typedef Templates4<T2, T3, T4, T5> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
struct Templates6 {
  typedef TemplateSel<T1> Head;
  typedef Templates5<T2, T3, T4, T5, T6> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7>
struct Templates7 {
  typedef TemplateSel<T1> Head;
  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
struct Templates8 {
  typedef TemplateSel<T1> Head;
  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
struct Templates9 {
  typedef TemplateSel<T1> Head;
  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10>
struct Templates10 {
  typedef TemplateSel<T1> Head;
  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
struct Templates11 {
  typedef TemplateSel<T1> Head;
  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
struct Templates12 {
  typedef TemplateSel<T1> Head;
  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13>
struct Templates13 {
  typedef TemplateSel<T1> Head;
  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
struct Templates14 {
  typedef TemplateSel<T1> Head;
  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
struct Templates15 {
  typedef TemplateSel<T1> Head;
  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16>
struct Templates16 {
  typedef TemplateSel<T1> Head;
  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
struct Templates17 {
  typedef TemplateSel<T1> Head;
  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
struct Templates18 {
  typedef TemplateSel<T1> Head;
  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19>
struct Templates19 {
  typedef TemplateSel<T1> Head;
  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
struct Templates20 {
  typedef TemplateSel<T1> Head;
  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
struct Templates21 {
  typedef TemplateSel<T1> Head;
  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22>
struct Templates22 {
  typedef TemplateSel<T1> Head;
  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
struct Templates23 {
  typedef TemplateSel<T1> Head;
  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
struct Templates24 {
  typedef TemplateSel<T1> Head;
  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25>
struct Templates25 {
  typedef TemplateSel<T1> Head;
  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
struct Templates26 {
  typedef TemplateSel<T1> Head;
  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
struct Templates27 {
  typedef TemplateSel<T1> Head;
  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28>
struct Templates28 {
  typedef TemplateSel<T1> Head;
  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
struct Templates29 {
  typedef TemplateSel<T1> Head;
  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
struct Templates30 {
  typedef TemplateSel<T1> Head;
  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31>
struct Templates31 {
  typedef TemplateSel<T1> Head;
  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
struct Templates32 {
  typedef TemplateSel<T1> Head;
  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
struct Templates33 {
  typedef TemplateSel<T1> Head;
  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34>
struct Templates34 {
  typedef TemplateSel<T1> Head;
  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
struct Templates35 {
  typedef TemplateSel<T1> Head;
  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
struct Templates36 {
  typedef TemplateSel<T1> Head;
  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37>
struct Templates37 {
  typedef TemplateSel<T1> Head;
  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
struct Templates38 {
  typedef TemplateSel<T1> Head;
  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
struct Templates39 {
  typedef TemplateSel<T1> Head;
  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40>
struct Templates40 {
  typedef TemplateSel<T1> Head;
  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
struct Templates41 {
  typedef TemplateSel<T1> Head;
  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
struct Templates42 {
  typedef TemplateSel<T1> Head;
  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43>
struct Templates43 {
  typedef TemplateSel<T1> Head;
  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
struct Templates44 {
  typedef TemplateSel<T1> Head;
  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
struct Templates45 {
  typedef TemplateSel<T1> Head;
  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46>
struct Templates46 {
  typedef TemplateSel<T1> Head;
  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45, T46> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
struct Templates47 {
  typedef TemplateSel<T1> Head;
  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45, T46, T47> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
struct Templates48 {
  typedef TemplateSel<T1> Head;
  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45, T46, T47, T48> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
    GTEST_TEMPLATE_ T49>
struct Templates49 {
  typedef TemplateSel<T1> Head;
  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45, T46, T47, T48, T49> Tail;
};

template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
struct Templates50 {
  typedef TemplateSel<T1> Head;
  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
      T43, T44, T45, T46, T47, T48, T49, T50> Tail;
};


// We don't want to require the users to write TemplatesN<...> directly,
// as that would require them to count the length.  Templates<...> is much
// easier to write, but generates horrible messages when there is a
// compiler error, as gcc insists on printing out each template
// argument, even if it has the default value (this means Templates<list>
// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
// errors).
//
// Our solution is to combine the best part of the two approaches: a
// user would write Templates<T1, ..., TN>, and Google Test will translate
// that to TemplatesN<T1, ..., TN> internally to make error messages
// readable.  The translation is done by the 'type' member of the
// Templates template.
template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
struct Templates {
  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
};

template <>
struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT> {
  typedef Templates0 type;
};
template <GTEST_TEMPLATE_ T1>
struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT> {
  typedef Templates1<T1> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT> {
  typedef Templates2<T1, T2> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates3<T1, T2, T3> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4>
struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates4<T1, T2, T3, T4> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates5<T1, T2, T3, T4, T5> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates6<T1, T2, T3, T4, T5, T6> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7>
struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT> {
  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT> {
  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT> {
  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT> {
  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT> {
  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT> {
  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT> {
  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT> {
  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT> {
  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT> {
  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT> {
  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT> {
  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    T45, T46, NoneT, NoneT, NoneT, NoneT> {
  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45, T46> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    T45, T46, T47, NoneT, NoneT, NoneT> {
  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45, T46, T47> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    T45, T46, T47, T48, NoneT, NoneT> {
  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45, T46, T47, T48> type;
};
template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
    GTEST_TEMPLATE_ T49>
struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
    T45, T46, T47, T48, T49, NoneT> {
  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
      T42, T43, T44, T45, T46, T47, T48, T49> type;
};

// The TypeList template makes it possible to use either a single type
// or a Types<...> list in TYPED_TEST_CASE() and
// INSTANTIATE_TYPED_TEST_CASE_P().

template <typename T>
struct TypeList {
  typedef Types1<T> type;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49, typename T50>
struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46, T47, T48, T49, T50> > {
  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
};

#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_

// Due to C++ preprocessor weirdness, we need double indirection to
// concatenate two tokens when one of them is __LINE__.  Writing
//
//   foo ## __LINE__
//
// will result in the token foo__LINE__, instead of foo followed by
// the current line number.  For more details, see
// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar

class ProtocolMessage;
namespace proto2 { class Message; }

namespace testing {

// Forward declarations.

class AssertionResult;                 // Result of an assertion.
class Message;                         // Represents a failure message.
class Test;                            // Represents a test.
class TestInfo;                        // Information about a test.
class TestPartResult;                  // Result of a test part.
class UnitTest;                        // A collection of test cases.

template <typename T>
::std::string PrintToString(const T& value);

namespace internal {

struct TraceInfo;                      // Information about a trace point.
class ScopedTrace;                     // Implements scoped trace.
class TestInfoImpl;                    // Opaque implementation of TestInfo
class UnitTestImpl;                    // Opaque implementation of UnitTest

// How many times InitGoogleTest() has been called.
GTEST_API_ extern int g_init_gtest_count;

// The text used in failure messages to indicate the start of the
// stack trace.
GTEST_API_ extern const char kStackTraceMarker[];

// Two overloaded helpers for checking at compile time whether an
// expression is a null pointer literal (i.e. NULL or any 0-valued
// compile-time integral constant).  Their return values have
// different sizes, so we can use sizeof() to test which version is
// picked by the compiler.  These helpers have no implementations, as
// we only need their signatures.
//
// Given IsNullLiteralHelper(x), the compiler will pick the first
// version if x can be implicitly converted to Secret*, and pick the
// second version otherwise.  Since Secret is a secret and incomplete
// type, the only expression a user can write that has type Secret* is
// a null pointer literal.  Therefore, we know that x is a null
// pointer literal if and only if the first version is picked by the
// compiler.
char IsNullLiteralHelper(Secret* p);
char (&IsNullLiteralHelper(...))[2];  // NOLINT

// A compile-time bool constant that is true if and only if x is a
// null pointer literal (i.e. NULL or any 0-valued compile-time
// integral constant).
#ifdef GTEST_ELLIPSIS_NEEDS_POD_
// We lose support for NULL detection where the compiler doesn't like
// passing non-POD classes through ellipsis (...).
# define GTEST_IS_NULL_LITERAL_(x) false
#else
# define GTEST_IS_NULL_LITERAL_(x) \
    (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
#endif  // GTEST_ELLIPSIS_NEEDS_POD_

// Appends the user-supplied message to the Google-Test-generated message.
GTEST_API_ std::string AppendUserMessage(
    const std::string& gtest_msg, const Message& user_msg);

#if GTEST_HAS_EXCEPTIONS

// This exception is thrown by (and only by) a failed Google Test
// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
// are enabled).  We derive it from std::runtime_error, which is for
// errors presumably detectable only at run time.  Since
// std::runtime_error inherits from std::exception, many testing
// frameworks know how to extract and print the message inside it.
class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
 public:
  explicit GoogleTestFailureException(const TestPartResult& failure);
};

#endif  // GTEST_HAS_EXCEPTIONS

// A helper class for creating scoped traces in user programs.
class GTEST_API_ ScopedTrace {
 public:
  // The c'tor pushes the given source file location and message onto
  // a trace stack maintained by Google Test.
  ScopedTrace(const char* file, int line, const Message& message);

  // The d'tor pops the info pushed by the c'tor.
  //
  // Note that the d'tor is not virtual in order to be efficient.
  // Don't inherit from ScopedTrace!
  ~ScopedTrace();

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
} GTEST_ATTRIBUTE_UNUSED_;  // A ScopedTrace object does its job in its
                            // c'tor and d'tor.  Therefore it doesn't
                            // need to be used otherwise.

// Constructs and returns the message for an equality assertion
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
//
// The first four parameters are the expressions used in the assertion
// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
// where foo is 5 and bar is 6, we have:
//
//   expected_expression: "foo"
//   actual_expression:   "bar"
//   expected_value:      "5"
//   actual_value:        "6"
//
// The ignoring_case parameter is true iff the assertion is a
// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
// be inserted into the message.
GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
                                     const char* actual_expression,
                                     const std::string& expected_value,
                                     const std::string& actual_value,
                                     bool ignoring_case);

// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
GTEST_API_ std::string GetBoolAssertionFailureMessage(
    const AssertionResult& assertion_result,
    const char* expression_text,
    const char* actual_predicate_value,
    const char* expected_predicate_value);

// This template class represents an IEEE floating-point number
// (either single-precision or double-precision, depending on the
// template parameters).
//
// The purpose of this class is to do more sophisticated number
// comparison.  (Due to round-off error, etc, it's very unlikely that
// two floating-points will be equal exactly.  Hence a naive
// comparison by the == operation often doesn't work.)
//
// Format of IEEE floating-point:
//
//   The most-significant bit being the leftmost, an IEEE
//   floating-point looks like
//
//     sign_bit exponent_bits fraction_bits
//
//   Here, sign_bit is a single bit that designates the sign of the
//   number.
//
//   For float, there are 8 exponent bits and 23 fraction bits.
//
//   For double, there are 11 exponent bits and 52 fraction bits.
//
//   More details can be found at
//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
//
// Template parameter:
//
//   RawType: the raw floating-point type (either float or double)
template <typename RawType>
class FloatingPoint {
 public:
  // Defines the unsigned integer type that has the same size as the
  // floating point number.
  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;

  // Constants.

  // # of bits in a number.
  static const size_t kBitCount = 8*sizeof(RawType);

  // # of fraction bits in a number.
  static const size_t kFractionBitCount =
    std::numeric_limits<RawType>::digits - 1;

  // # of exponent bits in a number.
  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;

  // The mask for the sign bit.
  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);

  // The mask for the fraction bits.
  static const Bits kFractionBitMask =
    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);

  // The mask for the exponent bits.
  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);

  // How many ULP's (Units in the Last Place) we want to tolerate when
  // comparing two numbers.  The larger the value, the more error we
  // allow.  A 0 value means that two numbers must be exactly the same
  // to be considered equal.
  //
  // The maximum error of a single floating-point operation is 0.5
  // units in the last place.  On Intel CPU's, all floating-point
  // calculations are done with 80-bit precision, while double has 64
  // bits.  Therefore, 4 should be enough for ordinary use.
  //
  // See the following article for more details on ULP:
  // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
  static const size_t kMaxUlps = 4;

  // Constructs a FloatingPoint from a raw floating-point number.
  //
  // On an Intel CPU, passing a non-normalized NAN (Not a Number)
  // around may change its bits, although the new value is guaranteed
  // to be also a NAN.  Therefore, don't expect this constructor to
  // preserve the bits in x when x is a NAN.
  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }

  // Static methods

  // Reinterprets a bit pattern as a floating-point number.
  //
  // This function is needed to test the AlmostEquals() method.
  static RawType ReinterpretBits(const Bits bits) {
    FloatingPoint fp(0);
    fp.u_.bits_ = bits;
    return fp.u_.value_;
  }

  // Returns the floating-point number that represent positive infinity.
  static RawType Infinity() {
    return ReinterpretBits(kExponentBitMask);
  }

  // Returns the maximum representable finite floating-point number.
  static RawType Max();

  // Non-static methods

  // Returns the bits that represents this number.
  const Bits &bits() const { return u_.bits_; }

  // Returns the exponent bits of this number.
  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }

  // Returns the fraction bits of this number.
  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }

  // Returns the sign bit of this number.
  Bits sign_bit() const { return kSignBitMask & u_.bits_; }

  // Returns true iff this is NAN (not a number).
  bool is_nan() const {
    // It's a NAN if the exponent bits are all ones and the fraction
    // bits are not entirely zeros.
    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
  }

  // Returns true iff this number is at most kMaxUlps ULP's away from
  // rhs.  In particular, this function:
  //
  //   - returns false if either number is (or both are) NAN.
  //   - treats really large numbers as almost equal to infinity.
  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
  bool AlmostEquals(const FloatingPoint& rhs) const {
    // The IEEE standard says that any comparison operation involving
    // a NAN must return false.
    if (is_nan() || rhs.is_nan()) return false;

    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
        <= kMaxUlps;
  }

 private:
  // The data type used to store the actual floating-point number.
  union FloatingPointUnion {
    RawType value_;  // The raw floating-point number.
    Bits bits_;      // The bits that represent the number.
  };

  // Converts an integer from the sign-and-magnitude representation to
  // the biased representation.  More precisely, let N be 2 to the
  // power of (kBitCount - 1), an integer x is represented by the
  // unsigned number x + N.
  //
  // For instance,
  //
  //   -N + 1 (the most negative number representable using
  //          sign-and-magnitude) is represented by 1;
  //   0      is represented by N; and
  //   N - 1  (the biggest number representable using
  //          sign-and-magnitude) is represented by 2N - 1.
  //
  // Read http://en.wikipedia.org/wiki/Signed_number_representations
  // for more details on signed number representations.
  static Bits SignAndMagnitudeToBiased(const Bits &sam) {
    if (kSignBitMask & sam) {
      // sam represents a negative number.
      return ~sam + 1;
    } else {
      // sam represents a positive number.
      return kSignBitMask | sam;
    }
  }

  // Given two numbers in the sign-and-magnitude representation,
  // returns the distance between them as an unsigned number.
  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
                                                     const Bits &sam2) {
    const Bits biased1 = SignAndMagnitudeToBiased(sam1);
    const Bits biased2 = SignAndMagnitudeToBiased(sam2);
    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
  }

  FloatingPointUnion u_;
};

// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
// macro defined by <windows.h>.
template <>
inline float FloatingPoint<float>::Max() { return FLT_MAX; }
template <>
inline double FloatingPoint<double>::Max() { return DBL_MAX; }

// Typedefs the instances of the FloatingPoint template class that we
// care to use.
typedef FloatingPoint<float> Float;
typedef FloatingPoint<double> Double;

// In order to catch the mistake of putting tests that use different
// test fixture classes in the same test case, we need to assign
// unique IDs to fixture classes and compare them.  The TypeId type is
// used to hold such IDs.  The user should treat TypeId as an opaque
// type: the only operation allowed on TypeId values is to compare
// them for equality using the == operator.
typedef const void* TypeId;

template <typename T>
class TypeIdHelper {
 public:
  // dummy_ must not have a const type.  Otherwise an overly eager
  // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
  // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
  static bool dummy_;
};

template <typename T>
bool TypeIdHelper<T>::dummy_ = false;

// GetTypeId<T>() returns the ID of type T.  Different values will be
// returned for different types.  Calling the function twice with the
// same type argument is guaranteed to return the same ID.
template <typename T>
TypeId GetTypeId() {
  // The compiler is required to allocate a different
  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
  // the template.  Therefore, the address of dummy_ is guaranteed to
  // be unique.
  return &(TypeIdHelper<T>::dummy_);
}

// Returns the type ID of ::testing::Test.  Always call this instead
// of GetTypeId< ::testing::Test>() to get the type ID of
// ::testing::Test, as the latter may give the wrong result due to a
// suspected linker bug when compiling Google Test as a Mac OS X
// framework.
GTEST_API_ TypeId GetTestTypeId();

// Defines the abstract factory interface that creates instances
// of a Test object.
class TestFactoryBase {
 public:
  virtual ~TestFactoryBase() {}

  // Creates a test instance to run. The instance is both created and destroyed
  // within TestInfoImpl::Run()
  virtual Test* CreateTest() = 0;

 protected:
  TestFactoryBase() {}

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
};

// This class provides implementation of TeastFactoryBase interface.
// It is used in TEST and TEST_F macros.
template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
 public:
  virtual Test* CreateTest() { return new TestClass; }
};

#if GTEST_OS_WINDOWS

// Predicate-formatters for implementing the HRESULT checking macros
// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
// We pass a long instead of HRESULT to avoid causing an
// include dependency for the HRESULT type.
GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
                                            long hr);  // NOLINT
GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
                                            long hr);  // NOLINT

#endif  // GTEST_OS_WINDOWS

// Types of SetUpTestCase() and TearDownTestCase() functions.
typedef void (*SetUpTestCaseFunc)();
typedef void (*TearDownTestCaseFunc)();

// Creates a new TestInfo object and registers it with Google Test;
// returns the created object.
//
// Arguments:
//
//   test_case_name:   name of the test case
//   name:             name of the test
//   type_param        the name of the test's type parameter, or NULL if
//                     this is not a typed or a type-parameterized test.
//   value_param       text representation of the test's value parameter,
//                     or NULL if this is not a type-parameterized test.
//   fixture_class_id: ID of the test fixture class
//   set_up_tc:        pointer to the function that sets up the test case
//   tear_down_tc:     pointer to the function that tears down the test case
//   factory:          pointer to the factory that creates a test object.
//                     The newly created TestInfo instance will assume
//                     ownership of the factory object.
GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
    const char* test_case_name,
    const char* name,
    const char* type_param,
    const char* value_param,
    TypeId fixture_class_id,
    SetUpTestCaseFunc set_up_tc,
    TearDownTestCaseFunc tear_down_tc,
    TestFactoryBase* factory);

// If *pstr starts with the given prefix, modifies *pstr to be right
// past the prefix and returns true; otherwise leaves *pstr unchanged
// and returns false.  None of pstr, *pstr, and prefix can be NULL.
GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);

#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

// State of the definition of a type-parameterized test case.
class GTEST_API_ TypedTestCasePState {
 public:
  TypedTestCasePState() : registered_(false) {}

  // Adds the given test name to defined_test_names_ and return true
  // if the test case hasn't been registered; otherwise aborts the
  // program.
  bool AddTestName(const char* file, int line, const char* case_name,
                   const char* test_name) {
    if (registered_) {
      fprintf(stderr, "%s Test %s must be defined before "
              "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
              FormatFileLocation(file, line).c_str(), test_name, case_name);
      fflush(stderr);
      posix::Abort();
    }
    defined_test_names_.insert(test_name);
    return true;
  }

  // Verifies that registered_tests match the test names in
  // defined_test_names_; returns registered_tests if successful, or
  // aborts the program otherwise.
  const char* VerifyRegisteredTestNames(
      const char* file, int line, const char* registered_tests);

 private:
  bool registered_;
  ::std::set<const char*> defined_test_names_;
};

// Skips to the first non-space char after the first comma in 'str';
// returns NULL if no comma is found in 'str'.
inline const char* SkipComma(const char* str) {
  const char* comma = strchr(str, ',');
  if (comma == NULL) {
    return NULL;
  }
  while (IsSpace(*(++comma))) {}
  return comma;
}

// Returns the prefix of 'str' before the first comma in it; returns
// the entire string if it contains no comma.
inline std::string GetPrefixUntilComma(const char* str) {
  const char* comma = strchr(str, ',');
  return comma == NULL ? str : std::string(str, comma);
}

// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
// registers a list of type-parameterized tests with Google Test.  The
// return value is insignificant - we just need to return something
// such that we can call this function in a namespace scope.
//
// Implementation note: The GTEST_TEMPLATE_ macro declares a template
// template parameter.  It's defined in gtest-type-util.h.
template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
class TypeParameterizedTest {
 public:
  // 'index' is the index of the test in the type list 'Types'
  // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
  // Types).  Valid values for 'index' are [0, N - 1] where N is the
  // length of Types.
  static bool Register(const char* prefix, const char* case_name,
                       const char* test_names, int index) {
    typedef typename Types::Head Type;
    typedef Fixture<Type> FixtureClass;
    typedef typename GTEST_BIND_(TestSel, Type) TestClass;

    // First, registers the first type-parameterized test in the type
    // list.
    MakeAndRegisterTestInfo(
        (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
         + StreamableToString(index)).c_str(),
        GetPrefixUntilComma(test_names).c_str(),
        GetTypeName<Type>().c_str(),
        NULL,  // No value parameter.
        GetTypeId<FixtureClass>(),
        TestClass::SetUpTestCase,
        TestClass::TearDownTestCase,
        new TestFactoryImpl<TestClass>);

    // Next, recurses (at compile time) with the tail of the type list.
    return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
        ::Register(prefix, case_name, test_names, index + 1);
  }
};

// The base case for the compile time recursion.
template <GTEST_TEMPLATE_ Fixture, class TestSel>
class TypeParameterizedTest<Fixture, TestSel, Types0> {
 public:
  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
                       const char* /*test_names*/, int /*index*/) {
    return true;
  }
};

// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
// registers *all combinations* of 'Tests' and 'Types' with Google
// Test.  The return value is insignificant - we just need to return
// something such that we can call this function in a namespace scope.
template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
class TypeParameterizedTestCase {
 public:
  static bool Register(const char* prefix, const char* case_name,
                       const char* test_names) {
    typedef typename Tests::Head Head;

    // First, register the first test in 'Test' for each type in 'Types'.
    TypeParameterizedTest<Fixture, Head, Types>::Register(
        prefix, case_name, test_names, 0);

    // Next, recurses (at compile time) with the tail of the test list.
    return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
        ::Register(prefix, case_name, SkipComma(test_names));
  }
};

// The base case for the compile time recursion.
template <GTEST_TEMPLATE_ Fixture, typename Types>
class TypeParameterizedTestCase<Fixture, Templates0, Types> {
 public:
  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
                       const char* /*test_names*/) {
    return true;
  }
};

#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

// Returns the current OS stack trace as an std::string.
//
// The maximum number of stack frames to be included is specified by
// the gtest_stack_trace_depth flag.  The skip_count parameter
// specifies the number of top frames to be skipped, which doesn't
// count against the number of frames to be included.
//
// For example, if Foo() calls Bar(), which in turn calls
// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
    UnitTest* unit_test, int skip_count);

// Helpers for suppressing warnings on unreachable code or constant
// condition.

// Always returns true.
GTEST_API_ bool AlwaysTrue();

// Always returns false.
inline bool AlwaysFalse() { return !AlwaysTrue(); }

// Helper for suppressing false warning from Clang on a const char*
// variable declared in a conditional expression always being NULL in
// the else branch.
struct GTEST_API_ ConstCharPtr {
  ConstCharPtr(const char* str) : value(str) {}
  operator bool() const { return true; }
  const char* value;
};

// A simple Linear Congruential Generator for generating random
// numbers with a uniform distribution.  Unlike rand() and srand(), it
// doesn't use global state (and therefore can't interfere with user
// code).  Unlike rand_r(), it's portable.  An LCG isn't very random,
// but it's good enough for our purposes.
class GTEST_API_ Random {
 public:
  static const UInt32 kMaxRange = 1u << 31;

  explicit Random(UInt32 seed) : state_(seed) {}

  void Reseed(UInt32 seed) { state_ = seed; }

  // Generates a random number from [0, range).  Crashes if 'range' is
  // 0 or greater than kMaxRange.
  UInt32 Generate(UInt32 range);

 private:
  UInt32 state_;
  GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
};

// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
// compiler error iff T1 and T2 are different types.
template <typename T1, typename T2>
struct CompileAssertTypesEqual;

template <typename T>
struct CompileAssertTypesEqual<T, T> {
};

// Removes the reference from a type if it is a reference type,
// otherwise leaves it unchanged.  This is the same as
// tr1::remove_reference, which is not widely available yet.
template <typename T>
struct RemoveReference { typedef T type; };  // NOLINT
template <typename T>
struct RemoveReference<T&> { typedef T type; };  // NOLINT

// A handy wrapper around RemoveReference that works when the argument
// T depends on template parameters.
#define GTEST_REMOVE_REFERENCE_(T) \
    typename ::testing::internal::RemoveReference<T>::type

// Removes const from a type if it is a const type, otherwise leaves
// it unchanged.  This is the same as tr1::remove_const, which is not
// widely available yet.
template <typename T>
struct RemoveConst { typedef T type; };  // NOLINT
template <typename T>
struct RemoveConst<const T> { typedef T type; };  // NOLINT

// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
// definition to fail to remove the const in 'const int[3]' and 'const
// char[3][4]'.  The following specialization works around the bug.
template <typename T, size_t N>
struct RemoveConst<const T[N]> {
  typedef typename RemoveConst<T>::type type[N];
};

#if defined(_MSC_VER) && _MSC_VER < 1400
// This is the only specialization that allows VC++ 7.1 to remove const in
// 'const int[3] and 'const int[3][4]'.  However, it causes trouble with GCC
// and thus needs to be conditionally compiled.
template <typename T, size_t N>
struct RemoveConst<T[N]> {
  typedef typename RemoveConst<T>::type type[N];
};
#endif

// A handy wrapper around RemoveConst that works when the argument
// T depends on template parameters.
#define GTEST_REMOVE_CONST_(T) \
    typename ::testing::internal::RemoveConst<T>::type

// Turns const U&, U&, const U, and U all into U.
#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
    GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))

// Adds reference to a type if it is not a reference type,
// otherwise leaves it unchanged.  This is the same as
// tr1::add_reference, which is not widely available yet.
template <typename T>
struct AddReference { typedef T& type; };  // NOLINT
template <typename T>
struct AddReference<T&> { typedef T& type; };  // NOLINT

// A handy wrapper around AddReference that works when the argument T
// depends on template parameters.
#define GTEST_ADD_REFERENCE_(T) \
    typename ::testing::internal::AddReference<T>::type

// Adds a reference to const on top of T as necessary.  For example,
// it transforms
//
//   char         ==> const char&
//   const char   ==> const char&
//   char&        ==> const char&
//   const char&  ==> const char&
//
// The argument T must depend on some template parameters.
#define GTEST_REFERENCE_TO_CONST_(T) \
    GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))

// ImplicitlyConvertible<From, To>::value is a compile-time bool
// constant that's true iff type From can be implicitly converted to
// type To.
template <typename From, typename To>
class ImplicitlyConvertible {
 private:
  // We need the following helper functions only for their types.
  // They have no implementations.

  // MakeFrom() is an expression whose type is From.  We cannot simply
  // use From(), as the type From may not have a public default
  // constructor.
  static From MakeFrom();

  // These two functions are overloaded.  Given an expression
  // Helper(x), the compiler will pick the first version if x can be
  // implicitly converted to type To; otherwise it will pick the
  // second version.
  //
  // The first version returns a value of size 1, and the second
  // version returns a value of size 2.  Therefore, by checking the
  // size of Helper(x), which can be done at compile time, we can tell
  // which version of Helper() is used, and hence whether x can be
  // implicitly converted to type To.
  static char Helper(To);
  static char (&Helper(...))[2];  // NOLINT

  // We have to put the 'public' section after the 'private' section,
  // or MSVC refuses to compile the code.
 public:
  // MSVC warns about implicitly converting from double to int for
  // possible loss of data, so we need to temporarily disable the
  // warning.
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4244)  // Temporarily disables warning 4244.

  static const bool value =
      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
# pragma warning(pop)           // Restores the warning state.
#elif defined(__BORLANDC__)
  // C++Builder cannot use member overload resolution during template
  // instantiation.  The simplest workaround is to use its C++0x type traits
  // functions (C++Builder 2009 and above only).
  static const bool value = __is_convertible(From, To);
#else
  static const bool value =
      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
#endif  // _MSV_VER
};
template <typename From, typename To>
const bool ImplicitlyConvertible<From, To>::value;

// IsAProtocolMessage<T>::value is a compile-time bool constant that's
// true iff T is type ProtocolMessage, proto2::Message, or a subclass
// of those.
template <typename T>
struct IsAProtocolMessage
    : public bool_constant<
  ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
  ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
};

// When the compiler sees expression IsContainerTest<C>(0), if C is an
// STL-style container class, the first overload of IsContainerTest
// will be viable (since both C::iterator* and C::const_iterator* are
// valid types and NULL can be implicitly converted to them).  It will
// be picked over the second overload as 'int' is a perfect match for
// the type of argument 0.  If C::iterator or C::const_iterator is not
// a valid type, the first overload is not viable, and the second
// overload will be picked.  Therefore, we can determine whether C is
// a container class by checking the type of IsContainerTest<C>(0).
// The value of the expression is insignificant.
//
// Note that we look for both C::iterator and C::const_iterator.  The
// reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator').  If we look for C::iterator
// only, for example, we would mistakenly think that a class named
// iterator is an STL container.
//
// Also note that the simpler approach of overloading
// IsContainerTest(typename C::const_iterator*) and
// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,
                            typename C::iterator* /* it */ = NULL,
                            typename C::const_iterator* /* const_it */ = NULL) {
  return 0;
}

typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }

// EnableIf<condition>::type is void when 'Cond' is true, and
// undefined when 'Cond' is false.  To use SFINAE to make a function
// overload only apply when a particular expression is true, add
// "typename EnableIf<expression>::type* = 0" as the last parameter.
template<bool> struct EnableIf;
template<> struct EnableIf<true> { typedef void type; };  // NOLINT

// Utilities for native arrays.

// ArrayEq() compares two k-dimensional native arrays using the
// elements' operator==, where k can be any integer >= 0.  When k is
// 0, ArrayEq() degenerates into comparing a single pair of values.

template <typename T, typename U>
bool ArrayEq(const T* lhs, size_t size, const U* rhs);

// This generic version is used when k is 0.
template <typename T, typename U>
inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }

// This overload is used when k >= 1.
template <typename T, typename U, size_t N>
inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
  return internal::ArrayEq(lhs, N, rhs);
}

// This helper reduces code bloat.  If we instead put its logic inside
// the previous ArrayEq() function, arrays with different sizes would
// lead to different copies of the template code.
template <typename T, typename U>
bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
  for (size_t i = 0; i != size; i++) {
    if (!internal::ArrayEq(lhs[i], rhs[i]))
      return false;
  }
  return true;
}

// Finds the first element in the iterator range [begin, end) that
// equals elem.  Element may be a native array type itself.
template <typename Iter, typename Element>
Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
  for (Iter it = begin; it != end; ++it) {
    if (internal::ArrayEq(*it, elem))
      return it;
  }
  return end;
}

// CopyArray() copies a k-dimensional native array using the elements'
// operator=, where k can be any integer >= 0.  When k is 0,
// CopyArray() degenerates into copying a single value.

template <typename T, typename U>
void CopyArray(const T* from, size_t size, U* to);

// This generic version is used when k is 0.
template <typename T, typename U>
inline void CopyArray(const T& from, U* to) { *to = from; }

// This overload is used when k >= 1.
template <typename T, typename U, size_t N>
inline void CopyArray(const T(&from)[N], U(*to)[N]) {
  internal::CopyArray(from, N, *to);
}

// This helper reduces code bloat.  If we instead put its logic inside
// the previous CopyArray() function, arrays with different sizes
// would lead to different copies of the template code.
template <typename T, typename U>
void CopyArray(const T* from, size_t size, U* to) {
  for (size_t i = 0; i != size; i++) {
    internal::CopyArray(from[i], to + i);
  }
}

// The relation between an NativeArray object (see below) and the
// native array it represents.
enum RelationToSource {
  kReference,  // The NativeArray references the native array.
  kCopy        // The NativeArray makes a copy of the native array and
               // owns the copy.
};

// Adapts a native array to a read-only STL-style container.  Instead
// of the complete STL container concept, this adaptor only implements
// members useful for Google Mock's container matchers.  New members
// should be added as needed.  To simplify the implementation, we only
// support Element being a raw type (i.e. having no top-level const or
// reference modifier).  It's the client's responsibility to satisfy
// this requirement.  Element can be an array type itself (hence
// multi-dimensional arrays are supported).
template <typename Element>
class NativeArray {
 public:
  // STL-style container typedefs.
  typedef Element value_type;
  typedef Element* iterator;
  typedef const Element* const_iterator;

  // Constructs from a native array.
  NativeArray(const Element* array, size_t count, RelationToSource relation) {
    Init(array, count, relation);
  }

  // Copy constructor.
  NativeArray(const NativeArray& rhs) {
    Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
  }

  ~NativeArray() {
    // Ensures that the user doesn't instantiate NativeArray with a
    // const or reference type.
    static_cast<void>(StaticAssertTypeEqHelper<Element,
        GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
    if (relation_to_source_ == kCopy)
      delete[] array_;
  }

  // STL-style container methods.
  size_t size() const { return size_; }
  const_iterator begin() const { return array_; }
  const_iterator end() const { return array_ + size_; }
  bool operator==(const NativeArray& rhs) const {
    return size() == rhs.size() &&
        ArrayEq(begin(), size(), rhs.begin());
  }

 private:
  // Initializes this object; makes a copy of the input array if
  // 'relation' is kCopy.
  void Init(const Element* array, size_t a_size, RelationToSource relation) {
    if (relation == kReference) {
      array_ = array;
    } else {
      Element* const copy = new Element[a_size];
      CopyArray(array, a_size, copy);
      array_ = copy;
    }
    size_ = a_size;
    relation_to_source_ = relation;
  }

  const Element* array_;
  size_t size_;
  RelationToSource relation_to_source_;

  GTEST_DISALLOW_ASSIGN_(NativeArray);
};

}  // namespace internal
}  // namespace testing

#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
  ::testing::internal::AssertHelper(result_type, file, line, message) \
    = ::testing::Message()

#define GTEST_MESSAGE_(message, result_type) \
  GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)

#define GTEST_FATAL_FAILURE_(message) \
  return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)

#define GTEST_NONFATAL_FAILURE_(message) \
  GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)

#define GTEST_SUCCESS_(message) \
  GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)

// Suppresses MSVC warnings 4072 (unreachable code) for the code following
// statement if it returns or throws (or doesn't return or throw in some
// situations).
#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
  if (::testing::internal::AlwaysTrue()) { statement; }

#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::ConstCharPtr gtest_msg = "") { \
    bool gtest_caught_expected = false; \
    try { \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
    } \
    catch (expected_exception const&) { \
      gtest_caught_expected = true; \
    } \
    catch (...) { \
      gtest_msg.value = \
          "Expected: " #statement " throws an exception of type " \
          #expected_exception ".\n  Actual: it throws a different type."; \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
    } \
    if (!gtest_caught_expected) { \
      gtest_msg.value = \
          "Expected: " #statement " throws an exception of type " \
          #expected_exception ".\n  Actual: it throws nothing."; \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
      fail(gtest_msg.value)

#define GTEST_TEST_NO_THROW_(statement, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
    try { \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
    } \
    catch (...) { \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
      fail("Expected: " #statement " doesn't throw an exception.\n" \
           "  Actual: it throws.")

#define GTEST_TEST_ANY_THROW_(statement, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
    bool gtest_caught_any = false; \
    try { \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
    } \
    catch (...) { \
      gtest_caught_any = true; \
    } \
    if (!gtest_caught_any) { \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
      fail("Expected: " #statement " throws an exception.\n" \
           "  Actual: it doesn't.")


// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
// either a boolean expression or an AssertionResult. text is a textual
// represenation of expression as it was passed into the EXPECT_TRUE.
#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (const ::testing::AssertionResult gtest_ar_ = \
      ::testing::AssertionResult(expression)) \
    ; \
  else \
    fail(::testing::internal::GetBoolAssertionFailureMessage(\
        gtest_ar_, text, #actual, #expected).c_str())

#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
    ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
    if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
      fail("Expected: " #statement " doesn't generate new fatal " \
           "failures in the current thread.\n" \
           "  Actual: it does.")

// Expands to the name of the class that implements the given test.
#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
  test_case_name##_##test_name##_Test

// Helper macro for defining tests.
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
 public:\
  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
 private:\
  virtual void TestBody();\
  static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
  GTEST_DISALLOW_COPY_AND_ASSIGN_(\
      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
};\
\
::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
  ::test_info_ =\
    ::testing::internal::MakeAndRegisterTestInfo(\
        #test_case_name, #test_name, NULL, NULL, \
        (parent_id), \
        parent_class::SetUpTestCase, \
        parent_class::TearDownTestCase, \
        new ::testing::internal::TestFactoryImpl<\
            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file defines the public API for death tests.  It is
// #included by gtest.h so a user doesn't need to include this
// directly.

#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
//
// The Google C++ Testing Framework (Google Test)
//
// This header file defines internal utilities needed for implementing
// death tests.  They are subject to change without notice.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_


#include <stdio.h>

namespace testing {
namespace internal {

GTEST_DECLARE_string_(internal_run_death_test);

// Names of the flags (needed for parsing Google Test flags).
const char kDeathTestStyleFlag[] = "death_test_style";
const char kDeathTestUseFork[] = "death_test_use_fork";
const char kInternalRunDeathTestFlag[] = "internal_run_death_test";

#if GTEST_HAS_DEATH_TEST

// DeathTest is a class that hides much of the complexity of the
// GTEST_DEATH_TEST_ macro.  It is abstract; its static Create method
// returns a concrete class that depends on the prevailing death test
// style, as defined by the --gtest_death_test_style and/or
// --gtest_internal_run_death_test flags.

// In describing the results of death tests, these terms are used with
// the corresponding definitions:
//
// exit status:  The integer exit information in the format specified
//               by wait(2)
// exit code:    The integer code passed to exit(3), _exit(2), or
//               returned from main()
class GTEST_API_ DeathTest {
 public:
  // Create returns false if there was an error determining the
  // appropriate action to take for the current death test; for example,
  // if the gtest_death_test_style flag is set to an invalid value.
  // The LastMessage method will return a more detailed message in that
  // case.  Otherwise, the DeathTest pointer pointed to by the "test"
  // argument is set.  If the death test should be skipped, the pointer
  // is set to NULL; otherwise, it is set to the address of a new concrete
  // DeathTest object that controls the execution of the current test.
  static bool Create(const char* statement, const RE* regex,
                     const char* file, int line, DeathTest** test);
  DeathTest();
  virtual ~DeathTest() { }

  // A helper class that aborts a death test when it's deleted.
  class ReturnSentinel {
   public:
    explicit ReturnSentinel(DeathTest* test) : test_(test) { }
    ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
   private:
    DeathTest* const test_;
    GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
  } GTEST_ATTRIBUTE_UNUSED_;

  // An enumeration of possible roles that may be taken when a death
  // test is encountered.  EXECUTE means that the death test logic should
  // be executed immediately.  OVERSEE means that the program should prepare
  // the appropriate environment for a child process to execute the death
  // test, then wait for it to complete.
  enum TestRole { OVERSEE_TEST, EXECUTE_TEST };

  // An enumeration of the three reasons that a test might be aborted.
  enum AbortReason {
    TEST_ENCOUNTERED_RETURN_STATEMENT,
    TEST_THREW_EXCEPTION,
    TEST_DID_NOT_DIE
  };

  // Assumes one of the above roles.
  virtual TestRole AssumeRole() = 0;

  // Waits for the death test to finish and returns its status.
  virtual int Wait() = 0;

  // Returns true if the death test passed; that is, the test process
  // exited during the test, its exit status matches a user-supplied
  // predicate, and its stderr output matches a user-supplied regular
  // expression.
  // The user-supplied predicate may be a macro expression rather
  // than a function pointer or functor, or else Wait and Passed could
  // be combined.
  virtual bool Passed(bool exit_status_ok) = 0;

  // Signals that the death test did not die as expected.
  virtual void Abort(AbortReason reason) = 0;

  // Returns a human-readable outcome message regarding the outcome of
  // the last death test.
  static const char* LastMessage();

  static void set_last_death_test_message(const std::string& message);

 private:
  // A string containing a description of the outcome of the last death test.
  static std::string last_death_test_message_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
};

// Factory interface for death tests.  May be mocked out for testing.
class DeathTestFactory {
 public:
  virtual ~DeathTestFactory() { }
  virtual bool Create(const char* statement, const RE* regex,
                      const char* file, int line, DeathTest** test) = 0;
};

// A concrete DeathTestFactory implementation for normal use.
class DefaultDeathTestFactory : public DeathTestFactory {
 public:
  virtual bool Create(const char* statement, const RE* regex,
                      const char* file, int line, DeathTest** test);
};

// Returns true if exit_status describes a process that was terminated
// by a signal, or exited normally with a nonzero exit code.
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);

// Traps C++ exceptions escaping statement and reports them as test
// failures. Note that trapping SEH exceptions is not implemented here.
# if GTEST_HAS_EXCEPTIONS
#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
  try { \
    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
  } catch (const ::std::exception& gtest_exception) { \
    fprintf(\
        stderr, \
        "\n%s: Caught std::exception-derived exception escaping the " \
        "death test statement. Exception message: %s\n", \
        ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
        gtest_exception.what()); \
    fflush(stderr); \
    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
  } catch (...) { \
    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
  }

# else
#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
  GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)

# endif

// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
// ASSERT_EXIT*, and EXPECT_EXIT*.
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
    const ::testing::internal::RE& gtest_regex = (regex); \
    ::testing::internal::DeathTest* gtest_dt; \
    if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
        __FILE__, __LINE__, &gtest_dt)) { \
      goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
    } \
    if (gtest_dt != NULL) { \
      ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
          gtest_dt_ptr(gtest_dt); \
      switch (gtest_dt->AssumeRole()) { \
        case ::testing::internal::DeathTest::OVERSEE_TEST: \
          if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
            goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
          } \
          break; \
        case ::testing::internal::DeathTest::EXECUTE_TEST: { \
          ::testing::internal::DeathTest::ReturnSentinel \
              gtest_sentinel(gtest_dt); \
          GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
          gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
          break; \
        } \
        default: \
          break; \
      } \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
      fail(::testing::internal::DeathTest::LastMessage())
// The symbol "fail" here expands to something into which a message
// can be streamed.

// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
// NDEBUG mode. In this case we need the statements to be executed, the regex is
// ignored, and the macro must accept a streamed message even though the message
// is never printed.
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
     GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
  } else \
    ::testing::Message()

// A class representing the parsed contents of the
// --gtest_internal_run_death_test flag, as it existed when
// RUN_ALL_TESTS was called.
class InternalRunDeathTestFlag {
 public:
  InternalRunDeathTestFlag(const std::string& a_file,
                           int a_line,
                           int an_index,
                           int a_write_fd)
      : file_(a_file), line_(a_line), index_(an_index),
        write_fd_(a_write_fd) {}

  ~InternalRunDeathTestFlag() {
    if (write_fd_ >= 0)
      posix::Close(write_fd_);
  }

  const std::string& file() const { return file_; }
  int line() const { return line_; }
  int index() const { return index_; }
  int write_fd() const { return write_fd_; }

 private:
  std::string file_;
  int line_;
  int index_;
  int write_fd_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
};

// Returns a newly created InternalRunDeathTestFlag object with fields
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
// the flag is specified; otherwise returns NULL.
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();

#else  // GTEST_HAS_DEATH_TEST

// This macro is used for implementing macros such as
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
// death tests are not supported. Those macros must compile on such systems
// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
// systems that support death tests. This allows one to write such a macro
// on a system that does not support death tests and be sure that it will
// compile on a death-test supporting system.
//
// Parameters:
//   statement -  A statement that a macro such as EXPECT_DEATH would test
//                for program termination. This macro has to make sure this
//                statement is compiled but not executed, to ensure that
//                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
//                parameter iff EXPECT_DEATH compiles with it.
//   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
//                the output of statement.  This parameter has to be
//                compiled but not evaluated by this macro, to ensure that
//                this macro only accepts expressions that a macro such as
//                EXPECT_DEATH would accept.
//   terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
//                and a return statement for ASSERT_DEATH_IF_SUPPORTED.
//                This ensures that ASSERT_DEATH_IF_SUPPORTED will not
//                compile inside functions where ASSERT_DEATH doesn't
//                compile.
//
//  The branch that has an always false condition is used to ensure that
//  statement and regex are compiled (and thus syntactically correct) but
//  never executed. The unreachable code macro protects the terminator
//  statement from generating an 'unreachable code' warning in case
//  statement unconditionally returns or throws. The Message constructor at
//  the end allows the syntax of streaming additional messages into the
//  macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
    if (::testing::internal::AlwaysTrue()) { \
      GTEST_LOG_(WARNING) \
          << "Death tests are not supported on this platform.\n" \
          << "Statement '" #statement "' cannot be verified."; \
    } else if (::testing::internal::AlwaysFalse()) { \
      ::testing::internal::RE::PartialMatch(".*", (regex)); \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
      terminator; \
    } else \
      ::testing::Message()

#endif  // GTEST_HAS_DEATH_TEST

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_

namespace testing {

// This flag controls the style of death tests.  Valid values are "threadsafe",
// meaning that the death test child process will re-execute the test binary
// from the start, running only a single death test, or "fast",
// meaning that the child process will execute the test logic immediately
// after forking.
GTEST_DECLARE_string_(death_test_style);

#if GTEST_HAS_DEATH_TEST

namespace internal {

// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process.  Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests.  IMPORTANT: This is an internal utility.  Using it may break the
// implementation of death tests.  User code MUST NOT use it.
GTEST_API_ bool InDeathTestChild();

}  // namespace internal

// The following macros are useful for writing death tests.

// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
// executed:
//
//   1. It generates a warning if there is more than one active
//   thread.  This is because it's safe to fork() or clone() only
//   when there is a single thread.
//
//   2. The parent process clone()s a sub-process and runs the death
//   test in it; the sub-process exits with code 0 at the end of the
//   death test, if it hasn't exited already.
//
//   3. The parent process waits for the sub-process to terminate.
//
//   4. The parent process checks the exit code and error message of
//   the sub-process.
//
// Examples:
//
//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
//   for (int i = 0; i < 5; i++) {
//     EXPECT_DEATH(server.ProcessRequest(i),
//                  "Invalid request .* in ProcessRequest()")
//                  << "Failed to die on request " << i;
//   }
//
//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
//
//   bool KilledBySIGHUP(int exit_code) {
//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
//   }
//
//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
//
// On the regular expressions used in death tests:
//
//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
//   which uses the POSIX extended regex syntax.
//
//   On other platforms (e.g. Windows), we only support a simple regex
//   syntax implemented as part of Google Test.  This limited
//   implementation should be enough most of the time when writing
//   death tests; though it lacks many features you can find in PCRE
//   or POSIX extended regex syntax.  For example, we don't support
//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
//   repetition count ("x{5,7}"), among others.
//
//   Below is the syntax that we do support.  We chose it to be a
//   subset of both PCRE and POSIX extended regex, so it's easy to
//   learn wherever you come from.  In the following: 'A' denotes a
//   literal character, period (.), or a single \\ escape sequence;
//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
//   natural numbers.
//
//     c     matches any literal character c
//     \\d   matches any decimal digit
//     \\D   matches any character that's not a decimal digit
//     \\f   matches \f
//     \\n   matches \n
//     \\r   matches \r
//     \\s   matches any ASCII whitespace, including \n
//     \\S   matches any character that's not a whitespace
//     \\t   matches \t
//     \\v   matches \v
//     \\w   matches any letter, _, or decimal digit
//     \\W   matches any character that \\w doesn't match
//     \\c   matches any literal character c, which must be a punctuation
//     .     matches any single character except \n
//     A?    matches 0 or 1 occurrences of A
//     A*    matches 0 or many occurrences of A
//     A+    matches 1 or many occurrences of A
//     ^     matches the beginning of a string (not that of each line)
//     $     matches the end of a string (not that of each line)
//     xy    matches x followed by y
//
//   If you accidentally use PCRE or POSIX extended regex features
//   not implemented by us, you will get a run-time failure.  In that
//   case, please try to rewrite your regular expression within the
//   above syntax.
//
//   This implementation is *not* meant to be as highly tuned or robust
//   as a compiled regex library, but should perform well enough for a
//   death test, which already incurs significant overhead by launching
//   a child process.
//
// Known caveats:
//
//   A "threadsafe" style death test obtains the path to the test
//   program from argv[0] and re-executes it in the sub-process.  For
//   simplicity, the current implementation doesn't search the PATH
//   when launching the sub-process.  This means that the user must
//   invoke the test program via a path that contains at least one
//   path separator (e.g. path/to/foo_test and
//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
//   is rarely a problem as people usually don't put the test binary
//   directory in PATH.
//
// TODO(wan@google.com): make thread-safe death tests search the PATH.

// Asserts that a given statement causes the program to exit, with an
// integer exit status that satisfies predicate, and emitting error output
// that matches regex.
# define ASSERT_EXIT(statement, predicate, regex) \
    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)

// Like ASSERT_EXIT, but continues on to successive tests in the
// test case, if any:
# define EXPECT_EXIT(statement, predicate, regex) \
    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)

// Asserts that a given statement causes the program to exit, either by
// explicitly exiting with a nonzero exit code or being killed by a
// signal, and emitting error output that matches regex.
# define ASSERT_DEATH(statement, regex) \
    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)

// Like ASSERT_DEATH, but continues on to successive tests in the
// test case, if any:
# define EXPECT_DEATH(statement, regex) \
    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)

// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:

// Tests that an exit code describes a normal exit with a given exit code.
class GTEST_API_ ExitedWithCode {
 public:
  explicit ExitedWithCode(int exit_code);
  bool operator()(int exit_status) const;
 private:
  // No implementation - assignment is unsupported.
  void operator=(const ExitedWithCode& other);

  const int exit_code_;
};

# if !GTEST_OS_WINDOWS
// Tests that an exit code describes an exit due to termination by a
// given signal.
class GTEST_API_ KilledBySignal {
 public:
  explicit KilledBySignal(int signum);
  bool operator()(int exit_status) const;
 private:
  const int signum_;
};
# endif  // !GTEST_OS_WINDOWS

// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
// The death testing framework causes this to have interesting semantics,
// since the sideeffects of the call are only visible in opt mode, and not
// in debug mode.
//
// In practice, this can be used to test functions that utilize the
// LOG(DFATAL) macro using the following style:
//
// int DieInDebugOr12(int* sideeffect) {
//   if (sideeffect) {
//     *sideeffect = 12;
//   }
//   LOG(DFATAL) << "death";
//   return 12;
// }
//
// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
//   int sideeffect = 0;
//   // Only asserts in dbg.
//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
//
// #ifdef NDEBUG
//   // opt-mode has sideeffect visible.
//   EXPECT_EQ(12, sideeffect);
// #else
//   // dbg-mode no visible sideeffect.
//   EXPECT_EQ(0, sideeffect);
// #endif
// }
//
// This will assert that DieInDebugReturn12InOpt() crashes in debug
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
// appropriate fallback value (12 in this case) in opt mode. If you
// need to test that a function has appropriate side-effects in opt
// mode, include assertions against the side-effects.  A general
// pattern for this is:
//
// EXPECT_DEBUG_DEATH({
//   // Side-effects here will have an effect after this statement in
//   // opt mode, but none in debug mode.
//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
// }, "death");
//
# ifdef NDEBUG

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

# else

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  EXPECT_DEATH(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  ASSERT_DEATH(statement, regex)

# endif  // NDEBUG for EXPECT_DEBUG_DEATH
#endif  // GTEST_HAS_DEATH_TEST

// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
// death tests are supported; otherwise they just issue a warning.  This is
// useful when you are combining death test assertions with normal test
// assertions in one test.
#if GTEST_HAS_DEATH_TEST
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    EXPECT_DEATH(statement, regex)
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    ASSERT_DEATH(statement, regex)
#else
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
#endif

}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
// This file was GENERATED by command:
//     pump.py gtest-param-test.h.pump
// DO NOT EDIT BY HAND!!!

// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: vladl@google.com (Vlad Losev)
//
// Macros and functions for implementing parameterized tests
// in Google C++ Testing Framework (Google Test)
//
// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
//
#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_


// Value-parameterized tests allow you to test your code with different
// parameters without writing multiple copies of the same test.
//
// Here is how you use value-parameterized tests:

#if 0

// To write value-parameterized tests, first you should define a fixture
// class. It is usually derived from testing::TestWithParam<T> (see below for
// another inheritance scheme that's sometimes useful in more complicated
// class hierarchies), where the type of your parameter values.
// TestWithParam<T> is itself derived from testing::Test. T can be any
// copyable type. If it's a raw pointer, you are responsible for managing the
// lifespan of the pointed values.

class FooTest : public ::testing::TestWithParam<const char*> {
  // You can implement all the usual class fixture members here.
};

// Then, use the TEST_P macro to define as many parameterized tests
// for this fixture as you want. The _P suffix is for "parameterized"
// or "pattern", whichever you prefer to think.

TEST_P(FooTest, DoesBlah) {
  // Inside a test, access the test parameter with the GetParam() method
  // of the TestWithParam<T> class:
  EXPECT_TRUE(foo.Blah(GetParam()));
  ...
}

TEST_P(FooTest, HasBlahBlah) {
  ...
}

// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
// case with any set of parameters you want. Google Test defines a number
// of functions for generating test parameters. They return what we call
// (surprise!) parameter generators. Here is a  summary of them, which
// are all in the testing namespace:
//
//
//  Range(begin, end [, step]) - Yields values {begin, begin+step,
//                               begin+step+step, ...}. The values do not
//                               include end. step defaults to 1.
//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.
//  ValuesIn(container)        - Yields values from a C-style array, an STL
//  ValuesIn(begin,end)          container, or an iterator range [begin, end).
//  Bool()                     - Yields sequence {false, true}.
//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product
//                               for the math savvy) of the values generated
//                               by the N generators.
//
// For more details, see comments at the definitions of these functions below
// in this file.
//
// The following statement will instantiate tests from the FooTest test case
// each with parameter values "meeny", "miny", and "moe".

INSTANTIATE_TEST_CASE_P(InstantiationName,
                        FooTest,
                        Values("meeny", "miny", "moe"));

// To distinguish different instances of the pattern, (yes, you
// can instantiate it more then once) the first argument to the
// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
// actual test case name. Remember to pick unique prefixes for different
// instantiations. The tests from the instantiation above will have
// these names:
//
//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"
//    * InstantiationName/FooTest.DoesBlah/1 for "miny"
//    * InstantiationName/FooTest.DoesBlah/2 for "moe"
//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
//
// You can use these names in --gtest_filter.
//
// This statement will instantiate all tests from FooTest again, each
// with parameter values "cat" and "dog":

const char* pets[] = {"cat", "dog"};
INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));

// The tests from the instantiation above will have these names:
//
//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
//
// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
// in the given test case, whether their definitions come before or
// AFTER the INSTANTIATE_TEST_CASE_P statement.
//
// Please also note that generator expressions (including parameters to the
// generators) are evaluated in InitGoogleTest(), after main() has started.
// This allows the user on one hand, to adjust generator parameters in order
// to dynamically determine a set of tests to run and on the other hand,
// give the user a chance to inspect the generated tests with Google Test
// reflection API before RUN_ALL_TESTS() is executed.
//
// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
// for more examples.
//
// In the future, we plan to publish the API for defining new parameter
// generators. But for now this interface remains part of the internal
// implementation and is subject to change.
//
//
// A parameterized test fixture must be derived from testing::Test and from
// testing::WithParamInterface<T>, where T is the type of the parameter
// values. Inheriting from TestWithParam<T> satisfies that requirement because
// TestWithParam<T> inherits from both Test and WithParamInterface. In more
// complicated hierarchies, however, it is occasionally useful to inherit
// separately from Test and WithParamInterface. For example:

class BaseTest : public ::testing::Test {
  // You can inherit all the usual members for a non-parameterized test
  // fixture here.
};

class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
  // The usual test fixture members go here too.
};

TEST_F(BaseTest, HasFoo) {
  // This is an ordinary non-parameterized test.
}

TEST_P(DerivedTest, DoesBlah) {
  // GetParam works just the same here as if you inherit from TestWithParam.
  EXPECT_TRUE(foo.Blah(GetParam()));
}

#endif  // 0


#if !GTEST_OS_SYMBIAN
# include <utility>
#endif

// scripts/fuse_gtest.py depends on gtest's own header being #included
// *unconditionally*.  Therefore these #includes cannot be moved
// inside #if GTEST_HAS_PARAM_TEST.
// Copyright 2008 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: vladl@google.com (Vlad Losev)

// Type and function utilities for implementing parameterized tests.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_

#include <iterator>
#include <utility>
#include <vector>

// scripts/fuse_gtest.py depends on gtest's own header being #included
// *unconditionally*.  Therefore these #includes cannot be moved
// inside #if GTEST_HAS_PARAM_TEST.
// Copyright 2003 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Dan Egnor (egnor@google.com)
//
// A "smart" pointer type with reference tracking.  Every pointer to a
// particular object is kept on a circular linked list.  When the last pointer
// to an object is destroyed or reassigned, the object is deleted.
//
// Used properly, this deletes the object when the last reference goes away.
// There are several caveats:
// - Like all reference counting schemes, cycles lead to leaks.
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
// - Every time a pointer is assigned, the entire list of pointers to that
//   object is traversed.  This class is therefore NOT SUITABLE when there
//   will often be more than two or three pointers to a particular object.
// - References are only tracked as long as linked_ptr<> objects are copied.
//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
//   will happen (double deletion).
//
// A good use of this class is storing object references in STL containers.
// You can safely put linked_ptr<> in a vector<>.
// Other uses may not be as good.
//
// Note: If you use an incomplete type with linked_ptr<>, the class
// *containing* linked_ptr<> must have a constructor and destructor (even
// if they do nothing!).
//
// Bill Gibbons suggested we use something like this.
//
// Thread Safety:
//   Unlike other linked_ptr implementations, in this implementation
//   a linked_ptr object is thread-safe in the sense that:
//     - it's safe to copy linked_ptr objects concurrently,
//     - it's safe to copy *from* a linked_ptr and read its underlying
//       raw pointer (e.g. via get()) concurrently, and
//     - it's safe to write to two linked_ptrs that point to the same
//       shared object concurrently.
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
// confusion with normal linked_ptr.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

#include <stdlib.h>
#include <assert.h>


namespace testing {
namespace internal {

// Protects copying of all linked_ptr objects.
GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);

// This is used internally by all instances of linked_ptr<>.  It needs to be
// a non-template class because different types of linked_ptr<> can refer to
// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
// So, it needs to be possible for different types of linked_ptr to participate
// in the same circular linked list, so we need a single class type here.
//
// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
class linked_ptr_internal {
 public:
  // Create a new circle that includes only this instance.
  void join_new() {
    next_ = this;
  }

  // Many linked_ptr operations may change p.link_ for some linked_ptr
  // variable p in the same circle as this object.  Therefore we need
  // to prevent two such operations from occurring concurrently.
  //
  // Note that different types of linked_ptr objects can coexist in a
  // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
  // linked_ptr<Derived2>).  Therefore we must use a single mutex to
  // protect all linked_ptr objects.  This can create serious
  // contention in production code, but is acceptable in a testing
  // framework.

  // Join an existing circle.
  void join(linked_ptr_internal const* ptr)
      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
    MutexLock lock(&g_linked_ptr_mutex);

    linked_ptr_internal const* p = ptr;
    while (p->next_ != ptr) p = p->next_;
    p->next_ = this;
    next_ = ptr;
  }

  // Leave whatever circle we're part of.  Returns true if we were the
  // last member of the circle.  Once this is done, you can join() another.
  bool depart()
      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
    MutexLock lock(&g_linked_ptr_mutex);

    if (next_ == this) return true;
    linked_ptr_internal const* p = next_;
    while (p->next_ != this) p = p->next_;
    p->next_ = next_;
    return false;
  }

 private:
  mutable linked_ptr_internal const* next_;
};

template <typename T>
class linked_ptr {
 public:
  typedef T element_type;

  // Take over ownership of a raw pointer.  This should happen as soon as
  // possible after the object is created.
  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
  ~linked_ptr() { depart(); }

  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
  linked_ptr(linked_ptr const& ptr) {  // NOLINT
    assert(&ptr != this);
    copy(&ptr);
  }

  // Assignment releases the old value and acquires the new.
  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
    depart();
    copy(&ptr);
    return *this;
  }

  linked_ptr& operator=(linked_ptr const& ptr) {
    if (&ptr != this) {
      depart();
      copy(&ptr);
    }
    return *this;
  }

  // Smart pointer members.
  void reset(T* ptr = NULL) {
    depart();
    capture(ptr);
  }
  T* get() const { return value_; }
  T* operator->() const { return value_; }
  T& operator*() const { return *value_; }

  bool operator==(T* p) const { return value_ == p; }
  bool operator!=(T* p) const { return value_ != p; }
  template <typename U>
  bool operator==(linked_ptr<U> const& ptr) const {
    return value_ == ptr.get();
  }
  template <typename U>
  bool operator!=(linked_ptr<U> const& ptr) const {
    return value_ != ptr.get();
  }

 private:
  template <typename U>
  friend class linked_ptr;

  T* value_;
  linked_ptr_internal link_;

  void depart() {
    if (link_.depart()) delete value_;
  }

  void capture(T* ptr) {
    value_ = ptr;
    link_.join_new();
  }

  template <typename U> void copy(linked_ptr<U> const* ptr) {
    value_ = ptr->get();
    if (value_)
      link_.join(&ptr->link_);
    else
      link_.join_new();
  }
};

template<typename T> inline
bool operator==(T* ptr, const linked_ptr<T>& x) {
  return ptr == x.get();
}

template<typename T> inline
bool operator!=(T* ptr, const linked_ptr<T>& x) {
  return ptr != x.get();
}

// A function to convert T* into linked_ptr<T>
// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
template <typename T>
linked_ptr<T> make_linked_ptr(T* ptr) {
  return linked_ptr<T>(ptr);
}

}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
// Copyright 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)

// Google Test - The Google C++ Testing Framework
//
// This file implements a universal value printer that can print a
// value of any type T:
//
//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
//
// A user can teach this function how to print a class type T by
// defining either operator<<() or PrintTo() in the namespace that
// defines T.  More specifically, the FIRST defined function in the
// following list will be used (assuming T is defined in namespace
// foo):
//
//   1. foo::PrintTo(const T&, ostream*)
//   2. operator<<(ostream&, const T&) defined in either foo or the
//      global namespace.
//
// If none of the above is defined, it will print the debug string of
// the value if it is a protocol buffer, or print the raw bytes in the
// value otherwise.
//
// To aid debugging: when T is a reference type, the address of the
// value is also printed; when T is a (const) char pointer, both the
// pointer value and the NUL-terminated string it points to are
// printed.
//
// We also provide some convenient wrappers:
//
//   // Prints a value to a string.  For a (const or not) char
//   // pointer, the NUL-terminated string (but not the pointer) is
//   // printed.
//   std::string ::testing::PrintToString(const T& value);
//
//   // Prints a value tersely: for a reference type, the referenced
//   // value (but not the address) is printed; for a (const or not) char
//   // pointer, the NUL-terminated string (but not the pointer) is
//   // printed.
//   void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
//
//   // Prints value using the type inferred by the compiler.  The difference
//   // from UniversalTersePrint() is that this function prints both the
//   // pointer and the NUL-terminated string for a (const or not) char pointer.
//   void ::testing::internal::UniversalPrint(const T& value, ostream*);
//
//   // Prints the fields of a tuple tersely to a string vector, one
//   // element for each field. Tuple support must be enabled in
//   // gtest-port.h.
//   std::vector<string> UniversalTersePrintTupleFieldsToStrings(
//       const Tuple& value);
//
// Known limitation:
//
// The print primitives print the elements of an STL-style container
// using the compiler-inferred type of *iter where iter is a
// const_iterator of the container.  When const_iterator is an input
// iterator but not a forward iterator, this inferred type may not
// match value_type, and the print output may be incorrect.  In
// practice, this is rarely a problem as for most containers
// const_iterator is a forward iterator.  We'll fix this if there's an
// actual need for it.  Note that this fix cannot rely on value_type
// being defined as many user-defined container types don't have
// value_type.

#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_

#include <ostream>  // NOLINT
#include <sstream>
#include <string>
#include <utility>
#include <vector>

namespace testing {

// Definitions in the 'internal' and 'internal2' name spaces are
// subject to change without notice.  DO NOT USE THEM IN USER CODE!
namespace internal2 {

// Prints the given number of bytes in the given object to the given
// ostream.
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
                                     size_t count,
                                     ::std::ostream* os);

// For selecting which printer to use when a given type has neither <<
// nor PrintTo().
enum TypeKind {
  kProtobuf,              // a protobuf type
  kConvertibleToInteger,  // a type implicitly convertible to BiggestInt
                          // (e.g. a named or unnamed enum type)
  kOtherType              // anything else
};

// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
// by the universal printer to print a value of type T when neither
// operator<< nor PrintTo() is defined for T, where kTypeKind is the
// "kind" of T as defined by enum TypeKind.
template <typename T, TypeKind kTypeKind>
class TypeWithoutFormatter {
 public:
  // This default version is called when kTypeKind is kOtherType.
  static void PrintValue(const T& value, ::std::ostream* os) {
    PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
                         sizeof(value), os);
  }
};

// We print a protobuf using its ShortDebugString() when the string
// doesn't exceed this many characters; otherwise we print it using
// DebugString() for better readability.
const size_t kProtobufOneLinerMaxLength = 50;

template <typename T>
class TypeWithoutFormatter<T, kProtobuf> {
 public:
  static void PrintValue(const T& value, ::std::ostream* os) {
    const ::testing::internal::string short_str = value.ShortDebugString();
    const ::testing::internal::string pretty_str =
        short_str.length() <= kProtobufOneLinerMaxLength ?
        short_str : ("\n" + value.DebugString());
    *os << ("<" + pretty_str + ">");
  }
};

template <typename T>
class TypeWithoutFormatter<T, kConvertibleToInteger> {
 public:
  // Since T has no << operator or PrintTo() but can be implicitly
  // converted to BiggestInt, we print it as a BiggestInt.
  //
  // Most likely T is an enum type (either named or unnamed), in which
  // case printing it as an integer is the desired behavior.  In case
  // T is not an enum, printing it as an integer is the best we can do
  // given that it has no user-defined printer.
  static void PrintValue(const T& value, ::std::ostream* os) {
    const internal::BiggestInt kBigInt = value;
    *os << kBigInt;
  }
};

// Prints the given value to the given ostream.  If the value is a
// protocol message, its debug string is printed; if it's an enum or
// of a type implicitly convertible to BiggestInt, it's printed as an
// integer; otherwise the bytes in the value are printed.  This is
// what UniversalPrinter<T>::Print() does when it knows nothing about
// type T and T has neither << operator nor PrintTo().
//
// A user can override this behavior for a class type Foo by defining
// a << operator in the namespace where Foo is defined.
//
// We put this operator in namespace 'internal2' instead of 'internal'
// to simplify the implementation, as much code in 'internal' needs to
// use << in STL, which would conflict with our own << were it defined
// in 'internal'.
//
// Note that this operator<< takes a generic std::basic_ostream<Char,
// CharTraits> type instead of the more restricted std::ostream.  If
// we define it to take an std::ostream instead, we'll get an
// "ambiguous overloads" compiler error when trying to print a type
// Foo that supports streaming to std::basic_ostream<Char,
// CharTraits>, as the compiler cannot tell whether
// operator<<(std::ostream&, const T&) or
// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
// specific.
template <typename Char, typename CharTraits, typename T>
::std::basic_ostream<Char, CharTraits>& operator<<(
    ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
  TypeWithoutFormatter<T,
      (internal::IsAProtocolMessage<T>::value ? kProtobuf :
       internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
       kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
  return os;
}

}  // namespace internal2
}  // namespace testing

// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
// magic needed for implementing UniversalPrinter won't work.
namespace testing_internal {

// Used to print a value that is not an STL-style container when the
// user doesn't define PrintTo() for it.
template <typename T>
void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
  // With the following statement, during unqualified name lookup,
  // testing::internal2::operator<< appears as if it was declared in
  // the nearest enclosing namespace that contains both
  // ::testing_internal and ::testing::internal2, i.e. the global
  // namespace.  For more details, refer to the C++ Standard section
  // 7.3.4-1 [namespace.udir].  This allows us to fall back onto
  // testing::internal2::operator<< in case T doesn't come with a <<
  // operator.
  //
  // We cannot write 'using ::testing::internal2::operator<<;', which
  // gcc 3.3 fails to compile due to a compiler bug.
  using namespace ::testing::internal2;  // NOLINT

  // Assuming T is defined in namespace foo, in the next statement,
  // the compiler will consider all of:
  //
  //   1. foo::operator<< (thanks to Koenig look-up),
  //   2. ::operator<< (as the current namespace is enclosed in ::),
  //   3. testing::internal2::operator<< (thanks to the using statement above).
  //
  // The operator<< whose type matches T best will be picked.
  //
  // We deliberately allow #2 to be a candidate, as sometimes it's
  // impossible to define #1 (e.g. when foo is ::std, defining
  // anything in it is undefined behavior unless you are a compiler
  // vendor.).
  *os << value;
}

}  // namespace testing_internal

namespace testing {
namespace internal {

// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
// value to the given ostream.  The caller must ensure that
// 'ostream_ptr' is not NULL, or the behavior is undefined.
//
// We define UniversalPrinter as a class template (as opposed to a
// function template), as we need to partially specialize it for
// reference types, which cannot be done with function templates.
template <typename T>
class UniversalPrinter;

template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os);

// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,
                    false_type /* is not a pointer */,
                    const C& container, ::std::ostream* os) {
  const size_t kMaxCount = 32;  // The maximum number of elements to print.
  *os << '{';
  size_t count = 0;
  for (typename C::const_iterator it = container.begin();
       it != container.end(); ++it, ++count) {
    if (count > 0) {
      *os << ',';
      if (count == kMaxCount) {  // Enough has been printed.
        *os << " ...";
        break;
      }
    }
    *os << ' ';
    // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
    // handle *it being a native array.
    internal::UniversalPrint(*it, os);
  }

  if (count > 0) {
    *os << ' ';
  }
  *os << '}';
}

// Used to print a pointer that is neither a char pointer nor a member
// pointer, when the user doesn't define PrintTo() for it.  (A member
// variable pointer or member function pointer doesn't really point to
// a location in the address space.  Their representation is
// implementation-defined.  Therefore they will be printed as raw
// bytes.)
template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,
                    true_type /* is a pointer */,
                    T* p, ::std::ostream* os) {
  if (p == NULL) {
    *os << "NULL";
  } else {
    // C++ doesn't allow casting from a function pointer to any object
    // pointer.
    //
    // IsTrue() silences warnings: "Condition is always true",
    // "unreachable code".
    if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
      // T is not a function type.  We just call << to print p,
      // relying on ADL to pick up user-defined << for their pointer
      // types, if any.
      *os << p;
    } else {
      // T is a function type, so '*os << p' doesn't do what we want
      // (it just prints p as bool).  We want to print p as a const
      // void*.  However, we cannot cast it to const void* directly,
      // even using reinterpret_cast, as earlier versions of gcc
      // (e.g. 3.4.5) cannot compile the cast when p is a function
      // pointer.  Casting to UInt64 first solves the problem.
      *os << reinterpret_cast<const void*>(
          reinterpret_cast<internal::UInt64>(p));
    }
  }
}

// Used to print a non-container, non-pointer value when the user
// doesn't define PrintTo() for it.
template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,
                    false_type /* is not a pointer */,
                    const T& value, ::std::ostream* os) {
  ::testing_internal::DefaultPrintNonContainerTo(value, os);
}

// Prints the given value using the << operator if it has one;
// otherwise prints the bytes in it.  This is what
// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
// or overloaded for type T.
//
// A user can override this behavior for a class type Foo by defining
// an overload of PrintTo() in the namespace where Foo is defined.  We
// give the user this option as sometimes defining a << operator for
// Foo is not desirable (e.g. the coding style may prevent doing it,
// or there is already a << operator but it doesn't do what the user
// wants).
template <typename T>
void PrintTo(const T& value, ::std::ostream* os) {
  // DefaultPrintTo() is overloaded.  The type of its first two
  // arguments determine which version will be picked.  If T is an
  // STL-style container, the version for container will be called; if
  // T is a pointer, the pointer version will be called; otherwise the
  // generic version will be called.
  //
  // Note that we check for container types here, prior to we check
  // for protocol message types in our operator<<.  The rationale is:
  //
  // For protocol messages, we want to give people a chance to
  // override Google Mock's format by defining a PrintTo() or
  // operator<<.  For STL containers, other formats can be
  // incompatible with Google Mock's format for the container
  // elements; therefore we check for container types here to ensure
  // that our format is used.
  //
  // The second argument of DefaultPrintTo() is needed to bypass a bug
  // in Symbian's C++ compiler that prevents it from picking the right
  // overload between:
  //
  //   PrintTo(const T& x, ...);
  //   PrintTo(T* x, ...);
  DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
}

// The following list of PrintTo() overloads tells
// UniversalPrinter<T>::Print() how to print standard types (built-in
// types, strings, plain arrays, and pointers).

// Overloads for various char types.
GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
inline void PrintTo(char c, ::std::ostream* os) {
  // When printing a plain char, we always treat it as unsigned.  This
  // way, the output won't be affected by whether the compiler thinks
  // char is signed or not.
  PrintTo(static_cast<unsigned char>(c), os);
}

// Overloads for other simple built-in types.
inline void PrintTo(bool x, ::std::ostream* os) {
  *os << (x ? "true" : "false");
}

// Overload for wchar_t type.
// Prints a wchar_t as a symbol if it is printable or as its internal
// code otherwise and also as its decimal code (except for L'\0').
// The L'\0' char is printed as "L'\\0'". The decimal code is printed
// as signed integer when wchar_t is implemented by the compiler
// as a signed type and is printed as an unsigned integer when wchar_t
// is implemented as an unsigned type.
GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);

// Overloads for C strings.
GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
inline void PrintTo(char* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const char*>(s), os);
}

// signed/unsigned char is often used for representing binary data, so
// we print pointers to it as void* to be safe.
inline void PrintTo(const signed char* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const void*>(s), os);
}
inline void PrintTo(signed char* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const void*>(s), os);
}
inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const void*>(s), os);
}
inline void PrintTo(unsigned char* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const void*>(s), os);
}

// MSVC can be configured to define wchar_t as a typedef of unsigned
// short.  It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
// type.  When wchar_t is a typedef, defining an overload for const
// wchar_t* would cause unsigned short* be printed as a wide string,
// possibly causing invalid memory accesses.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Overloads for wide C strings
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
inline void PrintTo(wchar_t* s, ::std::ostream* os) {
  PrintTo(ImplicitCast_<const wchar_t*>(s), os);
}
#endif

// Overload for C arrays.  Multi-dimensional arrays are printed
// properly.

// Prints the given number of elements in an array, without printing
// the curly braces.
template <typename T>
void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
  UniversalPrint(a[0], os);
  for (size_t i = 1; i != count; i++) {
    *os << ", ";
    UniversalPrint(a[i], os);
  }
}

// Overloads for ::string and ::std::string.
#if GTEST_HAS_GLOBAL_STRING
GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
inline void PrintTo(const ::string& s, ::std::ostream* os) {
  PrintStringTo(s, os);
}
#endif  // GTEST_HAS_GLOBAL_STRING

GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
  PrintStringTo(s, os);
}

// Overloads for ::wstring and ::std::wstring.
#if GTEST_HAS_GLOBAL_WSTRING
GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
  PrintWideStringTo(s, os);
}
#endif  // GTEST_HAS_GLOBAL_WSTRING

#if GTEST_HAS_STD_WSTRING
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
  PrintWideStringTo(s, os);
}
#endif  // GTEST_HAS_STD_WSTRING

#if GTEST_HAS_TR1_TUPLE
// Overload for ::std::tr1::tuple.  Needed for printing function arguments,
// which are packed as tuples.

// Helper function for printing a tuple.  T must be instantiated with
// a tuple type.
template <typename T>
void PrintTupleTo(const T& t, ::std::ostream* os);

// Overloaded PrintTo() for tuples of various arities.  We support
// tuples of up-to 10 fields.  The following implementation works
// regardless of whether tr1::tuple is implemented using the
// non-standard variadic template feature or not.

inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1>
void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2>
void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
             ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
             ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
             ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7, typename T8>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
             ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7, typename T8, typename T9>
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
             ::std::ostream* os) {
  PrintTupleTo(t, os);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7, typename T8, typename T9, typename T10>
void PrintTo(
    const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
    ::std::ostream* os) {
  PrintTupleTo(t, os);
}
#endif  // GTEST_HAS_TR1_TUPLE

// Overload for std::pair.
template <typename T1, typename T2>
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
  *os << '(';
  // We cannot use UniversalPrint(value.first, os) here, as T1 may be
  // a reference type.  The same for printing value.second.
  UniversalPrinter<T1>::Print(value.first, os);
  *os << ", ";
  UniversalPrinter<T2>::Print(value.second, os);
  *os << ')';
}

// Implements printing a non-reference type T by letting the compiler
// pick the right overload of PrintTo() for T.
template <typename T>
class UniversalPrinter {
 public:
  // MSVC warns about adding const to a function type, so we want to
  // disable the warning.
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4180)  // Temporarily disables warning 4180.
#endif  // _MSC_VER

  // Note: we deliberately don't call this PrintTo(), as that name
  // conflicts with ::testing::internal::PrintTo in the body of the
  // function.
  static void Print(const T& value, ::std::ostream* os) {
    // By default, ::testing::internal::PrintTo() is used for printing
    // the value.
    //
    // Thanks to Koenig look-up, if T is a class and has its own
    // PrintTo() function defined in its namespace, that function will
    // be visible here.  Since it is more specific than the generic ones
    // in ::testing::internal, it will be picked by the compiler in the
    // following statement - exactly what we want.
    PrintTo(value, os);
  }

#ifdef _MSC_VER
# pragma warning(pop)           // Restores the warning state.
#endif  // _MSC_VER
};

// UniversalPrintArray(begin, len, os) prints an array of 'len'
// elements, starting at address 'begin'.
template <typename T>
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
  if (len == 0) {
    *os << "{}";
  } else {
    *os << "{ ";
    const size_t kThreshold = 18;
    const size_t kChunkSize = 8;
    // If the array has more than kThreshold elements, we'll have to
    // omit some details by printing only the first and the last
    // kChunkSize elements.
    // TODO(wan@google.com): let the user control the threshold using a flag.
    if (len <= kThreshold) {
      PrintRawArrayTo(begin, len, os);
    } else {
      PrintRawArrayTo(begin, kChunkSize, os);
      *os << ", ..., ";
      PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
    }
    *os << " }";
  }
}
// This overload prints a (const) char array compactly.
GTEST_API_ void UniversalPrintArray(
    const char* begin, size_t len, ::std::ostream* os);

// This overload prints a (const) wchar_t array compactly.
GTEST_API_ void UniversalPrintArray(
    const wchar_t* begin, size_t len, ::std::ostream* os);

// Implements printing an array type T[N].
template <typename T, size_t N>
class UniversalPrinter<T[N]> {
 public:
  // Prints the given array, omitting some elements when there are too
  // many.
  static void Print(const T (&a)[N], ::std::ostream* os) {
    UniversalPrintArray(a, N, os);
  }
};

// Implements printing a reference type T&.
template <typename T>
class UniversalPrinter<T&> {
 public:
  // MSVC warns about adding const to a function type, so we want to
  // disable the warning.
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4180)  // Temporarily disables warning 4180.
#endif  // _MSC_VER

  static void Print(const T& value, ::std::ostream* os) {
    // Prints the address of the value.  We use reinterpret_cast here
    // as static_cast doesn't compile when T is a function type.
    *os << "@" << reinterpret_cast<const void*>(&value) << " ";

    // Then prints the value itself.
    UniversalPrint(value, os);
  }

#ifdef _MSC_VER
# pragma warning(pop)           // Restores the warning state.
#endif  // _MSC_VER
};

// Prints a value tersely: for a reference type, the referenced value
// (but not the address) is printed; for a (const) char pointer, the
// NUL-terminated string (but not the pointer) is printed.

template <typename T>
class UniversalTersePrinter {
 public:
  static void Print(const T& value, ::std::ostream* os) {
    UniversalPrint(value, os);
  }
};
template <typename T>
class UniversalTersePrinter<T&> {
 public:
  static void Print(const T& value, ::std::ostream* os) {
    UniversalPrint(value, os);
  }
};
template <typename T, size_t N>
class UniversalTersePrinter<T[N]> {
 public:
  static void Print(const T (&value)[N], ::std::ostream* os) {
    UniversalPrinter<T[N]>::Print(value, os);
  }
};
template <>
class UniversalTersePrinter<const char*> {
 public:
  static void Print(const char* str, ::std::ostream* os) {
    if (str == NULL) {
      *os << "NULL";
    } else {
      UniversalPrint(string(str), os);
    }
  }
};
template <>
class UniversalTersePrinter<char*> {
 public:
  static void Print(char* str, ::std::ostream* os) {
    UniversalTersePrinter<const char*>::Print(str, os);
  }
};

#if GTEST_HAS_STD_WSTRING
template <>
class UniversalTersePrinter<const wchar_t*> {
 public:
  static void Print(const wchar_t* str, ::std::ostream* os) {
    if (str == NULL) {
      *os << "NULL";
    } else {
      UniversalPrint(::std::wstring(str), os);
    }
  }
};
#endif

template <>
class UniversalTersePrinter<wchar_t*> {
 public:
  static void Print(wchar_t* str, ::std::ostream* os) {
    UniversalTersePrinter<const wchar_t*>::Print(str, os);
  }
};

template <typename T>
void UniversalTersePrint(const T& value, ::std::ostream* os) {
  UniversalTersePrinter<T>::Print(value, os);
}

// Prints a value using the type inferred by the compiler.  The
// difference between this and UniversalTersePrint() is that for a
// (const) char pointer, this prints both the pointer and the
// NUL-terminated string.
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os) {
  // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
  // UniversalPrinter with T directly.
  typedef T T1;
  UniversalPrinter<T1>::Print(value, os);
}

#if GTEST_HAS_TR1_TUPLE
typedef ::std::vector<string> Strings;

// This helper template allows PrintTo() for tuples and
// UniversalTersePrintTupleFieldsToStrings() to be defined by
// induction on the number of tuple fields.  The idea is that
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
// fields in tuple t, and can be defined in terms of
// TuplePrefixPrinter<N - 1>.

// The inductive case.
template <size_t N>
struct TuplePrefixPrinter {
  // Prints the first N fields of a tuple.
  template <typename Tuple>
  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
    TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
    *os << ", ";
    UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
        ::Print(::std::tr1::get<N - 1>(t), os);
  }

  // Tersely prints the first N fields of a tuple to a string vector,
  // one element for each field.
  template <typename Tuple>
  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
    TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
    ::std::stringstream ss;
    UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
    strings->push_back(ss.str());
  }
};

// Base cases.
template <>
struct TuplePrefixPrinter<0> {
  template <typename Tuple>
  static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}

  template <typename Tuple>
  static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
};
// We have to specialize the entire TuplePrefixPrinter<> class
// template here, even though the definition of
// TersePrintPrefixToStrings() is the same as the generic version, as
// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
// support specializing a method template of a class template.
template <>
struct TuplePrefixPrinter<1> {
  template <typename Tuple>
  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
    UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
        Print(::std::tr1::get<0>(t), os);
  }

  template <typename Tuple>
  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
    ::std::stringstream ss;
    UniversalTersePrint(::std::tr1::get<0>(t), &ss);
    strings->push_back(ss.str());
  }
};

// Helper function for printing a tuple.  T must be instantiated with
// a tuple type.
template <typename T>
void PrintTupleTo(const T& t, ::std::ostream* os) {
  *os << "(";
  TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
      PrintPrefixTo(t, os);
  *os << ")";
}

// Prints the fields of a tuple tersely to a string vector, one
// element for each field.  See the comment before
// UniversalTersePrint() for how we define "tersely".
template <typename Tuple>
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
  Strings result;
  TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
      TersePrintPrefixToStrings(value, &result);
  return result;
}
#endif  // GTEST_HAS_TR1_TUPLE

}  // namespace internal

template <typename T>
::std::string PrintToString(const T& value) {
  ::std::stringstream ss;
  internal::UniversalTersePrinter<T>::Print(value, &ss);
  return ss.str();
}

}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_

#if GTEST_HAS_PARAM_TEST

namespace testing {
namespace internal {

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Outputs a message explaining invalid registration of different
// fixture class for the same test case. This may happen when
// TEST_P macro is used to define two tests with the same name
// but in different namespaces.
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
                                          const char* file, int line);

template <typename> class ParamGeneratorInterface;
template <typename> class ParamGenerator;

// Interface for iterating over elements provided by an implementation
// of ParamGeneratorInterface<T>.
template <typename T>
class ParamIteratorInterface {
 public:
  virtual ~ParamIteratorInterface() {}
  // A pointer to the base generator instance.
  // Used only for the purposes of iterator comparison
  // to make sure that two iterators belong to the same generator.
  virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
  // Advances iterator to point to the next element
  // provided by the generator. The caller is responsible
  // for not calling Advance() on an iterator equal to
  // BaseGenerator()->End().
  virtual void Advance() = 0;
  // Clones the iterator object. Used for implementing copy semantics
  // of ParamIterator<T>.
  virtual ParamIteratorInterface* Clone() const = 0;
  // Dereferences the current iterator and provides (read-only) access
  // to the pointed value. It is the caller's responsibility not to call
  // Current() on an iterator equal to BaseGenerator()->End().
  // Used for implementing ParamGenerator<T>::operator*().
  virtual const T* Current() const = 0;
  // Determines whether the given iterator and other point to the same
  // element in the sequence generated by the generator.
  // Used for implementing ParamGenerator<T>::operator==().
  virtual bool Equals(const ParamIteratorInterface& other) const = 0;
};

// Class iterating over elements provided by an implementation of
// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
// and implements the const forward iterator concept.
template <typename T>
class ParamIterator {
 public:
  typedef T value_type;
  typedef const T& reference;
  typedef ptrdiff_t difference_type;

  // ParamIterator assumes ownership of the impl_ pointer.
  ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
  ParamIterator& operator=(const ParamIterator& other) {
    if (this != &other)
      impl_.reset(other.impl_->Clone());
    return *this;
  }

  const T& operator*() const { return *impl_->Current(); }
  const T* operator->() const { return impl_->Current(); }
  // Prefix version of operator++.
  ParamIterator& operator++() {
    impl_->Advance();
    return *this;
  }
  // Postfix version of operator++.
  ParamIterator operator++(int /*unused*/) {
    ParamIteratorInterface<T>* clone = impl_->Clone();
    impl_->Advance();
    return ParamIterator(clone);
  }
  bool operator==(const ParamIterator& other) const {
    return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
  }
  bool operator!=(const ParamIterator& other) const {
    return !(*this == other);
  }

 private:
  friend class ParamGenerator<T>;
  explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
  scoped_ptr<ParamIteratorInterface<T> > impl_;
};

// ParamGeneratorInterface<T> is the binary interface to access generators
// defined in other translation units.
template <typename T>
class ParamGeneratorInterface {
 public:
  typedef T ParamType;

  virtual ~ParamGeneratorInterface() {}

  // Generator interface definition
  virtual ParamIteratorInterface<T>* Begin() const = 0;
  virtual ParamIteratorInterface<T>* End() const = 0;
};

// Wraps ParamGeneratorInterface<T> and provides general generator syntax
// compatible with the STL Container concept.
// This class implements copy initialization semantics and the contained
// ParamGeneratorInterface<T> instance is shared among all copies
// of the original object. This is possible because that instance is immutable.
template<typename T>
class ParamGenerator {
 public:
  typedef ParamIterator<T> iterator;

  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}

  ParamGenerator& operator=(const ParamGenerator& other) {
    impl_ = other.impl_;
    return *this;
  }

  iterator begin() const { return iterator(impl_->Begin()); }
  iterator end() const { return iterator(impl_->End()); }

 private:
  linked_ptr<const ParamGeneratorInterface<T> > impl_;
};

// Generates values from a range of two comparable values. Can be used to
// generate sequences of user-defined types that implement operator+() and
// operator<().
// This class is used in the Range() function.
template <typename T, typename IncrementT>
class RangeGenerator : public ParamGeneratorInterface<T> {
 public:
  RangeGenerator(T begin, T end, IncrementT step)
      : begin_(begin), end_(end),
        step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
  virtual ~RangeGenerator() {}

  virtual ParamIteratorInterface<T>* Begin() const {
    return new Iterator(this, begin_, 0, step_);
  }
  virtual ParamIteratorInterface<T>* End() const {
    return new Iterator(this, end_, end_index_, step_);
  }

 private:
  class Iterator : public ParamIteratorInterface<T> {
   public:
    Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
             IncrementT step)
        : base_(base), value_(value), index_(index), step_(step) {}
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
      return base_;
    }
    virtual void Advance() {
      value_ = value_ + step_;
      index_++;
    }
    virtual ParamIteratorInterface<T>* Clone() const {
      return new Iterator(*this);
    }
    virtual const T* Current() const { return &value_; }
    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const int other_index =
          CheckedDowncastToActualType<const Iterator>(&other)->index_;
      return index_ == other_index;
    }

   private:
    Iterator(const Iterator& other)
        : ParamIteratorInterface<T>(),
          base_(other.base_), value_(other.value_), index_(other.index_),
          step_(other.step_) {}

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<T>* const base_;
    T value_;
    int index_;
    const IncrementT step_;
  };  // class RangeGenerator::Iterator

  static int CalculateEndIndex(const T& begin,
                               const T& end,
                               const IncrementT& step) {
    int end_index = 0;
    for (T i = begin; i < end; i = i + step)
      end_index++;
    return end_index;
  }

  // No implementation - assignment is unsupported.
  void operator=(const RangeGenerator& other);

  const T begin_;
  const T end_;
  const IncrementT step_;
  // The index for the end() iterator. All the elements in the generated
  // sequence are indexed (0-based) to aid iterator comparison.
  const int end_index_;
};  // class RangeGenerator


// Generates values from a pair of STL-style iterators. Used in the
// ValuesIn() function. The elements are copied from the source range
// since the source can be located on the stack, and the generator
// is likely to persist beyond that stack frame.
template <typename T>
class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
 public:
  template <typename ForwardIterator>
  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
      : container_(begin, end) {}
  virtual ~ValuesInIteratorRangeGenerator() {}

  virtual ParamIteratorInterface<T>* Begin() const {
    return new Iterator(this, container_.begin());
  }
  virtual ParamIteratorInterface<T>* End() const {
    return new Iterator(this, container_.end());
  }

 private:
  typedef typename ::std::vector<T> ContainerType;

  class Iterator : public ParamIteratorInterface<T> {
   public:
    Iterator(const ParamGeneratorInterface<T>* base,
             typename ContainerType::const_iterator iterator)
        : base_(base), iterator_(iterator) {}
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
      return base_;
    }
    virtual void Advance() {
      ++iterator_;
      value_.reset();
    }
    virtual ParamIteratorInterface<T>* Clone() const {
      return new Iterator(*this);
    }
    // We need to use cached value referenced by iterator_ because *iterator_
    // can return a temporary object (and of type other then T), so just
    // having "return &*iterator_;" doesn't work.
    // value_ is updated here and not in Advance() because Advance()
    // can advance iterator_ beyond the end of the range, and we cannot
    // detect that fact. The client code, on the other hand, is
    // responsible for not calling Current() on an out-of-range iterator.
    virtual const T* Current() const {
      if (value_.get() == NULL)
        value_.reset(new T(*iterator_));
      return value_.get();
    }
    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      return iterator_ ==
          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
    }

   private:
    Iterator(const Iterator& other)
          // The explicit constructor call suppresses a false warning
          // emitted by gcc when supplied with the -Wextra option.
        : ParamIteratorInterface<T>(),
          base_(other.base_),
          iterator_(other.iterator_) {}

    const ParamGeneratorInterface<T>* const base_;
    typename ContainerType::const_iterator iterator_;
    // A cached value of *iterator_. We keep it here to allow access by
    // pointer in the wrapping iterator's operator->().
    // value_ needs to be mutable to be accessed in Current().
    // Use of scoped_ptr helps manage cached value's lifetime,
    // which is bound by the lifespan of the iterator itself.
    mutable scoped_ptr<const T> value_;
  };  // class ValuesInIteratorRangeGenerator::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const ValuesInIteratorRangeGenerator& other);

  const ContainerType container_;
};  // class ValuesInIteratorRangeGenerator

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Stores a parameter value and later creates tests parameterized with that
// value.
template <class TestClass>
class ParameterizedTestFactory : public TestFactoryBase {
 public:
  typedef typename TestClass::ParamType ParamType;
  explicit ParameterizedTestFactory(ParamType parameter) :
      parameter_(parameter) {}
  virtual Test* CreateTest() {
    TestClass::SetParam(&parameter_);
    return new TestClass();
  }

 private:
  const ParamType parameter_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
};

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// TestMetaFactoryBase is a base class for meta-factories that create
// test factories for passing into MakeAndRegisterTestInfo function.
template <class ParamType>
class TestMetaFactoryBase {
 public:
  virtual ~TestMetaFactoryBase() {}

  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
};

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// TestMetaFactory creates test factories for passing into
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
// ownership of test factory pointer, same factory object cannot be passed
// into that method twice. But ParameterizedTestCaseInfo is going to call
// it for each Test/Parameter value combination. Thus it needs meta factory
// creator class.
template <class TestCase>
class TestMetaFactory
    : public TestMetaFactoryBase<typename TestCase::ParamType> {
 public:
  typedef typename TestCase::ParamType ParamType;

  TestMetaFactory() {}

  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
    return new ParameterizedTestFactory<TestCase>(parameter);
  }

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
};

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// ParameterizedTestCaseInfoBase is a generic interface
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
// accumulates test information provided by TEST_P macro invocations
// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
// and uses that information to register all resulting test instances
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
// a collection of pointers to the ParameterizedTestCaseInfo objects
// and calls RegisterTests() on each of them when asked.
class ParameterizedTestCaseInfoBase {
 public:
  virtual ~ParameterizedTestCaseInfoBase() {}

  // Base part of test case name for display purposes.
  virtual const string& GetTestCaseName() const = 0;
  // Test case id to verify identity.
  virtual TypeId GetTestCaseTypeId() const = 0;
  // UnitTest class invokes this method to register tests in this
  // test case right before running them in RUN_ALL_TESTS macro.
  // This method should not be called more then once on any single
  // instance of a ParameterizedTestCaseInfoBase derived class.
  virtual void RegisterTests() = 0;

 protected:
  ParameterizedTestCaseInfoBase() {}

 private:
  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
};

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
// macro invocations for a particular test case and generators
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
// test case. It registers tests with all values generated by all
// generators when asked.
template <class TestCase>
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
 public:
  // ParamType and GeneratorCreationFunc are private types but are required
  // for declarations of public methods AddTestPattern() and
  // AddTestCaseInstantiation().
  typedef typename TestCase::ParamType ParamType;
  // A function that returns an instance of appropriate generator type.
  typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();

  explicit ParameterizedTestCaseInfo(const char* name)
      : test_case_name_(name) {}

  // Test case base name for display purposes.
  virtual const string& GetTestCaseName() const { return test_case_name_; }
  // Test case id to verify identity.
  virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
  // TEST_P macro uses AddTestPattern() to record information
  // about a single test in a LocalTestInfo structure.
  // test_case_name is the base name of the test case (without invocation
  // prefix). test_base_name is the name of an individual test without
  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
  // test case base name and DoBar is test base name.
  void AddTestPattern(const char* test_case_name,
                      const char* test_base_name,
                      TestMetaFactoryBase<ParamType>* meta_factory) {
    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
                                                       test_base_name,
                                                       meta_factory)));
  }
  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
  // about a generator.
  int AddTestCaseInstantiation(const string& instantiation_name,
                               GeneratorCreationFunc* func,
                               const char* /* file */,
                               int /* line */) {
    instantiations_.push_back(::std::make_pair(instantiation_name, func));
    return 0;  // Return value used only to run this method in namespace scope.
  }
  // UnitTest class invokes this method to register tests in this test case
  // test cases right before running tests in RUN_ALL_TESTS macro.
  // This method should not be called more then once on any single
  // instance of a ParameterizedTestCaseInfoBase derived class.
  // UnitTest has a guard to prevent from calling this method more then once.
  virtual void RegisterTests() {
    for (typename TestInfoContainer::iterator test_it = tests_.begin();
         test_it != tests_.end(); ++test_it) {
      linked_ptr<TestInfo> test_info = *test_it;
      for (typename InstantiationContainer::iterator gen_it =
               instantiations_.begin(); gen_it != instantiations_.end();
               ++gen_it) {
        const string& instantiation_name = gen_it->first;
        ParamGenerator<ParamType> generator((*gen_it->second)());

        string test_case_name;
        if ( !instantiation_name.empty() )
          test_case_name = instantiation_name + "/";
        test_case_name += test_info->test_case_base_name;

        int i = 0;
        for (typename ParamGenerator<ParamType>::iterator param_it =
                 generator.begin();
             param_it != generator.end(); ++param_it, ++i) {
          Message test_name_stream;
          test_name_stream << test_info->test_base_name << "/" << i;
          MakeAndRegisterTestInfo(
              test_case_name.c_str(),
              test_name_stream.GetString().c_str(),
              NULL,  // No type parameter.
              PrintToString(*param_it).c_str(),
              GetTestCaseTypeId(),
              TestCase::SetUpTestCase,
              TestCase::TearDownTestCase,
              test_info->test_meta_factory->CreateTestFactory(*param_it));
        }  // for param_it
      }  // for gen_it
    }  // for test_it
  }  // RegisterTests

 private:
  // LocalTestInfo structure keeps information about a single test registered
  // with TEST_P macro.
  struct TestInfo {
    TestInfo(const char* a_test_case_base_name,
             const char* a_test_base_name,
             TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
        test_case_base_name(a_test_case_base_name),
        test_base_name(a_test_base_name),
        test_meta_factory(a_test_meta_factory) {}

    const string test_case_base_name;
    const string test_base_name;
    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
  };
  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
  // Keeps pairs of <Instantiation name, Sequence generator creation function>
  // received from INSTANTIATE_TEST_CASE_P macros.
  typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
      InstantiationContainer;

  const string test_case_name_;
  TestInfoContainer tests_;
  InstantiationContainer instantiations_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
};  // class ParameterizedTestCaseInfo

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
// macros use it to locate their corresponding ParameterizedTestCaseInfo
// descriptors.
class ParameterizedTestCaseRegistry {
 public:
  ParameterizedTestCaseRegistry() {}
  ~ParameterizedTestCaseRegistry() {
    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
         it != test_case_infos_.end(); ++it) {
      delete *it;
    }
  }

  // Looks up or creates and returns a structure containing information about
  // tests and instantiations of a particular test case.
  template <class TestCase>
  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
      const char* test_case_name,
      const char* file,
      int line) {
    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
         it != test_case_infos_.end(); ++it) {
      if ((*it)->GetTestCaseName() == test_case_name) {
        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
          // Complain about incorrect usage of Google Test facilities
          // and terminate the program since we cannot guaranty correct
          // test case setup and tear-down in this case.
          ReportInvalidTestCaseType(test_case_name,  file, line);
          posix::Abort();
        } else {
          // At this point we are sure that the object we found is of the same
          // type we are looking for, so we downcast it to that type
          // without further checks.
          typed_test_info = CheckedDowncastToActualType<
              ParameterizedTestCaseInfo<TestCase> >(*it);
        }
        break;
      }
    }
    if (typed_test_info == NULL) {
      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
      test_case_infos_.push_back(typed_test_info);
    }
    return typed_test_info;
  }
  void RegisterTests() {
    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
         it != test_case_infos_.end(); ++it) {
      (*it)->RegisterTests();
    }
  }

 private:
  typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;

  TestCaseInfoContainer test_case_infos_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
};

}  // namespace internal
}  // namespace testing

#endif  //  GTEST_HAS_PARAM_TEST

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
// This file was GENERATED by command:
//     pump.py gtest-param-util-generated.h.pump
// DO NOT EDIT BY HAND!!!

// Copyright 2008 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: vladl@google.com (Vlad Losev)

// Type and function utilities for implementing parameterized tests.
// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
//
// Currently Google Test supports at most 50 arguments in Values,
// and at most 10 arguments in Combine. Please contact
// googletestframework@googlegroups.com if you need more.
// Please note that the number of arguments to Combine is limited
// by the maximum arity of the implementation of tr1::tuple which is
// currently set at 10.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_

// scripts/fuse_gtest.py depends on gtest's own header being #included
// *unconditionally*.  Therefore these #includes cannot be moved
// inside #if GTEST_HAS_PARAM_TEST.

#if GTEST_HAS_PARAM_TEST

namespace testing {

// Forward declarations of ValuesIn(), which is implemented in
// include/gtest/gtest-param-test.h.
template <typename ForwardIterator>
internal::ParamGenerator<
  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
ValuesIn(ForwardIterator begin, ForwardIterator end);

template <typename T, size_t N>
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);

template <class Container>
internal::ParamGenerator<typename Container::value_type> ValuesIn(
    const Container& container);

namespace internal {

// Used in the Values() function to provide polymorphic capabilities.
template <typename T1>
class ValueArray1 {
 public:
  explicit ValueArray1(T1 v1) : v1_(v1) {}

  template <typename T>
  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray1& other);

  const T1 v1_;
};

template <typename T1, typename T2>
class ValueArray2 {
 public:
  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray2& other);

  const T1 v1_;
  const T2 v2_;
};

template <typename T1, typename T2, typename T3>
class ValueArray3 {
 public:
  ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray3& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
};

template <typename T1, typename T2, typename T3, typename T4>
class ValueArray4 {
 public:
  ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray4& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5>
class ValueArray5 {
 public:
  ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray5& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6>
class ValueArray6 {
 public:
  ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray6& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7>
class ValueArray7 {
 public:
  ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray7& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8>
class ValueArray8 {
 public:
  ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
      T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray8& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9>
class ValueArray9 {
 public:
  ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
      T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray9& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10>
class ValueArray10 {
 public:
  ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray10& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11>
class ValueArray11 {
 public:
  ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray11& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12>
class ValueArray12 {
 public:
  ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray12& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13>
class ValueArray13 {
 public:
  ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
      v12_(v12), v13_(v13) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray13& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14>
class ValueArray14 {
 public:
  ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray14& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15>
class ValueArray15 {
 public:
  ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray15& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16>
class ValueArray16 {
 public:
  ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
      v16_(v16) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray16& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17>
class ValueArray17 {
 public:
  ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
      T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray17& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18>
class ValueArray18 {
 public:
  ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray18& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19>
class ValueArray19 {
 public:
  ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray19& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20>
class ValueArray20 {
 public:
  ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
      v19_(v19), v20_(v20) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray20& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21>
class ValueArray21 {
 public:
  ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
      v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray21& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22>
class ValueArray22 {
 public:
  ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray22& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23>
class ValueArray23 {
 public:
  ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray23& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24>
class ValueArray24 {
 public:
  ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
      v22_(v22), v23_(v23), v24_(v24) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray24& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25>
class ValueArray25 {
 public:
  ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
      T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray25& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26>
class ValueArray26 {
 public:
  ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray26& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27>
class ValueArray27 {
 public:
  ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
      v26_(v26), v27_(v27) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray27& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28>
class ValueArray28 {
 public:
  ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
      v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray28& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29>
class ValueArray29 {
 public:
  ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray29& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30>
class ValueArray30 {
 public:
  ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray30& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31>
class ValueArray31 {
 public:
  ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30), v31_(v31) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray31& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32>
class ValueArray32 {
 public:
  ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray32& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33>
class ValueArray33 {
 public:
  ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
      T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray33& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34>
class ValueArray34 {
 public:
  ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33), v34_(v34) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray34& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35>
class ValueArray35 {
 public:
  ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
      v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray35& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36>
class ValueArray36 {
 public:
  ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray36& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37>
class ValueArray37 {
 public:
  ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
      v36_(v36), v37_(v37) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray37& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38>
class ValueArray38 {
 public:
  ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
      v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray38& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39>
class ValueArray39 {
 public:
  ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray39& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40>
class ValueArray40 {
 public:
  ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
      v40_(v40) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray40& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41>
class ValueArray41 {
 public:
  ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
      T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
      v39_(v39), v40_(v40), v41_(v41) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray41& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42>
class ValueArray42 {
 public:
  ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
      v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray42& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43>
class ValueArray43 {
 public:
  ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
      v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
      v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray43& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44>
class ValueArray44 {
 public:
  ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
      v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
      v43_(v43), v44_(v44) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray44& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45>
class ValueArray45 {
 public:
  ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
      v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
      v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray45& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46>
class ValueArray46 {
 public:
  ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_), static_cast<T>(v46_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray46& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
  const T46 v46_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47>
class ValueArray47 {
 public:
  ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
      v47_(v47) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray47& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
  const T46 v46_;
  const T47 v47_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48>
class ValueArray48 {
 public:
  ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
      v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
      v46_(v46), v47_(v47), v48_(v48) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
        static_cast<T>(v48_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray48& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
  const T46 v46_;
  const T47 v47_;
  const T48 v48_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49>
class ValueArray49 {
 public:
  ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
      T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
        static_cast<T>(v48_), static_cast<T>(v49_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray49& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
  const T46 v46_;
  const T47 v47_;
  const T48 v48_;
  const T49 v49_;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49, typename T50>
class ValueArray50 {
 public:
  ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
      T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}

  template <typename T>
  operator ParamGenerator<T>() const {
    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
        static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)};
    return ValuesIn(array);
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const ValueArray50& other);

  const T1 v1_;
  const T2 v2_;
  const T3 v3_;
  const T4 v4_;
  const T5 v5_;
  const T6 v6_;
  const T7 v7_;
  const T8 v8_;
  const T9 v9_;
  const T10 v10_;
  const T11 v11_;
  const T12 v12_;
  const T13 v13_;
  const T14 v14_;
  const T15 v15_;
  const T16 v16_;
  const T17 v17_;
  const T18 v18_;
  const T19 v19_;
  const T20 v20_;
  const T21 v21_;
  const T22 v22_;
  const T23 v23_;
  const T24 v24_;
  const T25 v25_;
  const T26 v26_;
  const T27 v27_;
  const T28 v28_;
  const T29 v29_;
  const T30 v30_;
  const T31 v31_;
  const T32 v32_;
  const T33 v33_;
  const T34 v34_;
  const T35 v35_;
  const T36 v36_;
  const T37 v37_;
  const T38 v38_;
  const T39 v39_;
  const T40 v40_;
  const T41 v41_;
  const T42 v42_;
  const T43 v43_;
  const T44 v44_;
  const T45 v45_;
  const T46 v46_;
  const T47 v47_;
  const T48 v48_;
  const T49 v49_;
  const T50 v50_;
};

# if GTEST_HAS_COMBINE
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Generates values from the Cartesian product of values produced
// by the argument generators.
//
template <typename T1, typename T2>
class CartesianProductGenerator2
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
 public:
  typedef ::std::tr1::tuple<T1, T2> ParamType;

  CartesianProductGenerator2(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2)
      : g1_(g1), g2_(g2) {}
  virtual ~CartesianProductGenerator2() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current2_;
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    ParamType current_value_;
  };  // class CartesianProductGenerator2::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator2& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
};  // class CartesianProductGenerator2


template <typename T1, typename T2, typename T3>
class CartesianProductGenerator3
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;

  CartesianProductGenerator3(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
      : g1_(g1), g2_(g2), g3_(g3) {}
  virtual ~CartesianProductGenerator3() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current3_;
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    ParamType current_value_;
  };  // class CartesianProductGenerator3::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator3& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
};  // class CartesianProductGenerator3


template <typename T1, typename T2, typename T3, typename T4>
class CartesianProductGenerator4
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;

  CartesianProductGenerator4(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
  virtual ~CartesianProductGenerator4() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current4_;
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    ParamType current_value_;
  };  // class CartesianProductGenerator4::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator4& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
};  // class CartesianProductGenerator4


template <typename T1, typename T2, typename T3, typename T4, typename T5>
class CartesianProductGenerator5
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;

  CartesianProductGenerator5(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
  virtual ~CartesianProductGenerator5() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current5_;
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    ParamType current_value_;
  };  // class CartesianProductGenerator5::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator5& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
};  // class CartesianProductGenerator5


template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6>
class CartesianProductGenerator6
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
        T6> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;

  CartesianProductGenerator6(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
      const ParamGenerator<T6>& g6)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
  virtual ~CartesianProductGenerator6() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5,
      const ParamGenerator<T6>& g6,
      const typename ParamGenerator<T6>::iterator& current6)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
          begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current6_;
      if (current6_ == end6_) {
        current6_ = begin6_;
        ++current5_;
      }
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_ &&
          current6_ == typed_other->current6_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_),
        begin6_(other.begin6_),
        end6_(other.end6_),
        current6_(other.current6_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_, *current6_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_ ||
          current6_ == end6_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    const typename ParamGenerator<T6>::iterator begin6_;
    const typename ParamGenerator<T6>::iterator end6_;
    typename ParamGenerator<T6>::iterator current6_;
    ParamType current_value_;
  };  // class CartesianProductGenerator6::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator6& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
  const ParamGenerator<T6> g6_;
};  // class CartesianProductGenerator6


template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7>
class CartesianProductGenerator7
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
        T7> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;

  CartesianProductGenerator7(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
  virtual ~CartesianProductGenerator7() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
        g7_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5,
      const ParamGenerator<T6>& g6,
      const typename ParamGenerator<T6>::iterator& current6,
      const ParamGenerator<T7>& g7,
      const typename ParamGenerator<T7>::iterator& current7)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
          begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current7_;
      if (current7_ == end7_) {
        current7_ = begin7_;
        ++current6_;
      }
      if (current6_ == end6_) {
        current6_ = begin6_;
        ++current5_;
      }
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_ &&
          current6_ == typed_other->current6_ &&
          current7_ == typed_other->current7_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_),
        begin6_(other.begin6_),
        end6_(other.end6_),
        current6_(other.current6_),
        begin7_(other.begin7_),
        end7_(other.end7_),
        current7_(other.current7_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_, *current6_, *current7_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_ ||
          current6_ == end6_ ||
          current7_ == end7_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    const typename ParamGenerator<T6>::iterator begin6_;
    const typename ParamGenerator<T6>::iterator end6_;
    typename ParamGenerator<T6>::iterator current6_;
    const typename ParamGenerator<T7>::iterator begin7_;
    const typename ParamGenerator<T7>::iterator end7_;
    typename ParamGenerator<T7>::iterator current7_;
    ParamType current_value_;
  };  // class CartesianProductGenerator7::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator7& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
  const ParamGenerator<T6> g6_;
  const ParamGenerator<T7> g7_;
};  // class CartesianProductGenerator7


template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8>
class CartesianProductGenerator8
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
        T7, T8> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;

  CartesianProductGenerator8(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
      const ParamGenerator<T8>& g8)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
          g8_(g8) {}
  virtual ~CartesianProductGenerator8() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
        g7_.begin(), g8_, g8_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
        g8_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5,
      const ParamGenerator<T6>& g6,
      const typename ParamGenerator<T6>::iterator& current6,
      const ParamGenerator<T7>& g7,
      const typename ParamGenerator<T7>::iterator& current7,
      const ParamGenerator<T8>& g8,
      const typename ParamGenerator<T8>::iterator& current8)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
          begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current8_;
      if (current8_ == end8_) {
        current8_ = begin8_;
        ++current7_;
      }
      if (current7_ == end7_) {
        current7_ = begin7_;
        ++current6_;
      }
      if (current6_ == end6_) {
        current6_ = begin6_;
        ++current5_;
      }
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_ &&
          current6_ == typed_other->current6_ &&
          current7_ == typed_other->current7_ &&
          current8_ == typed_other->current8_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_),
        begin6_(other.begin6_),
        end6_(other.end6_),
        current6_(other.current6_),
        begin7_(other.begin7_),
        end7_(other.end7_),
        current7_(other.current7_),
        begin8_(other.begin8_),
        end8_(other.end8_),
        current8_(other.current8_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_, *current6_, *current7_, *current8_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_ ||
          current6_ == end6_ ||
          current7_ == end7_ ||
          current8_ == end8_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    const typename ParamGenerator<T6>::iterator begin6_;
    const typename ParamGenerator<T6>::iterator end6_;
    typename ParamGenerator<T6>::iterator current6_;
    const typename ParamGenerator<T7>::iterator begin7_;
    const typename ParamGenerator<T7>::iterator end7_;
    typename ParamGenerator<T7>::iterator current7_;
    const typename ParamGenerator<T8>::iterator begin8_;
    const typename ParamGenerator<T8>::iterator end8_;
    typename ParamGenerator<T8>::iterator current8_;
    ParamType current_value_;
  };  // class CartesianProductGenerator8::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator8& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
  const ParamGenerator<T6> g6_;
  const ParamGenerator<T7> g7_;
  const ParamGenerator<T8> g8_;
};  // class CartesianProductGenerator8


template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9>
class CartesianProductGenerator9
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
        T7, T8, T9> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;

  CartesianProductGenerator9(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
          g9_(g9) {}
  virtual ~CartesianProductGenerator9() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
        g8_.end(), g9_, g9_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5,
      const ParamGenerator<T6>& g6,
      const typename ParamGenerator<T6>::iterator& current6,
      const ParamGenerator<T7>& g7,
      const typename ParamGenerator<T7>::iterator& current7,
      const ParamGenerator<T8>& g8,
      const typename ParamGenerator<T8>::iterator& current8,
      const ParamGenerator<T9>& g9,
      const typename ParamGenerator<T9>::iterator& current9)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
          begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current9_;
      if (current9_ == end9_) {
        current9_ = begin9_;
        ++current8_;
      }
      if (current8_ == end8_) {
        current8_ = begin8_;
        ++current7_;
      }
      if (current7_ == end7_) {
        current7_ = begin7_;
        ++current6_;
      }
      if (current6_ == end6_) {
        current6_ = begin6_;
        ++current5_;
      }
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_ &&
          current6_ == typed_other->current6_ &&
          current7_ == typed_other->current7_ &&
          current8_ == typed_other->current8_ &&
          current9_ == typed_other->current9_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_),
        begin6_(other.begin6_),
        end6_(other.end6_),
        current6_(other.current6_),
        begin7_(other.begin7_),
        end7_(other.end7_),
        current7_(other.current7_),
        begin8_(other.begin8_),
        end8_(other.end8_),
        current8_(other.current8_),
        begin9_(other.begin9_),
        end9_(other.end9_),
        current9_(other.current9_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_, *current6_, *current7_, *current8_,
            *current9_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_ ||
          current6_ == end6_ ||
          current7_ == end7_ ||
          current8_ == end8_ ||
          current9_ == end9_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    const typename ParamGenerator<T6>::iterator begin6_;
    const typename ParamGenerator<T6>::iterator end6_;
    typename ParamGenerator<T6>::iterator current6_;
    const typename ParamGenerator<T7>::iterator begin7_;
    const typename ParamGenerator<T7>::iterator end7_;
    typename ParamGenerator<T7>::iterator current7_;
    const typename ParamGenerator<T8>::iterator begin8_;
    const typename ParamGenerator<T8>::iterator end8_;
    typename ParamGenerator<T8>::iterator current8_;
    const typename ParamGenerator<T9>::iterator begin9_;
    const typename ParamGenerator<T9>::iterator end9_;
    typename ParamGenerator<T9>::iterator current9_;
    ParamType current_value_;
  };  // class CartesianProductGenerator9::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator9& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
  const ParamGenerator<T6> g6_;
  const ParamGenerator<T7> g7_;
  const ParamGenerator<T8> g8_;
  const ParamGenerator<T9> g9_;
};  // class CartesianProductGenerator9


template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10>
class CartesianProductGenerator10
    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
        T7, T8, T9, T10> > {
 public:
  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;

  CartesianProductGenerator10(const ParamGenerator<T1>& g1,
      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
      const ParamGenerator<T10>& g10)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
          g9_(g9), g10_(g10) {}
  virtual ~CartesianProductGenerator10() {}

  virtual ParamIteratorInterface<ParamType>* Begin() const {
    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
  }
  virtual ParamIteratorInterface<ParamType>* End() const {
    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
        g8_.end(), g9_, g9_.end(), g10_, g10_.end());
  }

 private:
  class Iterator : public ParamIteratorInterface<ParamType> {
   public:
    Iterator(const ParamGeneratorInterface<ParamType>* base,
      const ParamGenerator<T1>& g1,
      const typename ParamGenerator<T1>::iterator& current1,
      const ParamGenerator<T2>& g2,
      const typename ParamGenerator<T2>::iterator& current2,
      const ParamGenerator<T3>& g3,
      const typename ParamGenerator<T3>::iterator& current3,
      const ParamGenerator<T4>& g4,
      const typename ParamGenerator<T4>::iterator& current4,
      const ParamGenerator<T5>& g5,
      const typename ParamGenerator<T5>::iterator& current5,
      const ParamGenerator<T6>& g6,
      const typename ParamGenerator<T6>::iterator& current6,
      const ParamGenerator<T7>& g7,
      const typename ParamGenerator<T7>::iterator& current7,
      const ParamGenerator<T8>& g8,
      const typename ParamGenerator<T8>::iterator& current8,
      const ParamGenerator<T9>& g9,
      const typename ParamGenerator<T9>::iterator& current9,
      const ParamGenerator<T10>& g10,
      const typename ParamGenerator<T10>::iterator& current10)
        : base_(base),
          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
          begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
          begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {
      ComputeCurrentValue();
    }
    virtual ~Iterator() {}

    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
      return base_;
    }
    // Advance should not be called on beyond-of-range iterators
    // so no component iterators must be beyond end of range, either.
    virtual void Advance() {
      assert(!AtEnd());
      ++current10_;
      if (current10_ == end10_) {
        current10_ = begin10_;
        ++current9_;
      }
      if (current9_ == end9_) {
        current9_ = begin9_;
        ++current8_;
      }
      if (current8_ == end8_) {
        current8_ = begin8_;
        ++current7_;
      }
      if (current7_ == end7_) {
        current7_ = begin7_;
        ++current6_;
      }
      if (current6_ == end6_) {
        current6_ = begin6_;
        ++current5_;
      }
      if (current5_ == end5_) {
        current5_ = begin5_;
        ++current4_;
      }
      if (current4_ == end4_) {
        current4_ = begin4_;
        ++current3_;
      }
      if (current3_ == end3_) {
        current3_ = begin3_;
        ++current2_;
      }
      if (current2_ == end2_) {
        current2_ = begin2_;
        ++current1_;
      }
      ComputeCurrentValue();
    }
    virtual ParamIteratorInterface<ParamType>* Clone() const {
      return new Iterator(*this);
    }
    virtual const ParamType* Current() const { return &current_value_; }
    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
      // Having the same base generator guarantees that the other
      // iterator is of the same type and we can downcast.
      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
          << "The program attempted to compare iterators "
          << "from different generators." << std::endl;
      const Iterator* typed_other =
          CheckedDowncastToActualType<const Iterator>(&other);
      // We must report iterators equal if they both point beyond their
      // respective ranges. That can happen in a variety of fashions,
      // so we have to consult AtEnd().
      return (AtEnd() && typed_other->AtEnd()) ||
         (
          current1_ == typed_other->current1_ &&
          current2_ == typed_other->current2_ &&
          current3_ == typed_other->current3_ &&
          current4_ == typed_other->current4_ &&
          current5_ == typed_other->current5_ &&
          current6_ == typed_other->current6_ &&
          current7_ == typed_other->current7_ &&
          current8_ == typed_other->current8_ &&
          current9_ == typed_other->current9_ &&
          current10_ == typed_other->current10_);
    }

   private:
    Iterator(const Iterator& other)
        : base_(other.base_),
        begin1_(other.begin1_),
        end1_(other.end1_),
        current1_(other.current1_),
        begin2_(other.begin2_),
        end2_(other.end2_),
        current2_(other.current2_),
        begin3_(other.begin3_),
        end3_(other.end3_),
        current3_(other.current3_),
        begin4_(other.begin4_),
        end4_(other.end4_),
        current4_(other.current4_),
        begin5_(other.begin5_),
        end5_(other.end5_),
        current5_(other.current5_),
        begin6_(other.begin6_),
        end6_(other.end6_),
        current6_(other.current6_),
        begin7_(other.begin7_),
        end7_(other.end7_),
        current7_(other.current7_),
        begin8_(other.begin8_),
        end8_(other.end8_),
        current8_(other.current8_),
        begin9_(other.begin9_),
        end9_(other.end9_),
        current9_(other.current9_),
        begin10_(other.begin10_),
        end10_(other.end10_),
        current10_(other.current10_) {
      ComputeCurrentValue();
    }

    void ComputeCurrentValue() {
      if (!AtEnd())
        current_value_ = ParamType(*current1_, *current2_, *current3_,
            *current4_, *current5_, *current6_, *current7_, *current8_,
            *current9_, *current10_);
    }
    bool AtEnd() const {
      // We must report iterator past the end of the range when either of the
      // component iterators has reached the end of its range.
      return
          current1_ == end1_ ||
          current2_ == end2_ ||
          current3_ == end3_ ||
          current4_ == end4_ ||
          current5_ == end5_ ||
          current6_ == end6_ ||
          current7_ == end7_ ||
          current8_ == end8_ ||
          current9_ == end9_ ||
          current10_ == end10_;
    }

    // No implementation - assignment is unsupported.
    void operator=(const Iterator& other);

    const ParamGeneratorInterface<ParamType>* const base_;
    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
    // current[i]_ is the actual traversing iterator.
    const typename ParamGenerator<T1>::iterator begin1_;
    const typename ParamGenerator<T1>::iterator end1_;
    typename ParamGenerator<T1>::iterator current1_;
    const typename ParamGenerator<T2>::iterator begin2_;
    const typename ParamGenerator<T2>::iterator end2_;
    typename ParamGenerator<T2>::iterator current2_;
    const typename ParamGenerator<T3>::iterator begin3_;
    const typename ParamGenerator<T3>::iterator end3_;
    typename ParamGenerator<T3>::iterator current3_;
    const typename ParamGenerator<T4>::iterator begin4_;
    const typename ParamGenerator<T4>::iterator end4_;
    typename ParamGenerator<T4>::iterator current4_;
    const typename ParamGenerator<T5>::iterator begin5_;
    const typename ParamGenerator<T5>::iterator end5_;
    typename ParamGenerator<T5>::iterator current5_;
    const typename ParamGenerator<T6>::iterator begin6_;
    const typename ParamGenerator<T6>::iterator end6_;
    typename ParamGenerator<T6>::iterator current6_;
    const typename ParamGenerator<T7>::iterator begin7_;
    const typename ParamGenerator<T7>::iterator end7_;
    typename ParamGenerator<T7>::iterator current7_;
    const typename ParamGenerator<T8>::iterator begin8_;
    const typename ParamGenerator<T8>::iterator end8_;
    typename ParamGenerator<T8>::iterator current8_;
    const typename ParamGenerator<T9>::iterator begin9_;
    const typename ParamGenerator<T9>::iterator end9_;
    typename ParamGenerator<T9>::iterator current9_;
    const typename ParamGenerator<T10>::iterator begin10_;
    const typename ParamGenerator<T10>::iterator end10_;
    typename ParamGenerator<T10>::iterator current10_;
    ParamType current_value_;
  };  // class CartesianProductGenerator10::Iterator

  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductGenerator10& other);

  const ParamGenerator<T1> g1_;
  const ParamGenerator<T2> g2_;
  const ParamGenerator<T3> g3_;
  const ParamGenerator<T4> g4_;
  const ParamGenerator<T5> g5_;
  const ParamGenerator<T6> g6_;
  const ParamGenerator<T7> g7_;
  const ParamGenerator<T8> g8_;
  const ParamGenerator<T9> g9_;
  const ParamGenerator<T10> g10_;
};  // class CartesianProductGenerator10


// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Helper classes providing Combine() with polymorphic features. They allow
// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
// convertible to U.
//
template <class Generator1, class Generator2>
class CartesianProductHolder2 {
 public:
CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
      : g1_(g1), g2_(g2) {}
  template <typename T1, typename T2>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
        new CartesianProductGenerator2<T1, T2>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder2& other);

  const Generator1 g1_;
  const Generator2 g2_;
};  // class CartesianProductHolder2

template <class Generator1, class Generator2, class Generator3>
class CartesianProductHolder3 {
 public:
CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
    const Generator3& g3)
      : g1_(g1), g2_(g2), g3_(g3) {}
  template <typename T1, typename T2, typename T3>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
        new CartesianProductGenerator3<T1, T2, T3>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder3& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
};  // class CartesianProductHolder3

template <class Generator1, class Generator2, class Generator3,
    class Generator4>
class CartesianProductHolder4 {
 public:
CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
  template <typename T1, typename T2, typename T3, typename T4>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
        new CartesianProductGenerator4<T1, T2, T3, T4>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder4& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
};  // class CartesianProductHolder4

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5>
class CartesianProductHolder5 {
 public:
CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
        new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder5& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
};  // class CartesianProductHolder5

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5, class Generator6>
class CartesianProductHolder6 {
 public:
CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5,
    const Generator6& g6)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
        new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_),
        static_cast<ParamGenerator<T6> >(g6_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder6& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
  const Generator6 g6_;
};  // class CartesianProductHolder6

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5, class Generator6, class Generator7>
class CartesianProductHolder7 {
 public:
CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5,
    const Generator6& g6, const Generator7& g7)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
      T7> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
        new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_),
        static_cast<ParamGenerator<T6> >(g6_),
        static_cast<ParamGenerator<T7> >(g7_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder7& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
  const Generator6 g6_;
  const Generator7 g7_;
};  // class CartesianProductHolder7

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5, class Generator6, class Generator7,
    class Generator8>
class CartesianProductHolder8 {
 public:
CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5,
    const Generator6& g6, const Generator7& g7, const Generator8& g8)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
          g8_(g8) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
      T8> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
        new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_),
        static_cast<ParamGenerator<T6> >(g6_),
        static_cast<ParamGenerator<T7> >(g7_),
        static_cast<ParamGenerator<T8> >(g8_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder8& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
  const Generator6 g6_;
  const Generator7 g7_;
  const Generator8 g8_;
};  // class CartesianProductHolder8

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5, class Generator6, class Generator7,
    class Generator8, class Generator9>
class CartesianProductHolder9 {
 public:
CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5,
    const Generator6& g6, const Generator7& g7, const Generator8& g8,
    const Generator9& g9)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
          g9_(g9) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8, typename T9>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
      T9> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
        T9> >(
        new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_),
        static_cast<ParamGenerator<T6> >(g6_),
        static_cast<ParamGenerator<T7> >(g7_),
        static_cast<ParamGenerator<T8> >(g8_),
        static_cast<ParamGenerator<T9> >(g9_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder9& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
  const Generator6 g6_;
  const Generator7 g7_;
  const Generator8 g8_;
  const Generator9 g9_;
};  // class CartesianProductHolder9

template <class Generator1, class Generator2, class Generator3,
    class Generator4, class Generator5, class Generator6, class Generator7,
    class Generator8, class Generator9, class Generator10>
class CartesianProductHolder10 {
 public:
CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
    const Generator3& g3, const Generator4& g4, const Generator5& g5,
    const Generator6& g6, const Generator7& g7, const Generator8& g8,
    const Generator9& g9, const Generator10& g10)
      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
          g9_(g9), g10_(g10) {}
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8, typename T9, typename T10>
  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
      T9, T10> >() const {
    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
        T9, T10> >(
        new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
            T10>(
        static_cast<ParamGenerator<T1> >(g1_),
        static_cast<ParamGenerator<T2> >(g2_),
        static_cast<ParamGenerator<T3> >(g3_),
        static_cast<ParamGenerator<T4> >(g4_),
        static_cast<ParamGenerator<T5> >(g5_),
        static_cast<ParamGenerator<T6> >(g6_),
        static_cast<ParamGenerator<T7> >(g7_),
        static_cast<ParamGenerator<T8> >(g8_),
        static_cast<ParamGenerator<T9> >(g9_),
        static_cast<ParamGenerator<T10> >(g10_)));
  }

 private:
  // No implementation - assignment is unsupported.
  void operator=(const CartesianProductHolder10& other);

  const Generator1 g1_;
  const Generator2 g2_;
  const Generator3 g3_;
  const Generator4 g4_;
  const Generator5 g5_;
  const Generator6 g6_;
  const Generator7 g7_;
  const Generator8 g8_;
  const Generator9 g9_;
  const Generator10 g10_;
};  // class CartesianProductHolder10

# endif  // GTEST_HAS_COMBINE

}  // namespace internal
}  // namespace testing

#endif  //  GTEST_HAS_PARAM_TEST

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_

#if GTEST_HAS_PARAM_TEST

namespace testing {

// Functions producing parameter generators.
//
// Google Test uses these generators to produce parameters for value-
// parameterized tests. When a parameterized test case is instantiated
// with a particular generator, Google Test creates and runs tests
// for each element in the sequence produced by the generator.
//
// In the following sample, tests from test case FooTest are instantiated
// each three times with parameter values 3, 5, and 8:
//
// class FooTest : public TestWithParam<int> { ... };
//
// TEST_P(FooTest, TestThis) {
// }
// TEST_P(FooTest, TestThat) {
// }
// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
//

// Range() returns generators providing sequences of values in a range.
//
// Synopsis:
// Range(start, end)
//   - returns a generator producing a sequence of values {start, start+1,
//     start+2, ..., }.
// Range(start, end, step)
//   - returns a generator producing a sequence of values {start, start+step,
//     start+step+step, ..., }.
// Notes:
//   * The generated sequences never include end. For example, Range(1, 5)
//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
//     returns a generator producing {1, 3, 5, 7}.
//   * start and end must have the same type. That type may be any integral or
//     floating-point type or a user defined type satisfying these conditions:
//     * It must be assignable (have operator=() defined).
//     * It must have operator+() (operator+(int-compatible type) for
//       two-operand version).
//     * It must have operator<() defined.
//     Elements in the resulting sequences will also have that type.
//   * Condition start < end must be satisfied in order for resulting sequences
//     to contain any elements.
//
template <typename T, typename IncrementT>
internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
  return internal::ParamGenerator<T>(
      new internal::RangeGenerator<T, IncrementT>(start, end, step));
}

template <typename T>
internal::ParamGenerator<T> Range(T start, T end) {
  return Range(start, end, 1);
}

// ValuesIn() function allows generation of tests with parameters coming from
// a container.
//
// Synopsis:
// ValuesIn(const T (&array)[N])
//   - returns a generator producing sequences with elements from
//     a C-style array.
// ValuesIn(const Container& container)
//   - returns a generator producing sequences with elements from
//     an STL-style container.
// ValuesIn(Iterator begin, Iterator end)
//   - returns a generator producing sequences with elements from
//     a range [begin, end) defined by a pair of STL-style iterators. These
//     iterators can also be plain C pointers.
//
// Please note that ValuesIn copies the values from the containers
// passed in and keeps them to generate tests in RUN_ALL_TESTS().
//
// Examples:
//
// This instantiates tests from test case StringTest
// each with C-string values of "foo", "bar", and "baz":
//
// const char* strings[] = {"foo", "bar", "baz"};
// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
//
// This instantiates tests from test case StlStringTest
// each with STL strings with values "a" and "b":
//
// ::std::vector< ::std::string> GetParameterStrings() {
//   ::std::vector< ::std::string> v;
//   v.push_back("a");
//   v.push_back("b");
//   return v;
// }
//
// INSTANTIATE_TEST_CASE_P(CharSequence,
//                         StlStringTest,
//                         ValuesIn(GetParameterStrings()));
//
//
// This will also instantiate tests from CharTest
// each with parameter values 'a' and 'b':
//
// ::std::list<char> GetParameterChars() {
//   ::std::list<char> list;
//   list.push_back('a');
//   list.push_back('b');
//   return list;
// }
// ::std::list<char> l = GetParameterChars();
// INSTANTIATE_TEST_CASE_P(CharSequence2,
//                         CharTest,
//                         ValuesIn(l.begin(), l.end()));
//
template <typename ForwardIterator>
internal::ParamGenerator<
  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
ValuesIn(ForwardIterator begin, ForwardIterator end) {
  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
      ::value_type ParamType;
  return internal::ParamGenerator<ParamType>(
      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
}

template <typename T, size_t N>
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
  return ValuesIn(array, array + N);
}

template <class Container>
internal::ParamGenerator<typename Container::value_type> ValuesIn(
    const Container& container) {
  return ValuesIn(container.begin(), container.end());
}

// Values() allows generating tests from explicitly specified list of
// parameters.
//
// Synopsis:
// Values(T v1, T v2, ..., T vN)
//   - returns a generator producing sequences with elements v1, v2, ..., vN.
//
// For example, this instantiates tests from test case BarTest each
// with values "one", "two", and "three":
//
// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
//
// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
// The exact type of values will depend on the type of parameter in BazTest.
//
// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
//
// Currently, Values() supports from 1 to 50 parameters.
//
template <typename T1>
internal::ValueArray1<T1> Values(T1 v1) {
  return internal::ValueArray1<T1>(v1);
}

template <typename T1, typename T2>
internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
  return internal::ValueArray2<T1, T2>(v1, v2);
}

template <typename T1, typename T2, typename T3>
internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
  return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
}

template <typename T1, typename T2, typename T3, typename T4>
internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
  return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5>
internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5) {
  return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6>
internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
    T4 v4, T5 v5, T6 v6) {
  return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7>
internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
    T4 v4, T5 v5, T6 v6, T7 v7) {
  return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
      v6, v7);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8>
internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
  return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
      v5, v6, v7, v8);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9>
internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
  return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
      v4, v5, v6, v7, v8, v9);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10>
internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
  return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
      v2, v3, v4, v5, v6, v7, v8, v9, v10);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11>
internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
    T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11) {
  return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
      T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12>
internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
    T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12) {
  return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13>
internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
    T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13) {
  return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14>
internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
  return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
      v14);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15>
internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
  return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
      v13, v14, v15);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16>
internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16) {
  return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
      v12, v13, v14, v15, v16);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17>
internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17) {
  return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
      v11, v12, v13, v14, v15, v16, v17);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18>
internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18) {
  return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
      v10, v11, v12, v13, v14, v15, v16, v17, v18);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19>
internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
  return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20>
internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
  return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21>
internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
  return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22>
internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22) {
  return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
      v20, v21, v22);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23>
internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22, T23 v23) {
  return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
      v20, v21, v22, v23);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24>
internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22, T23 v23, T24 v24) {
  return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
      v19, v20, v21, v22, v23, v24);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25>
internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
  return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
      v18, v19, v20, v21, v22, v23, v24, v25);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26>
internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
    T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26) {
  return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27>
internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
    T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27) {
  return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28>
internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
    T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28) {
  return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
      v28);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29>
internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28, T29 v29) {
  return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
      v27, v28, v29);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30>
internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
  return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
      v26, v27, v28, v29, v30);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31>
internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
  return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
      v25, v26, v27, v28, v29, v30, v31);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32>
internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
    T32 v32) {
  return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
      v24, v25, v26, v27, v28, v29, v30, v31, v32);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33>
internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
    T32 v32, T33 v33) {
  return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34>
internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
    T31 v31, T32 v32, T33 v33, T34 v34) {
  return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35>
internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
  return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36>
internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
  return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
      v34, v35, v36);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37>
internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
    T37 v37) {
  return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
      v34, v35, v36, v37);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38>
internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
    T37 v37, T38 v38) {
  return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
      v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
      v33, v34, v35, v36, v37, v38);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39>
internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
    T37 v37, T38 v38, T39 v39) {
  return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
      v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
      v32, v33, v34, v35, v36, v37, v38, v39);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40>
internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
    T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
    T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
  return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
      v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41>
internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
    T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
  return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
      v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42>
internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
    T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
    T42 v42) {
  return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
      v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
      v42);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43>
internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
    T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
    T42 v42, T43 v43) {
  return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
      v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
      v41, v42, v43);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44>
internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
    T42 v42, T43 v43, T44 v44) {
  return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
      v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
      v40, v41, v42, v43, v44);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45>
internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
    T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
    T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
  return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
      v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
      v39, v40, v41, v42, v43, v44, v45);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46>
internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
  return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
      v38, v39, v40, v41, v42, v43, v44, v45, v46);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47>
internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
  return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
      v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48>
internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
    T48 v48) {
  return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
      v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49>
internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
    T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
    T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
    T47 v47, T48 v48, T49 v49) {
  return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
      v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
}

template <typename T1, typename T2, typename T3, typename T4, typename T5,
    typename T6, typename T7, typename T8, typename T9, typename T10,
    typename T11, typename T12, typename T13, typename T14, typename T15,
    typename T16, typename T17, typename T18, typename T19, typename T20,
    typename T21, typename T22, typename T23, typename T24, typename T25,
    typename T26, typename T27, typename T28, typename T29, typename T30,
    typename T31, typename T32, typename T33, typename T34, typename T35,
    typename T36, typename T37, typename T38, typename T39, typename T40,
    typename T41, typename T42, typename T43, typename T44, typename T45,
    typename T46, typename T47, typename T48, typename T49, typename T50>
internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
    T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
    T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
    T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
  return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
      v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
      v48, v49, v50);
}

// Bool() allows generating tests with parameters in a set of (false, true).
//
// Synopsis:
// Bool()
//   - returns a generator producing sequences with elements {false, true}.
//
// It is useful when testing code that depends on Boolean flags. Combinations
// of multiple flags can be tested when several Bool()'s are combined using
// Combine() function.
//
// In the following example all tests in the test case FlagDependentTest
// will be instantiated twice with parameters false and true.
//
// class FlagDependentTest : public testing::TestWithParam<bool> {
//   virtual void SetUp() {
//     external_flag = GetParam();
//   }
// }
// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
//
inline internal::ParamGenerator<bool> Bool() {
  return Values(false, true);
}

# if GTEST_HAS_COMBINE
// Combine() allows the user to combine two or more sequences to produce
// values of a Cartesian product of those sequences' elements.
//
// Synopsis:
// Combine(gen1, gen2, ..., genN)
//   - returns a generator producing sequences with elements coming from
//     the Cartesian product of elements from the sequences generated by
//     gen1, gen2, ..., genN. The sequence elements will have a type of
//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
//     of elements from sequences produces by gen1, gen2, ..., genN.
//
// Combine can have up to 10 arguments. This number is currently limited
// by the maximum number of elements in the tuple implementation used by Google
// Test.
//
// Example:
//
// This will instantiate tests in test case AnimalTest each one with
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
// tuple("dog", BLACK), and tuple("dog", WHITE):
//
// enum Color { BLACK, GRAY, WHITE };
// class AnimalTest
//     : public testing::TestWithParam<tuple<const char*, Color> > {...};
//
// TEST_P(AnimalTest, AnimalLooksNice) {...}
//
// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
//                         Combine(Values("cat", "dog"),
//                                 Values(BLACK, WHITE)));
//
// This will instantiate tests in FlagDependentTest with all variations of two
// Boolean flags:
//
// class FlagDependentTest
//     : public testing::TestWithParam<tuple<bool, bool> > {
//   virtual void SetUp() {
//     // Assigns external_flag_1 and external_flag_2 values from the tuple.
//     tie(external_flag_1, external_flag_2) = GetParam();
//   }
// };
//
// TEST_P(FlagDependentTest, TestFeature1) {
//   // Test your code using external_flag_1 and external_flag_2 here.
// }
// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
//                         Combine(Bool(), Bool()));
//
template <typename Generator1, typename Generator2>
internal::CartesianProductHolder2<Generator1, Generator2> Combine(
    const Generator1& g1, const Generator2& g2) {
  return internal::CartesianProductHolder2<Generator1, Generator2>(
      g1, g2);
}

template <typename Generator1, typename Generator2, typename Generator3>
internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3) {
  return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
      g1, g2, g3);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4>
internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
    Generator4> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4) {
  return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
      Generator4>(
      g1, g2, g3, g4);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5>
internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
    Generator4, Generator5> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5) {
  return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
      Generator4, Generator5>(
      g1, g2, g3, g4, g5);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5, typename Generator6>
internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
    Generator4, Generator5, Generator6> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5, const Generator6& g6) {
  return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
      Generator4, Generator5, Generator6>(
      g1, g2, g3, g4, g5, g6);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5, typename Generator6,
    typename Generator7>
internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
    Generator4, Generator5, Generator6, Generator7> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5, const Generator6& g6,
        const Generator7& g7) {
  return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
      Generator4, Generator5, Generator6, Generator7>(
      g1, g2, g3, g4, g5, g6, g7);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5, typename Generator6,
    typename Generator7, typename Generator8>
internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
    Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5, const Generator6& g6,
        const Generator7& g7, const Generator8& g8) {
  return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
      Generator4, Generator5, Generator6, Generator7, Generator8>(
      g1, g2, g3, g4, g5, g6, g7, g8);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5, typename Generator6,
    typename Generator7, typename Generator8, typename Generator9>
internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
    Generator4, Generator5, Generator6, Generator7, Generator8,
    Generator9> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5, const Generator6& g6,
        const Generator7& g7, const Generator8& g8, const Generator9& g9) {
  return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
      g1, g2, g3, g4, g5, g6, g7, g8, g9);
}

template <typename Generator1, typename Generator2, typename Generator3,
    typename Generator4, typename Generator5, typename Generator6,
    typename Generator7, typename Generator8, typename Generator9,
    typename Generator10>
internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
    Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
    Generator10> Combine(
    const Generator1& g1, const Generator2& g2, const Generator3& g3,
        const Generator4& g4, const Generator5& g5, const Generator6& g6,
        const Generator7& g7, const Generator8& g8, const Generator9& g9,
        const Generator10& g10) {
  return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
      Generator10>(
      g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
}
# endif  // GTEST_HAS_COMBINE



# define TEST_P(test_case_name, test_name) \
  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
      : public test_case_name { \
   public: \
    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
    virtual void TestBody(); \
   private: \
    static int AddToRegistry() { \
      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
          GetTestCasePatternHolder<test_case_name>(\
              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
                  #test_case_name, \
                  #test_name, \
                  new ::testing::internal::TestMetaFactory< \
                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
      return 0; \
    } \
    static int gtest_registering_dummy_; \
    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
  }; \
  int GTEST_TEST_CLASS_NAME_(test_case_name, \
                             test_name)::gtest_registering_dummy_ = \
      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
  ::testing::internal::ParamGenerator<test_case_name::ParamType> \
      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
  int gtest_##prefix##test_case_name##_dummy_ = \
      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
          GetTestCasePatternHolder<test_case_name>(\
              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
                  #prefix, \
                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
                  __FILE__, __LINE__)

}  // namespace testing

#endif  // GTEST_HAS_PARAM_TEST

#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
// Copyright 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
//
// Google C++ Testing Framework definitions useful in production code.

#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_

// When you need to test the private or protected members of a class,
// use the FRIEND_TEST macro to declare your tests as friends of the
// class.  For example:
//
// class MyClass {
//  private:
//   void MyMethod();
//   FRIEND_TEST(MyClassTest, MyMethod);
// };
//
// class MyClassTest : public testing::Test {
//   // ...
// };
//
// TEST_F(MyClassTest, MyMethod) {
//   // Can call MyClass::MyMethod() here.
// }

#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test

#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: mheule@google.com (Markus Heule)
//

#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_

#include <iosfwd>
#include <vector>

namespace testing {

// A copyable object representing the result of a test part (i.e. an
// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
//
// Don't inherit from TestPartResult as its destructor is not virtual.
class GTEST_API_ TestPartResult {
 public:
  // The possible outcomes of a test part (i.e. an assertion or an
  // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
  enum Type {
    kSuccess,          // Succeeded.
    kNonFatalFailure,  // Failed but the test can continue.
    kFatalFailure      // Failed and the test should be terminated.
  };

  // C'tor.  TestPartResult does NOT have a default constructor.
  // Always use this constructor (with parameters) to create a
  // TestPartResult object.
  TestPartResult(Type a_type,
                 const char* a_file_name,
                 int a_line_number,
                 const char* a_message)
      : type_(a_type),
        file_name_(a_file_name == NULL ? "" : a_file_name),
        line_number_(a_line_number),
        summary_(ExtractSummary(a_message)),
        message_(a_message) {
  }

  // Gets the outcome of the test part.
  Type type() const { return type_; }

  // Gets the name of the source file where the test part took place, or
  // NULL if it's unknown.
  const char* file_name() const {
    return file_name_.empty() ? NULL : file_name_.c_str();
  }

  // Gets the line in the source file where the test part took place,
  // or -1 if it's unknown.
  int line_number() const { return line_number_; }

  // Gets the summary of the failure message.
  const char* summary() const { return summary_.c_str(); }

  // Gets the message associated with the test part.
  const char* message() const { return message_.c_str(); }

  // Returns true iff the test part passed.
  bool passed() const { return type_ == kSuccess; }

  // Returns true iff the test part failed.
  bool failed() const { return type_ != kSuccess; }

  // Returns true iff the test part non-fatally failed.
  bool nonfatally_failed() const { return type_ == kNonFatalFailure; }

  // Returns true iff the test part fatally failed.
  bool fatally_failed() const { return type_ == kFatalFailure; }

 private:
  Type type_;

  // Gets the summary of the failure message by omitting the stack
  // trace in it.
  static std::string ExtractSummary(const char* message);

  // The name of the source file where the test part took place, or
  // "" if the source file is unknown.
  std::string file_name_;
  // The line in the source file where the test part took place, or -1
  // if the line number is unknown.
  int line_number_;
  std::string summary_;  // The test failure summary.
  std::string message_;  // The test failure message.
};

// Prints a TestPartResult object.
std::ostream& operator<<(std::ostream& os, const TestPartResult& result);

// An array of TestPartResult objects.
//
// Don't inherit from TestPartResultArray as its destructor is not
// virtual.
class GTEST_API_ TestPartResultArray {
 public:
  TestPartResultArray() {}

  // Appends the given TestPartResult to the array.
  void Append(const TestPartResult& result);

  // Returns the TestPartResult at the given index (0-based).
  const TestPartResult& GetTestPartResult(int index) const;

  // Returns the number of TestPartResult objects in the array.
  int size() const;

 private:
  std::vector<TestPartResult> array_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
};

// This interface knows how to report a test part result.
class TestPartResultReporterInterface {
 public:
  virtual ~TestPartResultReporterInterface() {}

  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
};

namespace internal {

// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
// statement generates new fatal failures. To do so it registers itself as the
// current test part result reporter. Besides checking if fatal failures were
// reported, it only delegates the reporting to the former result reporter.
// The original result reporter is restored in the destructor.
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
class GTEST_API_ HasNewFatalFailureHelper
    : public TestPartResultReporterInterface {
 public:
  HasNewFatalFailureHelper();
  virtual ~HasNewFatalFailureHelper();
  virtual void ReportTestPartResult(const TestPartResult& result);
  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
 private:
  bool has_new_fatal_failure_;
  TestPartResultReporterInterface* original_reporter_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
};

}  // namespace internal

}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
// Copyright 2008 Google Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)

#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

// This header implements typed tests and type-parameterized tests.

// Typed (aka type-driven) tests repeat the same test for types in a
// list.  You must know which types you want to test with when writing
// typed tests. Here's how you do it:

#if 0

// First, define a fixture class template.  It should be parameterized
// by a type.  Remember to derive it from testing::Test.
template <typename T>
class FooTest : public testing::Test {
 public:
  ...
  typedef std::list<T> List;
  static T shared_;
  T value_;
};

// Next, associate a list of types with the test case, which will be
// repeated for each type in the list.  The typedef is necessary for
// the macro to parse correctly.
typedef testing::Types<char, int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);

// If the type list contains only one type, you can write that type
// directly without Types<...>:
//   TYPED_TEST_CASE(FooTest, int);

// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
// tests for this test case as you want.
TYPED_TEST(FooTest, DoesBlah) {
  // Inside a test, refer to TypeParam to get the type parameter.
  // Since we are inside a derived class template, C++ requires use to
  // visit the members of FooTest via 'this'.
  TypeParam n = this->value_;

  // To visit static members of the fixture, add the TestFixture::
  // prefix.
  n += TestFixture::shared_;

  // To refer to typedefs in the fixture, add the "typename
  // TestFixture::" prefix.
  typename TestFixture::List values;
  values.push_back(n);
  ...
}

TYPED_TEST(FooTest, HasPropertyA) { ... }

#endif  // 0

// Type-parameterized tests are abstract test patterns parameterized
// by a type.  Compared with typed tests, type-parameterized tests
// allow you to define the test pattern without knowing what the type
// parameters are.  The defined pattern can be instantiated with
// different types any number of times, in any number of translation
// units.
//
// If you are designing an interface or concept, you can define a
// suite of type-parameterized tests to verify properties that any
// valid implementation of the interface/concept should have.  Then,
// each implementation can easily instantiate the test suite to verify
// that it conforms to the requirements, without having to write
// similar tests repeatedly.  Here's an example:

#if 0

// First, define a fixture class template.  It should be parameterized
// by a type.  Remember to derive it from testing::Test.
template <typename T>
class FooTest : public testing::Test {
  ...
};

// Next, declare that you will define a type-parameterized test case
// (the _P suffix is for "parameterized" or "pattern", whichever you
// prefer):
TYPED_TEST_CASE_P(FooTest);

// Then, use TYPED_TEST_P() to define as many type-parameterized tests
// for this type-parameterized test case as you want.
TYPED_TEST_P(FooTest, DoesBlah) {
  // Inside a test, refer to TypeParam to get the type parameter.
  TypeParam n = 0;
  ...
}

TYPED_TEST_P(FooTest, HasPropertyA) { ... }

// Now the tricky part: you need to register all test patterns before
// you can instantiate them.  The first argument of the macro is the
// test case name; the rest are the names of the tests in this test
// case.
REGISTER_TYPED_TEST_CASE_P(FooTest,
                           DoesBlah, HasPropertyA);

// Finally, you are free to instantiate the pattern with the types you
// want.  If you put the above code in a header file, you can #include
// it in multiple C++ source files and instantiate it multiple times.
//
// To distinguish different instances of the pattern, the first
// argument to the INSTANTIATE_* macro is a prefix that will be added
// to the actual test case name.  Remember to pick unique prefixes for
// different instances.
typedef testing::Types<char, int, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

// If the type list contains only one type, you can write that type
// directly without Types<...>:
//   INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);

#endif  // 0


// Implements typed tests.

#if GTEST_HAS_TYPED_TEST

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the name of the typedef for the type parameters of the
// given test case.
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_

// The 'Types' template argument below must have spaces around it
// since some compilers may choke on '>>' when passing a template
// instance (e.g. Types<int>)
# define TYPED_TEST_CASE(CaseName, Types) \
  typedef ::testing::internal::TypeList< Types >::type \
      GTEST_TYPE_PARAMS_(CaseName)

# define TYPED_TEST(CaseName, TestName) \
  template <typename gtest_TypeParam_> \
  class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
      : public CaseName<gtest_TypeParam_> { \
   private: \
    typedef CaseName<gtest_TypeParam_> TestFixture; \
    typedef gtest_TypeParam_ TypeParam; \
    virtual void TestBody(); \
  }; \
  bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
      ::testing::internal::TypeParameterizedTest< \
          CaseName, \
          ::testing::internal::TemplateSel< \
              GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
          GTEST_TYPE_PARAMS_(CaseName)>::Register(\
              "", #CaseName, #TestName, 0); \
  template <typename gtest_TypeParam_> \
  void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()

#endif  // GTEST_HAS_TYPED_TEST

// Implements type-parameterized tests.

#if GTEST_HAS_TYPED_TEST_P

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the namespace name that the type-parameterized tests for
// the given type-parameterized test case are defined in.  The exact
// name of the namespace is subject to change without notice.
# define GTEST_CASE_NAMESPACE_(TestCaseName) \
  gtest_case_##TestCaseName##_

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the name of the variable used to remember the names of
// the defined tests in the given test case.
# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
  gtest_typed_test_case_p_state_##TestCaseName##_

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
//
// Expands to the name of the variable used to remember the names of
// the registered tests in the given test case.
# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
  gtest_registered_test_names_##TestCaseName##_

// The variables defined in the type-parameterized test macros are
// static as typically these macros are used in a .h file that can be
// #included in multiple translation units linked together.
# define TYPED_TEST_CASE_P(CaseName) \
  static ::testing::internal::TypedTestCasePState \
      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)

# define TYPED_TEST_P(CaseName, TestName) \
  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
  template <typename gtest_TypeParam_> \
  class TestName : public CaseName<gtest_TypeParam_> { \
   private: \
    typedef CaseName<gtest_TypeParam_> TestFixture; \
    typedef gtest_TypeParam_ TypeParam; \
    virtual void TestBody(); \
  }; \
  static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
          __FILE__, __LINE__, #CaseName, #TestName); \
  } \
  template <typename gtest_TypeParam_> \
  void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()

# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
  typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
  } \
  static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
          __FILE__, __LINE__, #__VA_ARGS__)

// The 'Types' template argument below must have spaces around it
// since some compilers may choke on '>>' when passing a template
// instance (e.g. Types<int>)
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
  bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
      ::testing::internal::TypeParameterizedTestCase<CaseName, \
          GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
          ::testing::internal::TypeList< Types >::type>::Register(\
              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))

#endif  // GTEST_HAS_TYPED_TEST_P

#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

// Depending on the platform, different string classes are available.
// On Linux, in addition to ::std::string, Google also makes use of
// class ::string, which has the same interface as ::std::string, but
// has a different implementation.
//
// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
// ::string is available AND is a distinct type to ::std::string, or
// define it to 0 to indicate otherwise.
//
// If the user's ::std::string and ::string are the same class due to
// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
//
// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
// heuristically.

namespace testing {

// Declares the flags.

// This flag temporary enables the disabled tests.
GTEST_DECLARE_bool_(also_run_disabled_tests);

// This flag brings the debugger on an assertion failure.
GTEST_DECLARE_bool_(break_on_failure);

// This flag controls whether Google Test catches all test-thrown exceptions
// and logs them as failures.
GTEST_DECLARE_bool_(catch_exceptions);

// This flag enables using colors in terminal output. Available values are
// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
// to let Google Test decide.
GTEST_DECLARE_string_(color);

// This flag sets up the filter to select by name using a glob pattern
// the tests to run. If the filter is not given all tests are executed.
GTEST_DECLARE_string_(filter);

// This flag causes the Google Test to list tests. None of the tests listed
// are actually run if the flag is provided.
GTEST_DECLARE_bool_(list_tests);

// This flag controls whether Google Test emits a detailed XML report to a file
// in addition to its normal textual output.
GTEST_DECLARE_string_(output);

// This flags control whether Google Test prints the elapsed time for each
// test.
GTEST_DECLARE_bool_(print_time);

// This flag specifies the random number seed.
GTEST_DECLARE_int32_(random_seed);

// This flag sets how many times the tests are repeated. The default value
// is 1. If the value is -1 the tests are repeating forever.
GTEST_DECLARE_int32_(repeat);

// This flag controls whether Google Test includes Google Test internal
// stack frames in failure stack traces.
GTEST_DECLARE_bool_(show_internal_stack_frames);

// When this flag is specified, tests' order is randomized on every iteration.
GTEST_DECLARE_bool_(shuffle);

// This flag specifies the maximum number of stack frames to be
// printed in a failure message.
GTEST_DECLARE_int32_(stack_trace_depth);

// When this flag is specified, a failed assertion will throw an
// exception if exceptions are enabled, or exit the program with a
// non-zero code otherwise.
GTEST_DECLARE_bool_(throw_on_failure);

// When this flag is set with a "host:port" string, on supported
// platforms test results are streamed to the specified port on
// the specified host machine.
GTEST_DECLARE_string_(stream_result_to);

// The upper limit for valid stack trace depths.
const int kMaxStackTraceDepth = 100;

namespace internal {

class AssertHelper;
class DefaultGlobalTestPartResultReporter;
class ExecDeathTest;
class NoExecDeathTest;
class FinalSuccessChecker;
class GTestFlagSaver;
class StreamingListenerTest;
class TestResultAccessor;
class TestEventListenersAccessor;
class TestEventRepeater;
class UnitTestRecordPropertyTestHelper;
class WindowsDeathTest;
class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
                                    const std::string& message);

}  // namespace internal

// The friend relationship of some of these classes is cyclic.
// If we don't forward declare them the compiler might confuse the classes
// in friendship clauses with same named classes on the scope.
class Test;
class TestCase;
class TestInfo;
class UnitTest;

// A class for indicating whether an assertion was successful.  When
// the assertion wasn't successful, the AssertionResult object
// remembers a non-empty message that describes how it failed.
//
// To create an instance of this class, use one of the factory functions
// (AssertionSuccess() and AssertionFailure()).
//
// This class is useful for two purposes:
//   1. Defining predicate functions to be used with Boolean test assertions
//      EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
//   2. Defining predicate-format functions to be
//      used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
//
// For example, if you define IsEven predicate:
//
//   testing::AssertionResult IsEven(int n) {
//     if ((n % 2) == 0)
//       return testing::AssertionSuccess();
//     else
//       return testing::AssertionFailure() << n << " is odd";
//   }
//
// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
// will print the message
//
//   Value of: IsEven(Fib(5))
//     Actual: false (5 is odd)
//   Expected: true
//
// instead of a more opaque
//
//   Value of: IsEven(Fib(5))
//     Actual: false
//   Expected: true
//
// in case IsEven is a simple Boolean predicate.
//
// If you expect your predicate to be reused and want to support informative
// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
// about half as often as positive ones in our tests), supply messages for
// both success and failure cases:
//
//   testing::AssertionResult IsEven(int n) {
//     if ((n % 2) == 0)
//       return testing::AssertionSuccess() << n << " is even";
//     else
//       return testing::AssertionFailure() << n << " is odd";
//   }
//
// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
//
//   Value of: IsEven(Fib(6))
//     Actual: true (8 is even)
//   Expected: false
//
// NB: Predicates that support negative Boolean assertions have reduced
// performance in positive ones so be careful not to use them in tests
// that have lots (tens of thousands) of positive Boolean assertions.
//
// To use this class with EXPECT_PRED_FORMAT assertions such as:
//
//   // Verifies that Foo() returns an even number.
//   EXPECT_PRED_FORMAT1(IsEven, Foo());
//
// you need to define:
//
//   testing::AssertionResult IsEven(const char* expr, int n) {
//     if ((n % 2) == 0)
//       return testing::AssertionSuccess();
//     else
//       return testing::AssertionFailure()
//         << "Expected: " << expr << " is even\n  Actual: it's " << n;
//   }
//
// If Foo() returns 5, you will see the following message:
//
//   Expected: Foo() is even
//     Actual: it's 5
//
class GTEST_API_ AssertionResult {
 public:
  // Copy constructor.
  // Used in EXPECT_TRUE/FALSE(assertion_result).
  AssertionResult(const AssertionResult& other);
  // Used in the EXPECT_TRUE/FALSE(bool_expression).
  explicit AssertionResult(bool success) : success_(success) {}

  // Returns true iff the assertion succeeded.
  operator bool() const { return success_; }  // NOLINT

  // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
  AssertionResult operator!() const;

  // Returns the text streamed into this AssertionResult. Test assertions
  // use it when they fail (i.e., the predicate's outcome doesn't match the
  // assertion's expectation). When nothing has been streamed into the
  // object, returns an empty string.
  const char* message() const {
    return message_.get() != NULL ?  message_->c_str() : "";
  }
  // TODO(vladl@google.com): Remove this after making sure no clients use it.
  // Deprecated; please use message() instead.
  const char* failure_message() const { return message(); }

  // Streams a custom failure message into this object.
  template <typename T> AssertionResult& operator<<(const T& value) {
    AppendMessage(Message() << value);
    return *this;
  }

  // Allows streaming basic output manipulators such as endl or flush into
  // this object.
  AssertionResult& operator<<(
      ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
    AppendMessage(Message() << basic_manipulator);
    return *this;
  }

 private:
  // Appends the contents of message to message_.
  void AppendMessage(const Message& a_message) {
    if (message_.get() == NULL)
      message_.reset(new ::std::string);
    message_->append(a_message.GetString().c_str());
  }

  // Stores result of the assertion predicate.
  bool success_;
  // Stores the message describing the condition in case the expectation
  // construct is not satisfied with the predicate's outcome.
  // Referenced via a pointer to avoid taking too much stack frame space
  // with test assertions.
  internal::scoped_ptr< ::std::string> message_;

  GTEST_DISALLOW_ASSIGN_(AssertionResult);
};

// Makes a successful assertion result.
GTEST_API_ AssertionResult AssertionSuccess();

// Makes a failed assertion result.
GTEST_API_ AssertionResult AssertionFailure();

// Makes a failed assertion result with the given failure message.
// Deprecated; use AssertionFailure() << msg.
GTEST_API_ AssertionResult AssertionFailure(const Message& msg);

// The abstract class that all tests inherit from.
//
// In Google Test, a unit test program contains one or many TestCases, and
// each TestCase contains one or many Tests.
//
// When you define a test using the TEST macro, you don't need to
// explicitly derive from Test - the TEST macro automatically does
// this for you.
//
// The only time you derive from Test is when defining a test fixture
// to be used a TEST_F.  For example:
//
//   class FooTest : public testing::Test {
//    protected:
//     virtual void SetUp() { ... }
//     virtual void TearDown() { ... }
//     ...
//   };
//
//   TEST_F(FooTest, Bar) { ... }
//   TEST_F(FooTest, Baz) { ... }
//
// Test is not copyable.
class GTEST_API_ Test {
 public:
  friend class TestInfo;

  // Defines types for pointers to functions that set up and tear down
  // a test case.
  typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
  typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;

  // The d'tor is virtual as we intend to inherit from Test.
  virtual ~Test();

  // Sets up the stuff shared by all tests in this test case.
  //
  // Google Test will call Foo::SetUpTestCase() before running the first
  // test in test case Foo.  Hence a sub-class can define its own
  // SetUpTestCase() method to shadow the one defined in the super
  // class.
  static void SetUpTestCase() {}

  // Tears down the stuff shared by all tests in this test case.
  //
  // Google Test will call Foo::TearDownTestCase() after running the last
  // test in test case Foo.  Hence a sub-class can define its own
  // TearDownTestCase() method to shadow the one defined in the super
  // class.
  static void TearDownTestCase() {}

  // Returns true iff the current test has a fatal failure.
  static bool HasFatalFailure();

  // Returns true iff the current test has a non-fatal failure.
  static bool HasNonfatalFailure();

  // Returns true iff the current test has a (either fatal or
  // non-fatal) failure.
  static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }

  // Logs a property for the current test, test case, or for the entire
  // invocation of the test program when used outside of the context of a
  // test case.  Only the last value for a given key is remembered.  These
  // are public static so they can be called from utility functions that are
  // not members of the test fixture.  Calls to RecordProperty made during
  // lifespan of the test (from the moment its constructor starts to the
  // moment its destructor finishes) will be output in XML as attributes of
  // the <testcase> element.  Properties recorded from fixture's
  // SetUpTestCase or TearDownTestCase are logged as attributes of the
  // corresponding <testsuite> element.  Calls to RecordProperty made in the
  // global context (before or after invocation of RUN_ALL_TESTS and from
  // SetUp/TearDown method of Environment objects registered with Google
  // Test) will be output as attributes of the <testsuites> element.
  static void RecordProperty(const std::string& key, const std::string& value);
  static void RecordProperty(const std::string& key, int value);

 protected:
  // Creates a Test object.
  Test();

  // Sets up the test fixture.
  virtual void SetUp();

  // Tears down the test fixture.
  virtual void TearDown();

 private:
  // Returns true iff the current test has the same fixture class as
  // the first test in the current test case.
  static bool HasSameFixtureClass();

  // Runs the test after the test fixture has been set up.
  //
  // A sub-class must implement this to define the test logic.
  //
  // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
  // Instead, use the TEST or TEST_F macro.
  virtual void TestBody() = 0;

  // Sets up, executes, and tears down the test.
  void Run();

  // Deletes self.  We deliberately pick an unusual name for this
  // internal method to avoid clashing with names used in user TESTs.
  void DeleteSelf_() { delete this; }

  // Uses a GTestFlagSaver to save and restore all Google Test flags.
  const internal::GTestFlagSaver* const gtest_flag_saver_;

  // Often a user mis-spells SetUp() as Setup() and spends a long time
  // wondering why it is never called by Google Test.  The declaration of
  // the following method is solely for catching such an error at
  // compile time:
  //
  //   - The return type is deliberately chosen to be not void, so it
  //   will be a conflict if a user declares void Setup() in his test
  //   fixture.
  //
  //   - This method is private, so it will be another compiler error
  //   if a user calls it from his test fixture.
  //
  // DO NOT OVERRIDE THIS FUNCTION.
  //
  // If you see an error about overriding the following function or
  // about it being private, you have mis-spelled SetUp() as Setup().
  struct Setup_should_be_spelled_SetUp {};
  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }

  // We disallow copying Tests.
  GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
};

typedef internal::TimeInMillis TimeInMillis;

// A copyable object representing a user specified test property which can be
// output as a key/value string pair.
//
// Don't inherit from TestProperty as its destructor is not virtual.
class TestProperty {
 public:
  // C'tor.  TestProperty does NOT have a default constructor.
  // Always use this constructor (with parameters) to create a
  // TestProperty object.
  TestProperty(const std::string& a_key, const std::string& a_value) :
    key_(a_key), value_(a_value) {
  }

  // Gets the user supplied key.
  const char* key() const {
    return key_.c_str();
  }

  // Gets the user supplied value.
  const char* value() const {
    return value_.c_str();
  }

  // Sets a new value, overriding the one supplied in the constructor.
  void SetValue(const std::string& new_value) {
    value_ = new_value;
  }

 private:
  // The key supplied by the user.
  std::string key_;
  // The value supplied by the user.
  std::string value_;
};

// The result of a single Test.  This includes a list of
// TestPartResults, a list of TestProperties, a count of how many
// death tests there are in the Test, and how much time it took to run
// the Test.
//
// TestResult is not copyable.
class GTEST_API_ TestResult {
 public:
  // Creates an empty TestResult.
  TestResult();

  // D'tor.  Do not inherit from TestResult.
  ~TestResult();

  // Gets the number of all test parts.  This is the sum of the number
  // of successful test parts and the number of failed test parts.
  int total_part_count() const;

  // Returns the number of the test properties.
  int test_property_count() const;

  // Returns true iff the test passed (i.e. no test part failed).
  bool Passed() const { return !Failed(); }

  // Returns true iff the test failed.
  bool Failed() const;

  // Returns true iff the test fatally failed.
  bool HasFatalFailure() const;

  // Returns true iff the test has a non-fatal failure.
  bool HasNonfatalFailure() const;

  // Returns the elapsed time, in milliseconds.
  TimeInMillis elapsed_time() const { return elapsed_time_; }

  // Returns the i-th test part result among all the results. i can range
  // from 0 to test_property_count() - 1. If i is not in that range, aborts
  // the program.
  const TestPartResult& GetTestPartResult(int i) const;

  // Returns the i-th test property. i can range from 0 to
  // test_property_count() - 1. If i is not in that range, aborts the
  // program.
  const TestProperty& GetTestProperty(int i) const;

 private:
  friend class TestInfo;
  friend class TestCase;
  friend class UnitTest;
  friend class internal::DefaultGlobalTestPartResultReporter;
  friend class internal::ExecDeathTest;
  friend class internal::TestResultAccessor;
  friend class internal::UnitTestImpl;
  friend class internal::WindowsDeathTest;

  // Gets the vector of TestPartResults.
  const std::vector<TestPartResult>& test_part_results() const {
    return test_part_results_;
  }

  // Gets the vector of TestProperties.
  const std::vector<TestProperty>& test_properties() const {
    return test_properties_;
  }

  // Sets the elapsed time.
  void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }

  // Adds a test property to the list. The property is validated and may add
  // a non-fatal failure if invalid (e.g., if it conflicts with reserved
  // key names). If a property is already recorded for the same key, the
  // value will be updated, rather than storing multiple values for the same
  // key.  xml_element specifies the element for which the property is being
  // recorded and is used for validation.
  void RecordProperty(const std::string& xml_element,
                      const TestProperty& test_property);

  // Adds a failure if the key is a reserved attribute of Google Test
  // testcase tags.  Returns true if the property is valid.
  // TODO(russr): Validate attribute names are legal and human readable.
  static bool ValidateTestProperty(const std::string& xml_element,
                                   const TestProperty& test_property);

  // Adds a test part result to the list.
  void AddTestPartResult(const TestPartResult& test_part_result);

  // Returns the death test count.
  int death_test_count() const { return death_test_count_; }

  // Increments the death test count, returning the new count.
  int increment_death_test_count() { return ++death_test_count_; }

  // Clears the test part results.
  void ClearTestPartResults();

  // Clears the object.
  void Clear();

  // Protects mutable state of the property vector and of owned
  // properties, whose values may be updated.
  internal::Mutex test_properites_mutex_;

  // The vector of TestPartResults
  std::vector<TestPartResult> test_part_results_;
  // The vector of TestProperties
  std::vector<TestProperty> test_properties_;
  // Running count of death tests.
  int death_test_count_;
  // The elapsed time, in milliseconds.
  TimeInMillis elapsed_time_;

  // We disallow copying TestResult.
  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
};  // class TestResult

// A TestInfo object stores the following information about a test:
//
//   Test case name
//   Test name
//   Whether the test should be run
//   A function pointer that creates the test object when invoked
//   Test result
//
// The constructor of TestInfo registers itself with the UnitTest
// singleton such that the RUN_ALL_TESTS() macro knows which tests to
// run.
class GTEST_API_ TestInfo {
 public:
  // Destructs a TestInfo object.  This function is not virtual, so
  // don't inherit from TestInfo.
  ~TestInfo();

  // Returns the test case name.
  const char* test_case_name() const { return test_case_name_.c_str(); }

  // Returns the test name.
  const char* name() const { return name_.c_str(); }

  // Returns the name of the parameter type, or NULL if this is not a typed
  // or a type-parameterized test.
  const char* type_param() const {
    if (type_param_.get() != NULL)
      return type_param_->c_str();
    return NULL;
  }

  // Returns the text representation of the value parameter, or NULL if this
  // is not a value-parameterized test.
  const char* value_param() const {
    if (value_param_.get() != NULL)
      return value_param_->c_str();
    return NULL;
  }

  // Returns true if this test should run, that is if the test is not
  // disabled (or it is disabled but the also_run_disabled_tests flag has
  // been specified) and its full name matches the user-specified filter.
  //
  // Google Test allows the user to filter the tests by their full names.
  // The full name of a test Bar in test case Foo is defined as
  // "Foo.Bar".  Only the tests that match the filter will run.
  //
  // A filter is a colon-separated list of glob (not regex) patterns,
  // optionally followed by a '-' and a colon-separated list of
  // negative patterns (tests to exclude).  A test is run if it
  // matches one of the positive patterns and does not match any of
  // the negative patterns.
  //
  // For example, *A*:Foo.* is a filter that matches any string that
  // contains the character 'A' or starts with "Foo.".
  bool should_run() const { return should_run_; }

  // Returns true iff this test will appear in the XML report.
  bool is_reportable() const {
    // For now, the XML report includes all tests matching the filter.
    // In the future, we may trim tests that are excluded because of
    // sharding.
    return matches_filter_;
  }

  // Returns the result of the test.
  const TestResult* result() const { return &result_; }

 private:
#if GTEST_HAS_DEATH_TEST
  friend class internal::DefaultDeathTestFactory;
#endif  // GTEST_HAS_DEATH_TEST
  friend class Test;
  friend class TestCase;
  friend class internal::UnitTestImpl;
  friend class internal::StreamingListenerTest;
  friend TestInfo* internal::MakeAndRegisterTestInfo(
      const char* test_case_name,
      const char* name,
      const char* type_param,
      const char* value_param,
      internal::TypeId fixture_class_id,
      Test::SetUpTestCaseFunc set_up_tc,
      Test::TearDownTestCaseFunc tear_down_tc,
      internal::TestFactoryBase* factory);

  // Constructs a TestInfo object. The newly constructed instance assumes
  // ownership of the factory object.
  TestInfo(const std::string& test_case_name,
           const std::string& name,
           const char* a_type_param,   // NULL if not a type-parameterized test
           const char* a_value_param,  // NULL if not a value-parameterized test
           internal::TypeId fixture_class_id,
           internal::TestFactoryBase* factory);

  // Increments the number of death tests encountered in this test so
  // far.
  int increment_death_test_count() {
    return result_.increment_death_test_count();
  }

  // Creates the test object, runs it, records its result, and then
  // deletes it.
  void Run();

  static void ClearTestResult(TestInfo* test_info) {
    test_info->result_.Clear();
  }

  // These fields are immutable properties of the test.
  const std::string test_case_name_;     // Test case name
  const std::string name_;               // Test name
  // Name of the parameter type, or NULL if this is not a typed or a
  // type-parameterized test.
  const internal::scoped_ptr<const ::std::string> type_param_;
  // Text representation of the value parameter, or NULL if this is not a
  // value-parameterized test.
  const internal::scoped_ptr<const ::std::string> value_param_;
  const internal::TypeId fixture_class_id_;   // ID of the test fixture class
  bool should_run_;                 // True iff this test should run
  bool is_disabled_;                // True iff this test is disabled
  bool matches_filter_;             // True if this test matches the
                                    // user-specified filter.
  internal::TestFactoryBase* const factory_;  // The factory that creates
                                              // the test object

  // This field is mutable and needs to be reset before running the
  // test for the second time.
  TestResult result_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
};

// A test case, which consists of a vector of TestInfos.
//
// TestCase is not copyable.
class GTEST_API_ TestCase {
 public:
  // Creates a TestCase with the given name.
  //
  // TestCase does NOT have a default constructor.  Always use this
  // constructor to create a TestCase object.
  //
  // Arguments:
  //
  //   name:         name of the test case
  //   a_type_param: the name of the test's type parameter, or NULL if
  //                 this is not a type-parameterized test.
  //   set_up_tc:    pointer to the function that sets up the test case
  //   tear_down_tc: pointer to the function that tears down the test case
  TestCase(const char* name, const char* a_type_param,
           Test::SetUpTestCaseFunc set_up_tc,
           Test::TearDownTestCaseFunc tear_down_tc);

  // Destructor of TestCase.
  virtual ~TestCase();

  // Gets the name of the TestCase.
  const char* name() const { return name_.c_str(); }

  // Returns the name of the parameter type, or NULL if this is not a
  // type-parameterized test case.
  const char* type_param() const {
    if (type_param_.get() != NULL)
      return type_param_->c_str();
    return NULL;
  }

  // Returns true if any test in this test case should run.
  bool should_run() const { return should_run_; }

  // Gets the number of successful tests in this test case.
  int successful_test_count() const;

  // Gets the number of failed tests in this test case.
  int failed_test_count() const;

  // Gets the number of disabled tests that will be reported in the XML report.
  int reportable_disabled_test_count() const;

  // Gets the number of disabled tests in this test case.
  int disabled_test_count() const;

  // Gets the number of tests to be printed in the XML report.
  int reportable_test_count() const;

  // Get the number of tests in this test case that should run.
  int test_to_run_count() const;

  // Gets the number of all tests in this test case.
  int total_test_count() const;

  // Returns true iff the test case passed.
  bool Passed() const { return !Failed(); }

  // Returns true iff the test case failed.
  bool Failed() const { return failed_test_count() > 0; }

  // Returns the elapsed time, in milliseconds.
  TimeInMillis elapsed_time() const { return elapsed_time_; }

  // Returns the i-th test among all the tests. i can range from 0 to
  // total_test_count() - 1. If i is not in that range, returns NULL.
  const TestInfo* GetTestInfo(int i) const;

  // Returns the TestResult that holds test properties recorded during
  // execution of SetUpTestCase and TearDownTestCase.
  const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }

 private:
  friend class Test;
  friend class internal::UnitTestImpl;

  // Gets the (mutable) vector of TestInfos in this TestCase.
  std::vector<TestInfo*>& test_info_list() { return test_info_list_; }

  // Gets the (immutable) vector of TestInfos in this TestCase.
  const std::vector<TestInfo*>& test_info_list() const {
    return test_info_list_;
  }

  // Returns the i-th test among all the tests. i can range from 0 to
  // total_test_count() - 1. If i is not in that range, returns NULL.
  TestInfo* GetMutableTestInfo(int i);

  // Sets the should_run member.
  void set_should_run(bool should) { should_run_ = should; }

  // Adds a TestInfo to this test case.  Will delete the TestInfo upon
  // destruction of the TestCase object.
  void AddTestInfo(TestInfo * test_info);

  // Clears the results of all tests in this test case.
  void ClearResult();

  // Clears the results of all tests in the given test case.
  static void ClearTestCaseResult(TestCase* test_case) {
    test_case->ClearResult();
  }

  // Runs every test in this TestCase.
  void Run();

  // Runs SetUpTestCase() for this TestCase.  This wrapper is needed
  // for catching exceptions thrown from SetUpTestCase().
  void RunSetUpTestCase() { (*set_up_tc_)(); }

  // Runs TearDownTestCase() for this TestCase.  This wrapper is
  // needed for catching exceptions thrown from TearDownTestCase().
  void RunTearDownTestCase() { (*tear_down_tc_)(); }

  // Returns true iff test passed.
  static bool TestPassed(const TestInfo* test_info) {
    return test_info->should_run() && test_info->result()->Passed();
  }

  // Returns true iff test failed.
  static bool TestFailed(const TestInfo* test_info) {
    return test_info->should_run() && test_info->result()->Failed();
  }

  // Returns true iff the test is disabled and will be reported in the XML
  // report.
  static bool TestReportableDisabled(const TestInfo* test_info) {
    return test_info->is_reportable() && test_info->is_disabled_;
  }

  // Returns true iff test is disabled.
  static bool TestDisabled(const TestInfo* test_info) {
    return test_info->is_disabled_;
  }

  // Returns true iff this test will appear in the XML report.
  static bool TestReportable(const TestInfo* test_info) {
    return test_info->is_reportable();
  }

  // Returns true if the given test should run.
  static bool ShouldRunTest(const TestInfo* test_info) {
    return test_info->should_run();
  }

  // Shuffles the tests in this test case.
  void ShuffleTests(internal::Random* random);

  // Restores the test order to before the first shuffle.
  void UnshuffleTests();

  // Name of the test case.
  std::string name_;
  // Name of the parameter type, or NULL if this is not a typed or a
  // type-parameterized test.
  const internal::scoped_ptr<const ::std::string> type_param_;
  // The vector of TestInfos in their original order.  It owns the
  // elements in the vector.
  std::vector<TestInfo*> test_info_list_;
  // Provides a level of indirection for the test list to allow easy
  // shuffling and restoring the test order.  The i-th element in this
  // vector is the index of the i-th test in the shuffled test list.
  std::vector<int> test_indices_;
  // Pointer to the function that sets up the test case.
  Test::SetUpTestCaseFunc set_up_tc_;
  // Pointer to the function that tears down the test case.
  Test::TearDownTestCaseFunc tear_down_tc_;
  // True iff any test in this test case should run.
  bool should_run_;
  // Elapsed time, in milliseconds.
  TimeInMillis elapsed_time_;
  // Holds test properties recorded during execution of SetUpTestCase and
  // TearDownTestCase.
  TestResult ad_hoc_test_result_;

  // We disallow copying TestCases.
  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
};

// An Environment object is capable of setting up and tearing down an
// environment.  The user should subclass this to define his own
// environment(s).
//
// An Environment object does the set-up and tear-down in virtual
// methods SetUp() and TearDown() instead of the constructor and the
// destructor, as:
//
//   1. You cannot safely throw from a destructor.  This is a problem
//      as in some cases Google Test is used where exceptions are enabled, and
//      we may want to implement ASSERT_* using exceptions where they are
//      available.
//   2. You cannot use ASSERT_* directly in a constructor or
//      destructor.
class Environment {
 public:
  // The d'tor is virtual as we need to subclass Environment.
  virtual ~Environment() {}

  // Override this to define how to set up the environment.
  virtual void SetUp() {}

  // Override this to define how to tear down the environment.
  virtual void TearDown() {}
 private:
  // If you see an error about overriding the following function or
  // about it being private, you have mis-spelled SetUp() as Setup().
  struct Setup_should_be_spelled_SetUp {};
  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
};

// The interface for tracing execution of tests. The methods are organized in
// the order the corresponding events are fired.
class TestEventListener {
 public:
  virtual ~TestEventListener() {}

  // Fired before any test activity starts.
  virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;

  // Fired before each iteration of tests starts.  There may be more than
  // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
  // index, starting from 0.
  virtual void OnTestIterationStart(const UnitTest& unit_test,
                                    int iteration) = 0;

  // Fired before environment set-up for each iteration of tests starts.
  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;

  // Fired after environment set-up for each iteration of tests ends.
  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;

  // Fired before the test case starts.
  virtual void OnTestCaseStart(const TestCase& test_case) = 0;

  // Fired before the test starts.
  virtual void OnTestStart(const TestInfo& test_info) = 0;

  // Fired after a failed assertion or a SUCCEED() invocation.
  virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;

  // Fired after the test ends.
  virtual void OnTestEnd(const TestInfo& test_info) = 0;

  // Fired after the test case ends.
  virtual void OnTestCaseEnd(const TestCase& test_case) = 0;

  // Fired before environment tear-down for each iteration of tests starts.
  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;

  // Fired after environment tear-down for each iteration of tests ends.
  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;

  // Fired after each iteration of tests finishes.
  virtual void OnTestIterationEnd(const UnitTest& unit_test,
                                  int iteration) = 0;

  // Fired after all test activities have ended.
  virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
};

// The convenience class for users who need to override just one or two
// methods and are not concerned that a possible change to a signature of
// the methods they override will not be caught during the build.  For
// comments about each method please see the definition of TestEventListener
// above.
class EmptyTestEventListener : public TestEventListener {
 public:
  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
  virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
                                    int /*iteration*/) {}
  virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
  virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
  virtual void OnTestStart(const TestInfo& /*test_info*/) {}
  virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
  virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
  virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
  virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
  virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
                                  int /*iteration*/) {}
  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
};

// TestEventListeners lets users add listeners to track events in Google Test.
class GTEST_API_ TestEventListeners {
 public:
  TestEventListeners();
  ~TestEventListeners();

  // Appends an event listener to the end of the list. Google Test assumes
  // the ownership of the listener (i.e. it will delete the listener when
  // the test program finishes).
  void Append(TestEventListener* listener);

  // Removes the given event listener from the list and returns it.  It then
  // becomes the caller's responsibility to delete the listener. Returns
  // NULL if the listener is not found in the list.
  TestEventListener* Release(TestEventListener* listener);

  // Returns the standard listener responsible for the default console
  // output.  Can be removed from the listeners list to shut down default
  // console output.  Note that removing this object from the listener list
  // with Release transfers its ownership to the caller and makes this
  // function return NULL the next time.
  TestEventListener* default_result_printer() const {
    return default_result_printer_;
  }

  // Returns the standard listener responsible for the default XML output
  // controlled by the --gtest_output=xml flag.  Can be removed from the
  // listeners list by users who want to shut down the default XML output
  // controlled by this flag and substitute it with custom one.  Note that
  // removing this object from the listener list with Release transfers its
  // ownership to the caller and makes this function return NULL the next
  // time.
  TestEventListener* default_xml_generator() const {
    return default_xml_generator_;
  }

 private:
  friend class TestCase;
  friend class TestInfo;
  friend class internal::DefaultGlobalTestPartResultReporter;
  friend class internal::NoExecDeathTest;
  friend class internal::TestEventListenersAccessor;
  friend class internal::UnitTestImpl;

  // Returns repeater that broadcasts the TestEventListener events to all
  // subscribers.
  TestEventListener* repeater();

  // Sets the default_result_printer attribute to the provided listener.
  // The listener is also added to the listener list and previous
  // default_result_printer is removed from it and deleted. The listener can
  // also be NULL in which case it will not be added to the list. Does
  // nothing if the previous and the current listener objects are the same.
  void SetDefaultResultPrinter(TestEventListener* listener);

  // Sets the default_xml_generator attribute to the provided listener.  The
  // listener is also added to the listener list and previous
  // default_xml_generator is removed from it and deleted. The listener can
  // also be NULL in which case it will not be added to the list. Does
  // nothing if the previous and the current listener objects are the same.
  void SetDefaultXmlGenerator(TestEventListener* listener);

  // Controls whether events will be forwarded by the repeater to the
  // listeners in the list.
  bool EventForwardingEnabled() const;
  void SuppressEventForwarding();

  // The actual list of listeners.
  internal::TestEventRepeater* repeater_;
  // Listener responsible for the standard result output.
  TestEventListener* default_result_printer_;
  // Listener responsible for the creation of the XML output file.
  TestEventListener* default_xml_generator_;

  // We disallow copying TestEventListeners.
  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
};

// A UnitTest consists of a vector of TestCases.
//
// This is a singleton class.  The only instance of UnitTest is
// created when UnitTest::GetInstance() is first called.  This
// instance is never deleted.
//
// UnitTest is not copyable.
//
// This class is thread-safe as long as the methods are called
// according to their specification.
class GTEST_API_ UnitTest {
 public:
  // Gets the singleton UnitTest object.  The first time this method
  // is called, a UnitTest object is constructed and returned.
  // Consecutive calls will return the same object.
  static UnitTest* GetInstance();

  // Runs all tests in this UnitTest object and prints the result.
  // Returns 0 if successful, or 1 otherwise.
  //
  // This method can only be called from the main thread.
  //
  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
  int Run() GTEST_MUST_USE_RESULT_;

  // Returns the working directory when the first TEST() or TEST_F()
  // was executed.  The UnitTest object owns the string.
  const char* original_working_dir() const;

  // Returns the TestCase object for the test that's currently running,
  // or NULL if no test is running.
  const TestCase* current_test_case() const
      GTEST_LOCK_EXCLUDED_(mutex_);

  // Returns the TestInfo object for the test that's currently running,
  // or NULL if no test is running.
  const TestInfo* current_test_info() const
      GTEST_LOCK_EXCLUDED_(mutex_);

  // Returns the random seed used at the start of the current test run.
  int random_seed() const;

#if GTEST_HAS_PARAM_TEST
  // Returns the ParameterizedTestCaseRegistry object used to keep track of
  // value-parameterized tests and instantiate and register them.
  //
  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
  internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
      GTEST_LOCK_EXCLUDED_(mutex_);
#endif  // GTEST_HAS_PARAM_TEST

  // Gets the number of successful test cases.
  int successful_test_case_count() const;

  // Gets the number of failed test cases.
  int failed_test_case_count() const;

  // Gets the number of all test cases.
  int total_test_case_count() const;

  // Gets the number of all test cases that contain at least one test
  // that should run.
  int test_case_to_run_count() const;

  // Gets the number of successful tests.
  int successful_test_count() const;

  // Gets the number of failed tests.
  int failed_test_count() const;

  // Gets the number of disabled tests that will be reported in the XML report.
  int reportable_disabled_test_count() const;

  // Gets the number of disabled tests.
  int disabled_test_count() const;

  // Gets the number of tests to be printed in the XML report.
  int reportable_test_count() const;

  // Gets the number of all tests.
  int total_test_count() const;

  // Gets the number of tests that should run.
  int test_to_run_count() const;

  // Gets the time of the test program start, in ms from the start of the
  // UNIX epoch.
  TimeInMillis start_timestamp() const;

  // Gets the elapsed time, in milliseconds.
  TimeInMillis elapsed_time() const;

  // Returns true iff the unit test passed (i.e. all test cases passed).
  bool Passed() const;

  // Returns true iff the unit test failed (i.e. some test case failed
  // or something outside of all tests failed).
  bool Failed() const;

  // Gets the i-th test case among all the test cases. i can range from 0 to
  // total_test_case_count() - 1. If i is not in that range, returns NULL.
  const TestCase* GetTestCase(int i) const;

  // Returns the TestResult containing information on test failures and
  // properties logged outside of individual test cases.
  const TestResult& ad_hoc_test_result() const;

  // Returns the list of event listeners that can be used to track events
  // inside Google Test.
  TestEventListeners& listeners();

 private:
  // Registers and returns a global test environment.  When a test
  // program is run, all global test environments will be set-up in
  // the order they were registered.  After all tests in the program
  // have finished, all global test environments will be torn-down in
  // the *reverse* order they were registered.
  //
  // The UnitTest object takes ownership of the given environment.
  //
  // This method can only be called from the main thread.
  Environment* AddEnvironment(Environment* env);

  // Adds a TestPartResult to the current TestResult object.  All
  // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
  // eventually call this to report their results.  The user code
  // should use the assertion macros instead of calling this directly.
  void AddTestPartResult(TestPartResult::Type result_type,
                         const char* file_name,
                         int line_number,
                         const std::string& message,
                         const std::string& os_stack_trace)
      GTEST_LOCK_EXCLUDED_(mutex_);

  // Adds a TestProperty to the current TestResult object when invoked from
  // inside a test, to current TestCase's ad_hoc_test_result_ when invoked
  // from SetUpTestCase or TearDownTestCase, or to the global property set
  // when invoked elsewhere.  If the result already contains a property with
  // the same key, the value will be updated.
  void RecordProperty(const std::string& key, const std::string& value);

  // Gets the i-th test case among all the test cases. i can range from 0 to
  // total_test_case_count() - 1. If i is not in that range, returns NULL.
  TestCase* GetMutableTestCase(int i);

  // Accessors for the implementation object.
  internal::UnitTestImpl* impl() { return impl_; }
  const internal::UnitTestImpl* impl() const { return impl_; }

  // These classes and funcions are friends as they need to access private
  // members of UnitTest.
  friend class Test;
  friend class internal::AssertHelper;
  friend class internal::ScopedTrace;
  friend class internal::StreamingListenerTest;
  friend class internal::UnitTestRecordPropertyTestHelper;
  friend Environment* AddGlobalTestEnvironment(Environment* env);
  friend internal::UnitTestImpl* internal::GetUnitTestImpl();
  friend void internal::ReportFailureInUnknownLocation(
      TestPartResult::Type result_type,
      const std::string& message);

  // Creates an empty UnitTest.
  UnitTest();

  // D'tor
  virtual ~UnitTest();

  // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
  // Google Test trace stack.
  void PushGTestTrace(const internal::TraceInfo& trace)
      GTEST_LOCK_EXCLUDED_(mutex_);

  // Pops a trace from the per-thread Google Test trace stack.
  void PopGTestTrace()
      GTEST_LOCK_EXCLUDED_(mutex_);

  // Protects mutable state in *impl_.  This is mutable as some const
  // methods need to lock it too.
  mutable internal::Mutex mutex_;

  // Opaque implementation object.  This field is never changed once
  // the object is constructed.  We don't mark it as const here, as
  // doing so will cause a warning in the constructor of UnitTest.
  // Mutable state in *impl_ is protected by mutex_.
  internal::UnitTestImpl* impl_;

  // We disallow copying UnitTest.
  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
};

// A convenient wrapper for adding an environment for the test
// program.
//
// You should call this before RUN_ALL_TESTS() is called, probably in
// main().  If you use gtest_main, you need to call this before main()
// starts for it to take effect.  For example, you can define a global
// variable like this:
//
//   testing::Environment* const foo_env =
//       testing::AddGlobalTestEnvironment(new FooEnvironment);
//
// However, we strongly recommend you to write your own main() and
// call AddGlobalTestEnvironment() there, as relying on initialization
// of global variables makes the code harder to read and may cause
// problems when you register multiple environments from different
// translation units and the environments have dependencies among them
// (remember that the compiler doesn't guarantee the order in which
// global variables from different translation units are initialized).
inline Environment* AddGlobalTestEnvironment(Environment* env) {
  return UnitTest::GetInstance()->AddEnvironment(env);
}

// Initializes Google Test.  This must be called before calling
// RUN_ALL_TESTS().  In particular, it parses a command line for the
// flags that Google Test recognizes.  Whenever a Google Test flag is
// seen, it is removed from argv, and *argc is decremented.
//
// No value is returned.  Instead, the Google Test flag variables are
// updated.
//
// Calling the function for the second time has no user-visible effect.
GTEST_API_ void InitGoogleTest(int* argc, char** argv);

// This overloaded version can be used in Windows programs compiled in
// UNICODE mode.
GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);

namespace internal {

// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
// value of type ToPrint that is an operand of a comparison assertion
// (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
// the comparison, and is used to help determine the best way to
// format the value.  In particular, when the value is a C string
// (char pointer) and the other operand is an STL string object, we
// want to format the C string as a string, since we know it is
// compared by value with the string object.  If the value is a char
// pointer but the other operand is not an STL string object, we don't
// know whether the pointer is supposed to point to a NUL-terminated
// string, and thus want to print it as a pointer to be safe.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

// The default case.
template <typename ToPrint, typename OtherOperand>
class FormatForComparison {
 public:
  static ::std::string Format(const ToPrint& value) {
    return ::testing::PrintToString(value);
  }
};

// Array.
template <typename ToPrint, size_t N, typename OtherOperand>
class FormatForComparison<ToPrint[N], OtherOperand> {
 public:
  static ::std::string Format(const ToPrint* value) {
    return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
  }
};

// By default, print C string as pointers to be safe, as we don't know
// whether they actually point to a NUL-terminated string.

#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType)                \
  template <typename OtherOperand>                                      \
  class FormatForComparison<CharType*, OtherOperand> {                  \
   public:                                                              \
    static ::std::string Format(CharType* value) {                      \
      return ::testing::PrintToString(static_cast<const void*>(value)); \
    }                                                                   \
  }

GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);

#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_

// If a C string is compared with an STL string object, we know it's meant
// to point to a NUL-terminated string, and thus can print it as a string.

#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
  template <>                                                           \
  class FormatForComparison<CharType*, OtherStringType> {               \
   public:                                                              \
    static ::std::string Format(CharType* value) {                      \
      return ::testing::PrintToString(value);                           \
    }                                                                   \
  }

GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);

#if GTEST_HAS_GLOBAL_STRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
#endif

#if GTEST_HAS_GLOBAL_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
#endif

#if GTEST_HAS_STD_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
#endif

#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_

// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
// operand to be used in a failure message.  The type (but not value)
// of the other operand may affect the format.  This allows us to
// print a char* as a raw pointer when it is compared against another
// char* or void*, and print it as a C string when it is compared
// against an std::string object, for example.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
template <typename T1, typename T2>
std::string FormatForComparisonFailureMessage(
    const T1& value, const T2& /* other_operand */) {
  return FormatForComparison<T1, T2>::Format(value);
}

// The helper function for {ASSERT|EXPECT}_EQ.
template <typename T1, typename T2>
AssertionResult CmpHelperEQ(const char* expected_expression,
                            const char* actual_expression,
                            const T1& expected,
                            const T2& actual) {
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4389)  // Temporarily disables warning on
                                // signed/unsigned mismatch.
#endif

  if (expected == actual) {
    return AssertionSuccess();
  }

#ifdef _MSC_VER
# pragma warning(pop)          // Restores the warning state.
#endif

  return EqFailure(expected_expression,
                   actual_expression,
                   FormatForComparisonFailureMessage(expected, actual),
                   FormatForComparisonFailureMessage(actual, expected),
                   false);
}

// With this overloaded version, we allow anonymous enums to be used
// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
// can be implicitly cast to BiggestInt.
GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
                                       const char* actual_expression,
                                       BiggestInt expected,
                                       BiggestInt actual);

// The helper class for {ASSERT|EXPECT}_EQ.  The template argument
// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
// is a null pointer literal.  The following default implementation is
// for lhs_is_null_literal being false.
template <bool lhs_is_null_literal>
class EqHelper {
 public:
  // This templatized version is for the general case.
  template <typename T1, typename T2>
  static AssertionResult Compare(const char* expected_expression,
                                 const char* actual_expression,
                                 const T1& expected,
                                 const T2& actual) {
    return CmpHelperEQ(expected_expression, actual_expression, expected,
                       actual);
  }

  // With this overloaded version, we allow anonymous enums to be used
  // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
  // enums can be implicitly cast to BiggestInt.
  //
  // Even though its body looks the same as the above version, we
  // cannot merge the two, as it will make anonymous enums unhappy.
  static AssertionResult Compare(const char* expected_expression,
                                 const char* actual_expression,
                                 BiggestInt expected,
                                 BiggestInt actual) {
    return CmpHelperEQ(expected_expression, actual_expression, expected,
                       actual);
  }
};

// This specialization is used when the first argument to ASSERT_EQ()
// is a null pointer literal, like NULL, false, or 0.
template <>
class EqHelper<true> {
 public:
  // We define two overloaded versions of Compare().  The first
  // version will be picked when the second argument to ASSERT_EQ() is
  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
  // EXPECT_EQ(false, a_bool).
  template <typename T1, typename T2>
  static AssertionResult Compare(
      const char* expected_expression,
      const char* actual_expression,
      const T1& expected,
      const T2& actual,
      // The following line prevents this overload from being considered if T2
      // is not a pointer type.  We need this because ASSERT_EQ(NULL, my_ptr)
      // expands to Compare("", "", NULL, my_ptr), which requires a conversion
      // to match the Secret* in the other overload, which would otherwise make
      // this template match better.
      typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
    return CmpHelperEQ(expected_expression, actual_expression, expected,
                       actual);
  }

  // This version will be picked when the second argument to ASSERT_EQ() is a
  // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
  template <typename T>
  static AssertionResult Compare(
      const char* expected_expression,
      const char* actual_expression,
      // We used to have a second template parameter instead of Secret*.  That
      // template parameter would deduce to 'long', making this a better match
      // than the first overload even without the first overload's EnableIf.
      // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
      // non-pointer argument" (even a deduced integral argument), so the old
      // implementation caused warnings in user code.
      Secret* /* expected (NULL) */,
      T* actual) {
    // We already know that 'expected' is a null pointer.
    return CmpHelperEQ(expected_expression, actual_expression,
                       static_cast<T*>(NULL), actual);
  }
};

// A macro for implementing the helper functions needed to implement
// ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
// of similar code.
//
// For each templatized helper function, we also define an overloaded
// version for BiggestInt in order to reduce code bloat and allow
// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
// with gcc 4.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
template <typename T1, typename T2>\
AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
                                   const T1& val1, const T2& val2) {\
  if (val1 op val2) {\
    return AssertionSuccess();\
  } else {\
    return AssertionFailure() \
        << "Expected: (" << expr1 << ") " #op " (" << expr2\
        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
  }\
}\
GTEST_API_ AssertionResult CmpHelper##op_name(\
    const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)

// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

// Implements the helper function for {ASSERT|EXPECT}_NE
GTEST_IMPL_CMP_HELPER_(NE, !=);
// Implements the helper function for {ASSERT|EXPECT}_LE
GTEST_IMPL_CMP_HELPER_(LE, <=);
// Implements the helper function for {ASSERT|EXPECT}_LT
GTEST_IMPL_CMP_HELPER_(LT, <);
// Implements the helper function for {ASSERT|EXPECT}_GE
GTEST_IMPL_CMP_HELPER_(GE, >=);
// Implements the helper function for {ASSERT|EXPECT}_GT
GTEST_IMPL_CMP_HELPER_(GT, >);

#undef GTEST_IMPL_CMP_HELPER_

// The helper function for {ASSERT|EXPECT}_STREQ.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
                                          const char* actual_expression,
                                          const char* expected,
                                          const char* actual);

// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
                                              const char* actual_expression,
                                              const char* expected,
                                              const char* actual);

// The helper function for {ASSERT|EXPECT}_STRNE.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
                                          const char* s2_expression,
                                          const char* s1,
                                          const char* s2);

// The helper function for {ASSERT|EXPECT}_STRCASENE.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
                                              const char* s2_expression,
                                              const char* s1,
                                              const char* s2);


// Helper function for *_STREQ on wide strings.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
                                          const char* actual_expression,
                                          const wchar_t* expected,
                                          const wchar_t* actual);

// Helper function for *_STRNE on wide strings.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
                                          const char* s2_expression,
                                          const wchar_t* s1,
                                          const wchar_t* s2);

}  // namespace internal

// IsSubstring() and IsNotSubstring() are intended to be used as the
// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
// themselves.  They check whether needle is a substring of haystack
// (NULL is considered a substring of itself only), and return an
// appropriate error message when they fail.
//
// The {needle,haystack}_expr arguments are the stringified
// expressions that generated the two real arguments.
GTEST_API_ AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const char* needle, const char* haystack);
GTEST_API_ AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const wchar_t* needle, const wchar_t* haystack);
GTEST_API_ AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const char* needle, const char* haystack);
GTEST_API_ AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const wchar_t* needle, const wchar_t* haystack);
GTEST_API_ AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::string& needle, const ::std::string& haystack);
GTEST_API_ AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::string& needle, const ::std::string& haystack);

#if GTEST_HAS_STD_WSTRING
GTEST_API_ AssertionResult IsSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::wstring& needle, const ::std::wstring& haystack);
GTEST_API_ AssertionResult IsNotSubstring(
    const char* needle_expr, const char* haystack_expr,
    const ::std::wstring& needle, const ::std::wstring& haystack);
#endif  // GTEST_HAS_STD_WSTRING

namespace internal {

// Helper template function for comparing floating-points.
//
// Template parameter:
//
//   RawType: the raw floating-point type (either float or double)
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
template <typename RawType>
AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
                                         const char* actual_expression,
                                         RawType expected,
                                         RawType actual) {
  const FloatingPoint<RawType> lhs(expected), rhs(actual);

  if (lhs.AlmostEquals(rhs)) {
    return AssertionSuccess();
  }

  ::std::stringstream expected_ss;
  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
              << expected;

  ::std::stringstream actual_ss;
  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
            << actual;

  return EqFailure(expected_expression,
                   actual_expression,
                   StringStreamToString(&expected_ss),
                   StringStreamToString(&actual_ss),
                   false);
}

// Helper function for implementing ASSERT_NEAR.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
                                                const char* expr2,
                                                const char* abs_error_expr,
                                                double val1,
                                                double val2,
                                                double abs_error);

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
// A class that enables one to stream messages to assertion macros
class GTEST_API_ AssertHelper {
 public:
  // Constructor.
  AssertHelper(TestPartResult::Type type,
               const char* file,
               int line,
               const char* message);
  ~AssertHelper();

  // Message assignment is a semantic trick to enable assertion
  // streaming; see the GTEST_MESSAGE_ macro below.
  void operator=(const Message& message) const;

 private:
  // We put our data in a struct so that the size of the AssertHelper class can
  // be as small as possible.  This is important because gcc is incapable of
  // re-using stack space even for temporary variables, so every EXPECT_EQ
  // reserves stack space for another AssertHelper.
  struct AssertHelperData {
    AssertHelperData(TestPartResult::Type t,
                     const char* srcfile,
                     int line_num,
                     const char* msg)
        : type(t), file(srcfile), line(line_num), message(msg) { }

    TestPartResult::Type const type;
    const char* const file;
    int const line;
    std::string const message;

   private:
    GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
  };

  AssertHelperData* const data_;

  GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
};

}  // namespace internal

#if GTEST_HAS_PARAM_TEST
// The pure interface class that all value-parameterized tests inherit from.
// A value-parameterized class must inherit from both ::testing::Test and
// ::testing::WithParamInterface. In most cases that just means inheriting
// from ::testing::TestWithParam, but more complicated test hierarchies
// may need to inherit from Test and WithParamInterface at different levels.
//
// This interface has support for accessing the test parameter value via
// the GetParam() method.
//
// Use it with one of the parameter generator defining functions, like Range(),
// Values(), ValuesIn(), Bool(), and Combine().
//
// class FooTest : public ::testing::TestWithParam<int> {
//  protected:
//   FooTest() {
//     // Can use GetParam() here.
//   }
//   virtual ~FooTest() {
//     // Can use GetParam() here.
//   }
//   virtual void SetUp() {
//     // Can use GetParam() here.
//   }
//   virtual void TearDown {
//     // Can use GetParam() here.
//   }
// };
// TEST_P(FooTest, DoesBar) {
//   // Can use GetParam() method here.
//   Foo foo;
//   ASSERT_TRUE(foo.DoesBar(GetParam()));
// }
// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));

template <typename T>
class WithParamInterface {
 public:
  typedef T ParamType;
  virtual ~WithParamInterface() {}

  // The current parameter value. Is also available in the test fixture's
  // constructor. This member function is non-static, even though it only
  // references static data, to reduce the opportunity for incorrect uses
  // like writing 'WithParamInterface<bool>::GetParam()' for a test that
  // uses a fixture whose parameter type is int.
  const ParamType& GetParam() const {
    GTEST_CHECK_(parameter_ != NULL)
        << "GetParam() can only be called inside a value-parameterized test "
        << "-- did you intend to write TEST_P instead of TEST_F?";
    return *parameter_;
  }

 private:
  // Sets parameter value. The caller is responsible for making sure the value
  // remains alive and unchanged throughout the current test.
  static void SetParam(const ParamType* parameter) {
    parameter_ = parameter;
  }

  // Static value used for accessing parameter during a test lifetime.
  static const ParamType* parameter_;

  // TestClass must be a subclass of WithParamInterface<T> and Test.
  template <class TestClass> friend class internal::ParameterizedTestFactory;
};

template <typename T>
const T* WithParamInterface<T>::parameter_ = NULL;

// Most value-parameterized classes can ignore the existence of
// WithParamInterface, and can just inherit from ::testing::TestWithParam.

template <typename T>
class TestWithParam : public Test, public WithParamInterface<T> {
};

#endif  // GTEST_HAS_PARAM_TEST

// Macros for indicating success/failure in test code.

// ADD_FAILURE unconditionally adds a failure to the current test.
// SUCCEED generates a success - it doesn't automatically make the
// current test successful, as a test is only successful when it has
// no failure.
//
// EXPECT_* verifies that a certain condition is satisfied.  If not,
// it behaves like ADD_FAILURE.  In particular:
//
//   EXPECT_TRUE  verifies that a Boolean condition is true.
//   EXPECT_FALSE verifies that a Boolean condition is false.
//
// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
// that they will also abort the current function on failure.  People
// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
// writing data-driven tests often find themselves using ADD_FAILURE
// and EXPECT_* more.

// Generates a nonfatal failure with a generic message.
#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")

// Generates a nonfatal failure at the given source file location with
// a generic message.
#define ADD_FAILURE_AT(file, line) \
  GTEST_MESSAGE_AT_(file, line, "Failed", \
                    ::testing::TestPartResult::kNonFatalFailure)

// Generates a fatal failure with a generic message.
#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")

// Define this macro to 1 to omit the definition of FAIL(), which is a
// generic name and clashes with some other libraries.
#if !GTEST_DONT_DEFINE_FAIL
# define FAIL() GTEST_FAIL()
#endif

// Generates a success with a generic message.
#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")

// Define this macro to 1 to omit the definition of SUCCEED(), which
// is a generic name and clashes with some other libraries.
#if !GTEST_DONT_DEFINE_SUCCEED
# define SUCCEED() GTEST_SUCCEED()
#endif

// Macros for testing exceptions.
//
//    * {ASSERT|EXPECT}_THROW(statement, expected_exception):
//         Tests that the statement throws the expected exception.
//    * {ASSERT|EXPECT}_NO_THROW(statement):
//         Tests that the statement doesn't throw any exception.
//    * {ASSERT|EXPECT}_ANY_THROW(statement):
//         Tests that the statement throws an exception.

#define EXPECT_THROW(statement, expected_exception) \
  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
#define EXPECT_NO_THROW(statement) \
  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
#define EXPECT_ANY_THROW(statement) \
  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
#define ASSERT_THROW(statement, expected_exception) \
  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
#define ASSERT_NO_THROW(statement) \
  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
#define ASSERT_ANY_THROW(statement) \
  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)

// Boolean assertions. Condition can be either a Boolean expression or an
// AssertionResult. For more information on how to use AssertionResult with
// these macros see comments on that class.
#define EXPECT_TRUE(condition) \
  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
                      GTEST_NONFATAL_FAILURE_)
#define EXPECT_FALSE(condition) \
  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                      GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \
  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
                      GTEST_FATAL_FAILURE_)
#define ASSERT_FALSE(condition) \
  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                      GTEST_FATAL_FAILURE_)

// Includes the auto-generated header that implements a family of
// generic predicate assertion macros.
// Copyright 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
// 'gen_gtest_pred_impl.py 5'.  DO NOT EDIT BY HAND!
//
// Implements a family of generic predicate assertion macros.

#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_

// Makes sure this header is not included before gtest.h.
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
# error Do not include gtest_pred_impl.h directly.  Include gtest.h instead.
#endif  // GTEST_INCLUDE_GTEST_GTEST_H_

// This header implements a family of generic predicate assertion
// macros:
//
//   ASSERT_PRED_FORMAT1(pred_format, v1)
//   ASSERT_PRED_FORMAT2(pred_format, v1, v2)
//   ...
//
// where pred_format is a function or functor that takes n (in the
// case of ASSERT_PRED_FORMATn) values and their source expression
// text, and returns a testing::AssertionResult.  See the definition
// of ASSERT_EQ in gtest.h for an example.
//
// If you don't care about formatting, you can use the more
// restrictive version:
//
//   ASSERT_PRED1(pred, v1)
//   ASSERT_PRED2(pred, v1, v2)
//   ...
//
// where pred is an n-ary function or functor that returns bool,
// and the values v1, v2, ..., must support the << operator for
// streaming to std::ostream.
//
// We also define the EXPECT_* variations.
//
// For now we only support predicates whose arity is at most 5.
// Please email googletestframework@googlegroups.com if you need
// support for higher arities.

// GTEST_ASSERT_ is the basic statement to which all of the assertions
// in this file reduce.  Don't use this in your code.

#define GTEST_ASSERT_(expression, on_failure) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (const ::testing::AssertionResult gtest_ar = (expression)) \
    ; \
  else \
    on_failure(gtest_ar.failure_message())


// Helper function for implementing {EXPECT|ASSERT}_PRED1.  Don't use
// this in your code.
template <typename Pred,
          typename T1>
AssertionResult AssertPred1Helper(const char* pred_text,
                                  const char* e1,
                                  Pred pred,
                                  const T1& v1) {
  if (pred(v1)) return AssertionSuccess();

  return AssertionFailure() << pred_text << "("
                            << e1 << ") evaluates to false, where"
                            << "\n" << e1 << " evaluates to " << v1;
}

// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
// Don't use this in your code.
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
  GTEST_ASSERT_(pred_format(#v1, v1), \
                on_failure)

// Internal macro for implementing {EXPECT|ASSERT}_PRED1.  Don't use
// this in your code.
#define GTEST_PRED1_(pred, v1, on_failure)\
  GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
                                             #v1, \
                                             pred, \
                                             v1), on_failure)

// Unary predicate assertion macros.
#define EXPECT_PRED_FORMAT1(pred_format, v1) \
  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED1(pred, v1) \
  GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT1(pred_format, v1) \
  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED1(pred, v1) \
  GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)



// Helper function for implementing {EXPECT|ASSERT}_PRED2.  Don't use
// this in your code.
template <typename Pred,
          typename T1,
          typename T2>
AssertionResult AssertPred2Helper(const char* pred_text,
                                  const char* e1,
                                  const char* e2,
                                  Pred pred,
                                  const T1& v1,
                                  const T2& v2) {
  if (pred(v1, v2)) return AssertionSuccess();

  return AssertionFailure() << pred_text << "("
                            << e1 << ", "
                            << e2 << ") evaluates to false, where"
                            << "\n" << e1 << " evaluates to " << v1
                            << "\n" << e2 << " evaluates to " << v2;
}

// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
// Don't use this in your code.
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
  GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
                on_failure)

// Internal macro for implementing {EXPECT|ASSERT}_PRED2.  Don't use
// this in your code.
#define GTEST_PRED2_(pred, v1, v2, on_failure)\
  GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
                                             #v1, \
                                             #v2, \
                                             pred, \
                                             v1, \
                                             v2), on_failure)

// Binary predicate assertion macros.
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED2(pred, v1, v2) \
  GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED2(pred, v1, v2) \
  GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)



// Helper function for implementing {EXPECT|ASSERT}_PRED3.  Don't use
// this in your code.
template <typename Pred,
          typename T1,
          typename T2,
          typename T3>
AssertionResult AssertPred3Helper(const char* pred_text,
                                  const char* e1,
                                  const char* e2,
                                  const char* e3,
                                  Pred pred,
                                  const T1& v1,
                                  const T2& v2,
                                  const T3& v3) {
  if (pred(v1, v2, v3)) return AssertionSuccess();

  return AssertionFailure() << pred_text << "("
                            << e1 << ", "
                            << e2 << ", "
                            << e3 << ") evaluates to false, where"
                            << "\n" << e1 << " evaluates to " << v1
                            << "\n" << e2 << " evaluates to " << v2
                            << "\n" << e3 << " evaluates to " << v3;
}

// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
// Don't use this in your code.
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
                on_failure)

// Internal macro for implementing {EXPECT|ASSERT}_PRED3.  Don't use
// this in your code.
#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
  GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
                                             #v1, \
                                             #v2, \
                                             #v3, \
                                             pred, \
                                             v1, \
                                             v2, \
                                             v3), on_failure)

// Ternary predicate assertion macros.
#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED3(pred, v1, v2, v3) \
  GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED3(pred, v1, v2, v3) \
  GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)



// Helper function for implementing {EXPECT|ASSERT}_PRED4.  Don't use
// this in your code.
template <typename Pred,
          typename T1,
          typename T2,
          typename T3,
          typename T4>
AssertionResult AssertPred4Helper(const char* pred_text,
                                  const char* e1,
                                  const char* e2,
                                  const char* e3,
                                  const char* e4,
                                  Pred pred,
                                  const T1& v1,
                                  const T2& v2,
                                  const T3& v3,
                                  const T4& v4) {
  if (pred(v1, v2, v3, v4)) return AssertionSuccess();

  return AssertionFailure() << pred_text << "("
                            << e1 << ", "
                            << e2 << ", "
                            << e3 << ", "
                            << e4 << ") evaluates to false, where"
                            << "\n" << e1 << " evaluates to " << v1
                            << "\n" << e2 << " evaluates to " << v2
                            << "\n" << e3 << " evaluates to " << v3
                            << "\n" << e4 << " evaluates to " << v4;
}

// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
// Don't use this in your code.
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
                on_failure)

// Internal macro for implementing {EXPECT|ASSERT}_PRED4.  Don't use
// this in your code.
#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
  GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
                                             #v1, \
                                             #v2, \
                                             #v3, \
                                             #v4, \
                                             pred, \
                                             v1, \
                                             v2, \
                                             v3, \
                                             v4), on_failure)

// 4-ary predicate assertion macros.
#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)



// Helper function for implementing {EXPECT|ASSERT}_PRED5.  Don't use
// this in your code.
template <typename Pred,
          typename T1,
          typename T2,
          typename T3,
          typename T4,
          typename T5>
AssertionResult AssertPred5Helper(const char* pred_text,
                                  const char* e1,
                                  const char* e2,
                                  const char* e3,
                                  const char* e4,
                                  const char* e5,
                                  Pred pred,
                                  const T1& v1,
                                  const T2& v2,
                                  const T3& v3,
                                  const T4& v4,
                                  const T5& v5) {
  if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();

  return AssertionFailure() << pred_text << "("
                            << e1 << ", "
                            << e2 << ", "
                            << e3 << ", "
                            << e4 << ", "
                            << e5 << ") evaluates to false, where"
                            << "\n" << e1 << " evaluates to " << v1
                            << "\n" << e2 << " evaluates to " << v2
                            << "\n" << e3 << " evaluates to " << v3
                            << "\n" << e4 << " evaluates to " << v4
                            << "\n" << e5 << " evaluates to " << v5;
}

// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
// Don't use this in your code.
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
                on_failure)

// Internal macro for implementing {EXPECT|ASSERT}_PRED5.  Don't use
// this in your code.
#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
  GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
                                             #v1, \
                                             #v2, \
                                             #v3, \
                                             #v4, \
                                             #v5, \
                                             pred, \
                                             v1, \
                                             v2, \
                                             v3, \
                                             v4, \
                                             v5), on_failure)

// 5-ary predicate assertion macros.
#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)



#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_

// Macros for testing equalities and inequalities.
//
//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
//
// When they are not, Google Test prints both the tested expressions and
// their actual values.  The values must be compatible built-in types,
// or you will get a compiler error.  By "compatible" we mean that the
// values can be compared by the respective operator.
//
// Note:
//
//   1. It is possible to make a user-defined type work with
//   {ASSERT|EXPECT}_??(), but that requires overloading the
//   comparison operators and is thus discouraged by the Google C++
//   Usage Guide.  Therefore, you are advised to use the
//   {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
//   equal.
//
//   2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
//   pointers (in particular, C strings).  Therefore, if you use it
//   with two C strings, you are testing how their locations in memory
//   are related, not how their content is related.  To compare two C
//   strings by content, use {ASSERT|EXPECT}_STR*().
//
//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
//   what the actual value is when it fails, and similarly for the
//   other comparisons.
//
//   4. Do not depend on the order in which {ASSERT|EXPECT}_??()
//   evaluate their arguments, which is undefined.
//
//   5. These macros evaluate their arguments exactly once.
//
// Examples:
//
//   EXPECT_NE(5, Foo());
//   EXPECT_EQ(NULL, a_pointer);
//   ASSERT_LT(i, array_size);
//   ASSERT_GT(records.size(), 0) << "There is no record left.";

#define EXPECT_EQ(expected, actual) \
  EXPECT_PRED_FORMAT2(::testing::internal:: \
                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
                      expected, actual)
#define EXPECT_NE(expected, actual) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
#define EXPECT_LE(val1, val2) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
#define EXPECT_LT(val1, val2) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
#define EXPECT_GE(val1, val2) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
#define EXPECT_GT(val1, val2) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)

#define GTEST_ASSERT_EQ(expected, actual) \
  ASSERT_PRED_FORMAT2(::testing::internal:: \
                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
                      expected, actual)
#define GTEST_ASSERT_NE(val1, val2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
#define GTEST_ASSERT_LE(val1, val2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
#define GTEST_ASSERT_LT(val1, val2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
#define GTEST_ASSERT_GE(val1, val2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
#define GTEST_ASSERT_GT(val1, val2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)

// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
// ASSERT_XY(), which clashes with some users' own code.

#if !GTEST_DONT_DEFINE_ASSERT_EQ
# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
#endif

#if !GTEST_DONT_DEFINE_ASSERT_NE
# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
#endif

#if !GTEST_DONT_DEFINE_ASSERT_LE
# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
#endif

#if !GTEST_DONT_DEFINE_ASSERT_LT
# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
#endif

#if !GTEST_DONT_DEFINE_ASSERT_GE
# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
#endif

#if !GTEST_DONT_DEFINE_ASSERT_GT
# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
#endif

// C-string Comparisons.  All tests treat NULL and any non-NULL string
// as different.  Two NULLs are equal.
//
//    * {ASSERT|EXPECT}_STREQ(s1, s2):     Tests that s1 == s2
//    * {ASSERT|EXPECT}_STRNE(s1, s2):     Tests that s1 != s2
//    * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
//    * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
//
// For wide or narrow string objects, you can use the
// {ASSERT|EXPECT}_??() macros.
//
// Don't depend on the order in which the arguments are evaluated,
// which is undefined.
//
// These macros evaluate their arguments exactly once.

#define EXPECT_STREQ(expected, actual) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
#define EXPECT_STRNE(s1, s2) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
#define EXPECT_STRCASEEQ(expected, actual) \
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
#define EXPECT_STRCASENE(s1, s2)\
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)

#define ASSERT_STREQ(expected, actual) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
#define ASSERT_STRNE(s1, s2) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
#define ASSERT_STRCASEEQ(expected, actual) \
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
#define ASSERT_STRCASENE(s1, s2)\
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)

// Macros for comparing floating-point numbers.
//
//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
//         Tests that two float values are almost equal.
//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
//         Tests that two double values are almost equal.
//    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
//         Tests that v1 and v2 are within the given distance to each other.
//
// Google Test uses ULP-based comparison to automatically pick a default
// error bound that is appropriate for the operands.  See the
// FloatingPoint template class in gtest-internal.h if you are
// interested in the implementation details.

#define EXPECT_FLOAT_EQ(expected, actual)\
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
                      expected, actual)

#define EXPECT_DOUBLE_EQ(expected, actual)\
  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
                      expected, actual)

#define ASSERT_FLOAT_EQ(expected, actual)\
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
                      expected, actual)

#define ASSERT_DOUBLE_EQ(expected, actual)\
  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
                      expected, actual)

#define EXPECT_NEAR(val1, val2, abs_error)\
  EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
                      val1, val2, abs_error)

#define ASSERT_NEAR(val1, val2, abs_error)\
  ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
                      val1, val2, abs_error)

// These predicate format functions work on floating-point values, and
// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
//
//   EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);

// Asserts that val1 is less than, or almost equal to, val2.  Fails
// otherwise.  In particular, it fails if either val1 or val2 is NaN.
GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
                                   float val1, float val2);
GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
                                    double val1, double val2);


#if GTEST_OS_WINDOWS

// Macros that test for HRESULT failure and success, these are only useful
// on Windows, and rely on Windows SDK macros and APIs to compile.
//
//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
//
// When expr unexpectedly fails or succeeds, Google Test prints the
// expected result and the actual result with both a human-readable
// string representation of the error, if available, as well as the
// hex result code.
# define EXPECT_HRESULT_SUCCEEDED(expr) \
    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

# define ASSERT_HRESULT_SUCCEEDED(expr) \
    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

# define EXPECT_HRESULT_FAILED(expr) \
    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

# define ASSERT_HRESULT_FAILED(expr) \
    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

#endif  // GTEST_OS_WINDOWS

// Macros that execute statement and check that it doesn't generate new fatal
// failures in the current thread.
//
//   * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
//
// Examples:
//
//   EXPECT_NO_FATAL_FAILURE(Process());
//   ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
//
#define ASSERT_NO_FATAL_FAILURE(statement) \
    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
#define EXPECT_NO_FATAL_FAILURE(statement) \
    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)

// Causes a trace (including the source file path, the current line
// number, and the given message) to be included in every test failure
// message generated by code in the current scope.  The effect is
// undone when the control leaves the current scope.
//
// The message argument can be anything streamable to std::ostream.
//
// In the implementation, we include the current line number as part
// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
// to appear in the same block - as long as they are on different
// lines.
#define SCOPED_TRACE(message) \
  ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
    __FILE__, __LINE__, ::testing::Message() << (message))

// Compile-time assertion for type equality.
// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
// the same type.  The value it returns is not interesting.
//
// Instead of making StaticAssertTypeEq a class template, we make it a
// function template that invokes a helper class template.  This
// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
// defining objects of that type.
//
// CAVEAT:
//
// When used inside a method of a class template,
// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
// instantiated.  For example, given:
//
//   template <typename T> class Foo {
//    public:
//     void Bar() { testing::StaticAssertTypeEq<int, T>(); }
//   };
//
// the code:
//
//   void Test1() { Foo<bool> foo; }
//
// will NOT generate a compiler error, as Foo<bool>::Bar() is never
// actually instantiated.  Instead, you need:
//
//   void Test2() { Foo<bool> foo; foo.Bar(); }
//
// to cause a compiler error.
template <typename T1, typename T2>
bool StaticAssertTypeEq() {
  (void)internal::StaticAssertTypeEqHelper<T1, T2>();
  return true;
}

// Defines a test.
//
// The first parameter is the name of the test case, and the second
// parameter is the name of the test within the test case.
//
// The convention is to end the test case name with "Test".  For
// example, a test case for the Foo class can be named FooTest.
//
// The user should put his test code between braces after using this
// macro.  Example:
//
//   TEST(FooTest, InitializesCorrectly) {
//     Foo foo;
//     EXPECT_TRUE(foo.StatusIsOK());
//   }

// Note that we call GetTestTypeId() instead of GetTypeId<
// ::testing::Test>() here to get the type ID of testing::Test.  This
// is to work around a suspected linker bug when using Google Test as
// a framework on Mac OS X.  The bug causes GetTypeId<
// ::testing::Test>() to return different values depending on whether
// the call is from the Google Test framework itself or from user test
// code.  GetTestTypeId() is guaranteed to always return the same
// value, as it always calls GetTypeId<>() from the Google Test
// framework.
#define GTEST_TEST(test_case_name, test_name)\
  GTEST_TEST_(test_case_name, test_name, \
              ::testing::Test, ::testing::internal::GetTestTypeId())

// Define this macro to 1 to omit the definition of TEST(), which
// is a generic name and clashes with some other libraries.
#if !GTEST_DONT_DEFINE_TEST
# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
#endif

// Defines a test that uses a test fixture.
//
// The first parameter is the name of the test fixture class, which
// also doubles as the test case name.  The second parameter is the
// name of the test within the test case.
//
// A test fixture class must be declared earlier.  The user should put
// his test code between braces after using this macro.  Example:
//
//   class FooTest : public testing::Test {
//    protected:
//     virtual void SetUp() { b_.AddElement(3); }
//
//     Foo a_;
//     Foo b_;
//   };
//
//   TEST_F(FooTest, InitializesCorrectly) {
//     EXPECT_TRUE(a_.StatusIsOK());
//   }
//
//   TEST_F(FooTest, ReturnsElementCountCorrectly) {
//     EXPECT_EQ(0, a_.size());
//     EXPECT_EQ(1, b_.size());
//   }

#define TEST_F(test_fixture, test_name)\
  GTEST_TEST_(test_fixture, test_name, test_fixture, \
              ::testing::internal::GetTypeId<test_fixture>())

}  // namespace testing

// Use this function in main() to run all tests.  It returns 0 if all
// tests are successful, or 1 otherwise.
//
// RUN_ALL_TESTS() should be invoked after the command line has been
// parsed by InitGoogleTest().
//
// This function was formerly a macro; thus, it is in the global
// namespace and has an all-caps name.
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;

inline int RUN_ALL_TESTS() {
  return ::testing::UnitTest::GetInstance()->Run();
}

#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
UnitTests
/*
	Audio File Library
	Copyright (C) 1998-2000, 2003-2004, 2010-2013, Michael Pruett <michael@68k.org>
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	AIFF.cpp

	This file contains routines for reading and writing AIFF and
	AIFF-C sound files.
*/

#include "config.h"
#include "AIFF.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Instrument.h"
#include "Marker.h"
#include "Setup.h"
#include "Tag.h"
#include "Track.h"
#include "byteorder.h"
#include "extended.h"
#include "util.h"

const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS] =
{
	{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
	{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
	{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
	{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
	{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
	{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
	{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} },
	{ AF_INST_SUSLOOPID, AU_PVTYPE_LONG, "Sustain loop id", {0} },
	{ AF_INST_RELLOOPID, AU_PVTYPE_LONG, "Release loop id", {0} }
};

const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW,
	AF_COMPRESSION_IMA
};

static const _AFfilesetup aiffDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_AIFF,		/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	1,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

#define AIFC_VERSION_1 0xa2805140

struct _INST
{
	uint8_t		baseNote;
	int8_t		detune;
	uint8_t		lowNote, highNote;
	uint8_t		lowVelocity, highVelocity;
	int16_t		gain;

	uint16_t	sustainLoopPlayMode;
	uint16_t	sustainLoopBegin;
	uint16_t	sustainLoopEnd;

	uint16_t	releaseLoopPlayMode;
	uint16_t	releaseLoopBegin;
	uint16_t	releaseLoopEnd;
};

AIFFFile::AIFFFile()
{
	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);

	m_miscellaneousPosition = 0;
	m_FVER_offset = 0;
	m_COMM_offset = 0;
	m_MARK_offset = 0;
	m_INST_offset = 0;
	m_AESD_offset = 0;
	m_SSND_offset = 0;
}

/*
	FVER chunks are only present in AIFF-C files.
*/
status AIFFFile::parseFVER(const Tag &type, size_t size)
{
	assert(type == "FVER");

	uint32_t timestamp;
	readU32(&timestamp);
	/* timestamp holds the number of seconds since January 1, 1904. */

	return AF_SUCCEED;
}

/*
	Parse AES recording data.
*/
status AIFFFile::parseAESD(const Tag &type, size_t size)
{
	unsigned char aesChannelStatusData[24];

	assert(type == "AESD");
	assert(size == 24);

	Track *track = getTrack();

	track->hasAESData = true;

	/*
		Try to read 24 bytes of AES nonaudio data from the file.
		Fail if the file disappoints.
	*/
	if (m_fh->read(aesChannelStatusData, 24) != 24)
		return AF_FAIL;

	memcpy(track->aesData, aesChannelStatusData, 24);

	return AF_SUCCEED;
}

/*
	Parse miscellaneous data chunks such as name, author, copyright,
	and annotation chunks.
*/
status AIFFFile::parseMiscellaneous(const Tag &type, size_t size)
{
	int misctype = AF_MISC_UNRECOGNIZED;

	assert(type == "NAME" ||
		type == "AUTH" ||
		type == "(c) " ||
		type == "ANNO" ||
		type == "APPL" ||
		type == "MIDI");

	/* Skip zero-length miscellaneous chunks. */
	if (size == 0)
		return AF_FAIL;

	m_miscellaneousCount++;
	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
		m_miscellaneousCount * sizeof (Miscellaneous));

	if (type == "NAME")
		misctype = AF_MISC_NAME;
	else if (type == "AUTH")
		misctype = AF_MISC_AUTH;
	else if (type == "(c) ")
		misctype = AF_MISC_COPY;
	else if (type == "ANNO")
		misctype = AF_MISC_ANNO;
	else if (type == "APPL")
		misctype = AF_MISC_APPL;
	else if (type == "MIDI")
		misctype = AF_MISC_MIDI;

	m_miscellaneous[m_miscellaneousCount - 1].id = m_miscellaneousCount;
	m_miscellaneous[m_miscellaneousCount - 1].type = misctype;
	m_miscellaneous[m_miscellaneousCount - 1].size = size;
	m_miscellaneous[m_miscellaneousCount - 1].position = 0;
	m_miscellaneous[m_miscellaneousCount - 1].buffer = _af_malloc(size);
	m_fh->read(m_miscellaneous[m_miscellaneousCount - 1].buffer, size);

	return AF_SUCCEED;
}

/*
	Parse instrument chunks, which contain information about using
	sound data as a sampled instrument.
*/
status AIFFFile::parseINST(const Tag &type, size_t size)
{
	uint8_t baseNote;
	int8_t detune;
	uint8_t lowNote, highNote, lowVelocity, highVelocity;
	int16_t gain;

	uint16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd;
	uint16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd;

	Instrument *instrument = (Instrument *) _af_calloc(1, sizeof (Instrument));
	instrument->id = AF_DEFAULT_INST;
	instrument->values = (AFPVu *) _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu));
	instrument->loopCount = 2;
	instrument->loops = (Loop *) _af_calloc(2, sizeof (Loop));

	m_instrumentCount = 1;
	m_instruments = instrument;

	readU8(&baseNote);
	readS8(&detune);
	readU8(&lowNote);
	readU8(&highNote);
	readU8(&lowVelocity);
	readU8(&highVelocity);
	readS16(&gain);

	instrument->values[0].l = baseNote;
	instrument->values[1].l = detune;
	instrument->values[2].l = lowVelocity;
	instrument->values[3].l = highVelocity;
	instrument->values[4].l = lowNote;
	instrument->values[5].l = highNote;
	instrument->values[6].l = gain;

	instrument->values[7].l = 1;	/* sustain loop id */
	instrument->values[8].l = 2;	/* release loop id */

	readU16(&sustainLoopPlayMode);
	readU16(&sustainLoopBegin);
	readU16(&sustainLoopEnd);

	readU16(&releaseLoopPlayMode);
	readU16(&releaseLoopBegin);
	readU16(&releaseLoopEnd);

	instrument->loops[0].id = 1;
	instrument->loops[0].mode = sustainLoopPlayMode;
	instrument->loops[0].beginMarker = sustainLoopBegin;
	instrument->loops[0].endMarker = sustainLoopEnd;
	instrument->loops[0].trackid = AF_DEFAULT_TRACK;

	instrument->loops[1].id = 2;
	instrument->loops[1].mode = releaseLoopPlayMode;
	instrument->loops[1].beginMarker = releaseLoopBegin;
	instrument->loops[1].endMarker = releaseLoopEnd;
	instrument->loops[1].trackid = AF_DEFAULT_TRACK;

	return AF_SUCCEED;
}

/*
	Parse marker chunks, which contain the positions and names of loop markers.
*/
status AIFFFile::parseMARK(const Tag &type, size_t size)
{
	assert(type == "MARK");

	Track *track = getTrack();

	uint16_t numMarkers;
	readU16(&numMarkers);

	track->markerCount = numMarkers;
	if (numMarkers)
		track->markers = _af_marker_new(numMarkers);

	for (unsigned i=0; i<numMarkers; i++)
	{
		uint16_t markerID = 0;
		uint32_t markerPosition = 0;
		uint8_t sizeByte = 0;
		char *markerName = NULL;

		readU16(&markerID);
		readU32(&markerPosition);
		m_fh->read(&sizeByte, 1);
		markerName = (char *) _af_malloc(sizeByte + 1);
		m_fh->read(markerName, sizeByte);

		markerName[sizeByte] = '\0';

		/*
			If sizeByte is even, then 1+sizeByte (the length
			of the string) is odd.	Skip an extra byte to
			make it even.
		*/

		if ((sizeByte % 2) == 0)
			m_fh->seek(1, File::SeekFromCurrent);

		track->markers[i].id = markerID;
		track->markers[i].position = markerPosition;
		track->markers[i].name = markerName;
		track->markers[i].comment = _af_strdup("");
	}

	return AF_SUCCEED;
}

/*
	Parse common data chunks, which contain information regarding the
	sampling rate, the number of sample frames, and the number of
	sound channels.
*/
status AIFFFile::parseCOMM(const Tag &type, size_t size)
{
	assert(type == "COMM");

	Track *track = getTrack();

	uint16_t numChannels;
	uint32_t numSampleFrames;
	uint16_t sampleSize;
	unsigned char sampleRate[10];

	readU16(&numChannels);
	track->f.channelCount = numChannels;

	if (!numChannels)
	{
		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
		return AF_FAIL;
	}

	readU32(&numSampleFrames);
	track->totalfframes = numSampleFrames;

	readU16(&sampleSize);
	track->f.sampleWidth = sampleSize;

	m_fh->read(sampleRate, 10);
	track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate);

	track->f.compressionType = AF_COMPRESSION_NONE;
	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	track->f.framesPerPacket = 1;

	if (isAIFFC())
	{
		Tag compressionID;
		// Pascal strings are at most 255 bytes long.
		char compressionName[256];

		readTag(&compressionID);

		// Read the Pascal-style string containing the name.
		readPString(compressionName);

		if (compressionID == "NONE" || compressionID == "twos")
		{
			track->f.compressionType = AF_COMPRESSION_NONE;
		}
		else if (compressionID == "in24")
		{
			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.sampleWidth = 24;
		}
		else if (compressionID == "in32")
		{
			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.sampleWidth = 32;
		}
		else if (compressionID == "ACE2" ||
			compressionID == "ACE8" ||
			compressionID == "MAC3" ||
			compressionID == "MAC6")
		{
			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName);
			return AF_FAIL;
		}
		else if (compressionID == "ulaw" || compressionID == "ULAW")
		{
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.sampleWidth = 16;
			track->f.bytesPerPacket = track->f.channelCount;
		}
		else if (compressionID == "alaw" || compressionID == "ALAW")
		{
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.sampleWidth = 16;
			track->f.bytesPerPacket = track->f.channelCount;
		}
		else if (compressionID == "fl32" || compressionID == "FL32")
		{
			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
			track->f.sampleWidth = 32;
			track->f.compressionType = AF_COMPRESSION_NONE;
		}
		else if (compressionID == "fl64" || compressionID == "FL64")
		{
			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
			track->f.sampleWidth = 64;
			track->f.compressionType = AF_COMPRESSION_NONE;
		}
		else if (compressionID == "sowt")
		{
			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
		}
		else if (compressionID == "ima4")
		{
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.compressionType = AF_COMPRESSION_IMA;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;

			initIMACompressionParams();

			track->totalfframes *= 64;
		}
		else
		{
			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%s' not currently supported",
				compressionID.name().c_str());
			return AF_FAIL;
		}
	}

	if (track->f.isUncompressed())
		track->f.computeBytesPerPacketPCM();

	if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
		return AF_FAIL;

	return AF_SUCCEED;
}

/*
	Parse the stored sound chunk, which usually contains little more
	than the sound data.
*/
status AIFFFile::parseSSND(const Tag &type, size_t size)
{
	assert(type == "SSND");

	Track *track = getTrack();

	uint32_t offset, blockSize;
	readU32(&offset);
	readU32(&blockSize);

	track->data_size = size - 8 - offset;

	track->fpos_first_frame = m_fh->tell() + offset;

	return AF_SUCCEED;
}

status AIFFFile::readInit(AFfilesetup setup)
{
	uint32_t type, size, formtype;

	bool hasCOMM = false;
	bool hasFVER = false;
	bool hasSSND = false;

	m_fh->seek(0, File::SeekFromBeginning);

	m_fh->read(&type, 4);
	readU32(&size);
	m_fh->read(&formtype, 4);

	if (memcmp(&type, "FORM", 4) != 0 ||
		(memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4)))
		return AF_FAIL;

	if (!allocateTrack())
		return AF_FAIL;

	/* Include the offset of the form type. */
	size_t index = 4;
	while (index < size)
	{
		Tag chunkid;
		uint32_t chunksize = 0;
		status result = AF_SUCCEED;

		readTag(&chunkid);
		readU32(&chunksize);

		if (chunkid == "COMM")
		{
			hasCOMM = true;
			result = parseCOMM(chunkid, chunksize);
		}
		else if (chunkid == "FVER")
		{
			hasFVER = true;
			parseFVER(chunkid, chunksize);
		}
		else if (chunkid == "INST")
		{
			parseINST(chunkid, chunksize);
		}
		else if (chunkid == "MARK")
		{
			parseMARK(chunkid, chunksize);
		}
		else if (chunkid == "AESD")
		{
			parseAESD(chunkid, chunksize);
		}
		else if (chunkid == "NAME" ||
			chunkid == "AUTH" ||
			chunkid == "(c) " ||
			chunkid == "ANNO" ||
			chunkid == "APPL" ||
			chunkid == "MIDI")
		{
			parseMiscellaneous(chunkid, chunksize);
		}
		/*
			The sound data chunk is required if there are more than
			zero sample frames.
		*/
		else if (chunkid == "SSND")
		{
			if (hasSSND)
			{
				_af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk");
				return AF_FAIL;
			}
			hasSSND = true;
			result = parseSSND(chunkid, chunksize);
		}

		if (result == AF_FAIL)
			return AF_FAIL;

		index += chunksize + 8;

		/* all chunks must be aligned on an even number of bytes */
		if ((index % 2) != 0)
			index++;

		m_fh->seek(index + 8, File::SeekFromBeginning);
	}

	if (!hasCOMM)
	{
		_af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk");
	}

	if (isAIFFC() && !hasFVER)
	{
		_af_error(AF_BAD_HEADER, "FVER chunk is required in AIFF-C");
	}

	/* The file has been successfully parsed. */
	return AF_SUCCEED;
}

bool AIFFFile::recognizeAIFF(File *fh)
{
	uint8_t buffer[8];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
		return false;
	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFF", 4) != 0)
		return false;

	return true;
}

bool AIFFFile::recognizeAIFFC(File *fh)
{
	uint8_t buffer[8];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
		return false;
	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFC", 4) != 0)
		return false;

	return true;
}

AFfilesetup AIFFFile::completeSetup(AFfilesetup setup)
{
	bool	isAIFF = setup->fileFormat == AF_FILE_AIFF;

	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "AIFF/AIFF-C file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
		{
			_af_error(AF_BAD_FILEFMT, "AIFF/AIFF-C format does not support unsigned data");
			return AF_NULL_FILESETUP;
		}
		else if (isAIFF && track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
		{
			_af_error(AF_BAD_FILEFMT, "AIFF format supports only two's complement integer data");
			return AF_NULL_FILESETUP;
		}
	}
	else
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
			track->f.sampleWidth);

	/* Check sample width if writing two's complement. Otherwise ignore. */
	if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
		(track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
	{
		_af_error(AF_BAD_WIDTH,
			"invalid sample width %d for AIFF/AIFF-C file "
			"(must be 1-32)", track->f.sampleWidth);
		return AF_NULL_FILESETUP;
	}

	if (isAIFF && track->f.compressionType != AF_COMPRESSION_NONE)
	{
		_af_error(AF_BAD_FILESETUP,
			"AIFF does not support compression; use AIFF-C");
		return AF_NULL_FILESETUP;
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
		track->f.compressionType != AF_COMPRESSION_IMA)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in AIFF-C");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed() &&
		track->byteOrderSet &&
		track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
		track->f.isByteOrderSignificant())
	{
		_af_error(AF_BAD_BYTEORDER,
			"AIFF/AIFF-C format supports only big-endian data");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed())
		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	if (setup->instrumentSet)
	{
		if (setup->instrumentCount != 0 && setup->instrumentCount != 1)
		{
			_af_error(AF_BAD_NUMINSTS, "AIFF/AIFF-C file must have 0 or 1 instrument chunk");
			return AF_NULL_FILESETUP;
		}
		if (setup->instruments != 0 &&
			setup->instruments[0].loopCount != 2)
		{
			_af_error(AF_BAD_NUMLOOPS, "AIFF/AIFF-C file with instrument must also have 2 loops");
			return AF_NULL_FILESETUP;
		}
	}

	if (setup->miscellaneousSet)
	{
		for (int i=0; i<setup->miscellaneousCount; i++)
		{
			switch (setup->miscellaneous[i].type)
			{
				case AF_MISC_COPY:
				case AF_MISC_AUTH:
				case AF_MISC_NAME:
				case AF_MISC_ANNO:
				case AF_MISC_APPL:
				case AF_MISC_MIDI:
					break;

				default:
					_af_error(AF_BAD_MISCTYPE, "invalid miscellaneous type %d for AIFF/AIFF-C file", setup->miscellaneous[i].type);
					return AF_NULL_FILESETUP;
			}
		}
	}

	return _af_filesetup_copy(setup, &aiffDefaultFileSetup, true);
}

bool AIFFFile::isInstrumentParameterValid(AUpvlist list, int i)
{
	int param, type;

	AUpvgetparam(list, i, &param);
	AUpvgetvaltype(list, i, &type);
	if (type != AU_PVTYPE_LONG)
		return false;

	long lval;
	AUpvgetval(list, i, &lval);

	switch (param)
	{
		case AF_INST_MIDI_BASENOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_NUMCENTS_DETUNE:
			return ((lval >= -50) && (lval <= 50));

		case AF_INST_MIDI_LOVELOCITY:
			return ((lval >= 1) && (lval <= 127));

		case AF_INST_MIDI_HIVELOCITY:
			return ((lval >= 1) && (lval <= 127));

		case AF_INST_MIDI_LONOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_MIDI_HINOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_NUMDBS_GAIN:
		case AF_INST_SUSLOOPID:
		case AF_INST_RELLOOPID:
			return true;

		default:
			return false;
			break;
	}

	return true;
}

int AIFFFile::getVersion()
{
	if (isAIFFC())
		return AIFC_VERSION_1;
	return 0;
}

status AIFFFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	initCompressionParams();

	uint32_t fileSize = 0;
	m_fh->write("FORM", 4);
	writeU32(&fileSize);

	if (isAIFFC())
		m_fh->write("AIFC", 4);
	else
		m_fh->write("AIFF", 4);

	if (isAIFFC())
		writeFVER();

	writeCOMM();
	writeMARK();
	writeINST();
	writeAESD();
	writeMiscellaneous();
	writeSSND();

	return AF_SUCCEED;
}

status AIFFFile::update()
{
	/* Get the length of the file. */
	uint32_t length = m_fh->length();
	length -= 8;

	/* Set the length of the FORM chunk. */
	m_fh->seek(4, File::SeekFromBeginning);
	writeU32(&length);

	if (isAIFFC())
		writeFVER();

	writeCOMM();
	writeMARK();
	writeINST();
	writeAESD();
	writeMiscellaneous();
	writeSSND();

	return AF_SUCCEED;
}

status AIFFFile::writeCOMM()
{
	/*
		If COMM_offset hasn't been set yet, set it to the
		current offset.
	*/
	if (m_COMM_offset == 0)
		m_COMM_offset = m_fh->tell();
	else
		m_fh->seek(m_COMM_offset, File::SeekFromBeginning);

	Track *track = getTrack();

	Tag compressionTag;
	/* Pascal strings can occupy only 255 bytes (+ a size byte). */
	char compressionName[256];

	if (isAIFFC())
	{
		if (track->f.compressionType == AF_COMPRESSION_NONE)
		{
			if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
			{
				compressionTag = "NONE";
				strcpy(compressionName, "not compressed");
			}
			else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
			{
				compressionTag = "fl32";
				strcpy(compressionName, "32-bit Floating Point");
			}
			else if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
			{
				compressionTag = "fl64";
				strcpy(compressionName, "64-bit Floating Point");
			}
			/*
				We disallow unsigned sample data for
				AIFF files in _af_aiff_complete_setup,
				so the next condition should never be
				satisfied.
			*/
			else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
			{
				_af_error(AF_BAD_SAMPFMT,
					"AIFF/AIFF-C format does not support unsigned data");
				assert(0);
				return AF_FAIL;
			}
		}
		else if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
		{
			compressionTag = "ulaw";
			strcpy(compressionName, "CCITT G.711 u-law");
		}
		else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
		{
			compressionTag = "alaw";
			strcpy(compressionName, "CCITT G.711 A-law");
		}
		else if (track->f.compressionType == AF_COMPRESSION_IMA)
		{
			compressionTag = "ima4";
			strcpy(compressionName, "IMA 4:1 compression");
		}
	}

	m_fh->write("COMM", 4);

	/*
		For AIFF-C files, the length of the COMM chunk is 22
		plus the length of the compression name plus the size
		byte.  If the length of the data is an odd number of
		bytes, add a zero pad byte at the end, but don't
		include the pad byte in the chunk's size.
	*/
	uint32_t chunkSize;
	if (isAIFFC())
		chunkSize = 22 + strlen(compressionName) + 1;
	else
		chunkSize = 18;
	writeU32(&chunkSize);

	/* number of channels, 2 bytes */
	uint16_t channelCount = track->f.channelCount;
	writeU16(&channelCount);

	/* number of sample frames, 4 bytes */
	uint32_t frameCount = track->totalfframes;
	if (track->f.compressionType == AF_COMPRESSION_IMA)
		frameCount = track->totalfframes / track->f.framesPerPacket;
	writeU32(&frameCount);

	/* sample size, 2 bytes */
	uint16_t sampleSize = track->f.sampleWidth;
	writeU16(&sampleSize);

	/* sample rate, 10 bytes */
	uint8_t sampleRate[10];
	_af_convert_to_ieee_extended(track->f.sampleRate, sampleRate);
	m_fh->write(sampleRate, 10);

	if (isAIFFC())
	{
		writeTag(&compressionTag);
		writePString(compressionName);
	}

	return AF_SUCCEED;
}

/*
	The AESD chunk contains information pertinent to audio recording
	devices.
*/
status AIFFFile::writeAESD()
{
	Track *track = getTrack();

	if (!track->hasAESData)
		return AF_SUCCEED;

	if (m_AESD_offset == 0)
		m_AESD_offset = m_fh->tell();
	else
		m_fh->seek(m_AESD_offset, File::SeekFromBeginning);

	if (m_fh->write("AESD", 4) < 4)
		return AF_FAIL;

	uint32_t size = 24;
	if (!writeU32(&size))
		return AF_FAIL;

	if (m_fh->write(track->aesData, 24) < 24)
		return AF_FAIL;

	return AF_SUCCEED;
}

status AIFFFile::writeSSND()
{
	Track *track = getTrack();

	if (m_SSND_offset == 0)
		m_SSND_offset = m_fh->tell();
	else
		m_fh->seek(m_SSND_offset, File::SeekFromBeginning);

	m_fh->write("SSND", 4);

	uint32_t chunkSize = track->data_size + 8;
	writeU32(&chunkSize);

	uint32_t zero = 0;
	/* data offset */
	writeU32(&zero);
	/* block size */
	writeU32(&zero);

	if (track->fpos_first_frame == 0)
		track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}

status AIFFFile::writeINST()
{
	uint32_t length = 20;

	struct _INST instrumentdata;

	instrumentdata.sustainLoopPlayMode =
		afGetLoopMode(this, AF_DEFAULT_INST, 1);
	instrumentdata.sustainLoopBegin =
		afGetLoopStart(this, AF_DEFAULT_INST, 1);
	instrumentdata.sustainLoopEnd =
		afGetLoopEnd(this, AF_DEFAULT_INST, 1);

	instrumentdata.releaseLoopPlayMode =
		afGetLoopMode(this, AF_DEFAULT_INST, 2);
	instrumentdata.releaseLoopBegin =
		afGetLoopStart(this, AF_DEFAULT_INST, 2);
	instrumentdata.releaseLoopEnd =
		afGetLoopEnd(this, AF_DEFAULT_INST, 2);

	m_fh->write("INST", 4);
	writeU32(&length);

	instrumentdata.baseNote =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
	writeU8(&instrumentdata.baseNote);
	instrumentdata.detune =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
	writeS8(&instrumentdata.detune);
	instrumentdata.lowNote =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
	writeU8(&instrumentdata.lowNote);
	instrumentdata.highNote =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
	writeU8(&instrumentdata.highNote);
	instrumentdata.lowVelocity =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
	writeU8(&instrumentdata.lowVelocity);
	instrumentdata.highVelocity =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
	writeU8(&instrumentdata.highVelocity);

	instrumentdata.gain =
		afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
	writeS16(&instrumentdata.gain);

	writeU16(&instrumentdata.sustainLoopPlayMode);
	writeU16(&instrumentdata.sustainLoopBegin);
	writeU16(&instrumentdata.sustainLoopEnd);

	writeU16(&instrumentdata.releaseLoopPlayMode);
	writeU16(&instrumentdata.releaseLoopBegin);
	writeU16(&instrumentdata.releaseLoopEnd);

	return AF_SUCCEED;
}

status AIFFFile::writeMARK()
{
	Track *track = getTrack();
	if (!track->markerCount)
		return AF_SUCCEED;

	if (m_MARK_offset == 0)
		m_MARK_offset = m_fh->tell();
	else
		m_fh->seek(m_MARK_offset, File::SeekFromBeginning);

	Tag markTag("MARK");
	uint32_t length = 0;

	writeTag(&markTag);
	writeU32(&length);

	AFfileoffset chunkStartPosition = m_fh->tell();

	uint16_t numMarkers = track->markerCount;
	writeU16(&numMarkers);

	for (unsigned i=0; i<numMarkers; i++)
	{
		uint16_t id = track->markers[i].id;
		writeU16(&id);

		uint32_t position = track->markers[i].position;
		writeU32(&position);

		const char *name = track->markers[i].name;
		assert(name);

		// Write the name as a Pascal-style string.
		writePString(name);
	}

	AFfileoffset chunkEndPosition = m_fh->tell();
	length = chunkEndPosition - chunkStartPosition;

	m_fh->seek(chunkStartPosition - 4, File::SeekFromBeginning);

	writeU32(&length);
	m_fh->seek(chunkEndPosition, File::SeekFromBeginning);

	return AF_SUCCEED;
}

/*
	The FVER chunk, if present, is always the first chunk in the file.
*/
status AIFFFile::writeFVER()
{
	uint32_t chunkSize, timeStamp;

	assert(isAIFFC());

	if (m_FVER_offset == 0)
		m_FVER_offset = m_fh->tell();
	else
		m_fh->seek(m_FVER_offset, File::SeekFromBeginning);

	m_fh->write("FVER", 4);

	chunkSize = 4;
	writeU32(&chunkSize);

	timeStamp = AIFC_VERSION_1;
	writeU32(&timeStamp);

	return AF_SUCCEED;
}

/*
	WriteMiscellaneous writes all the miscellaneous data chunks in a
	file handle structure to an AIFF or AIFF-C file.
*/
status AIFFFile::writeMiscellaneous()
{
	if (m_miscellaneousPosition == 0)
		m_miscellaneousPosition = m_fh->tell();
	else
		m_fh->seek(m_miscellaneousPosition, File::SeekFromBeginning);

	for (int i=0; i<m_miscellaneousCount; i++)
	{
		Miscellaneous *misc = &m_miscellaneous[i];
		Tag chunkType;
		uint32_t chunkSize;
		uint8_t padByte = 0;

		switch (misc->type)
		{
			case AF_MISC_NAME:
				chunkType = "NAME"; break;
			case AF_MISC_AUTH:
				chunkType = "AUTH"; break;
			case AF_MISC_COPY:
				chunkType = "(c) "; break;
			case AF_MISC_ANNO:
				chunkType = "ANNO"; break;
			case AF_MISC_MIDI:
				chunkType = "MIDI"; break;
			case AF_MISC_APPL:
				chunkType = "APPL"; break;
		}

		writeTag(&chunkType);

		chunkSize = misc->size;
		writeU32(&chunkSize);
		/*
			Write the miscellaneous buffer and then a pad byte
			if necessary.  If the buffer is null, skip the space
			for now.
		*/
		if (misc->buffer != NULL)
			m_fh->write(misc->buffer, misc->size);
		else
			m_fh->seek(misc->size, File::SeekFromCurrent);

		if (misc->size % 2 != 0)
			writeU8(&padByte);
	}

	return AF_SUCCEED;
}

void AIFFFile::initCompressionParams()
{
	Track *track = getTrack();
	if (track->f.compressionType == AF_COMPRESSION_IMA)
		initIMACompressionParams();
}

void AIFFFile::initIMACompressionParams()
{
	Track *track = getTrack();

	track->f.bytesPerPacket = 34 * track->f.channelCount;
	track->f.framesPerPacket = 64;

	AUpvlist pv = AUpvnew(1);
	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = _AF_IMA_ADPCM_TYPE_QT;
	AUpvsetval(pv, 0, &l);

	track->f.compressionParams = pv;
}

// Read a Pascal-style string.
bool AIFFFile::readPString(char s[256])
{
	uint8_t length;
	if (m_fh->read(&length, 1) != 1)
		return false;
	if (m_fh->read(s, length) != static_cast<ssize_t>(length))
		return false;
	s[length] = '\0';
	return true;
}

// Write a Pascal-style string.
bool AIFFFile::writePString(const char *s)
{
	size_t length = strlen(s);
	if (length > 255)
		return false;
	uint8_t sizeByte = static_cast<uint8_t>(length);
	if (m_fh->write(&sizeByte, 1) != 1)
		return false;
	if (m_fh->write(s, length) != (ssize_t) length)
		return false;
	/*
		Add a pad byte if the length of the Pascal-style string
		(including the size byte) is odd.
	*/
	if ((length % 2) == 0)
	{
		uint8_t zero = 0;
		if (m_fh->write(&zero, 1) != 1)
			return false;
	}
	return true;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, 2003-2004, 2010-2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	AIFF.h

	This file contains structures and constants related to the AIFF
	and AIFF-C formats.
*/

#ifndef AIFF_H
#define AIFF_H

#include "Compiler.h"
#include "FileHandle.h"

#define _AF_AIFF_NUM_INSTPARAMS 9
extern const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS];
#define _AF_AIFFC_NUM_COMPTYPES 3
extern const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES];

class AIFFFile : public _AFfilehandle
{
public:
	AIFFFile();

	static bool recognizeAIFF(File *fh);
	static bool recognizeAIFFC(File *fh);

	static AFfilesetup completeSetup(AFfilesetup);

	int getVersion() OVERRIDE;

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;

	status update() OVERRIDE;

	bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;

private:
	AFfileoffset m_miscellaneousPosition;
	AFfileoffset m_FVER_offset;
	AFfileoffset m_COMM_offset;
	AFfileoffset m_MARK_offset;
	AFfileoffset m_INST_offset;
	AFfileoffset m_AESD_offset;
	AFfileoffset m_SSND_offset;

	status parseFVER(const Tag &type, size_t size);
	status parseAESD(const Tag &type, size_t size);
	status parseMiscellaneous(const Tag &type, size_t size);
	status parseINST(const Tag &type, size_t size);
	status parseMARK(const Tag &type, size_t size);
	status parseCOMM(const Tag &type, size_t size);
	status parseSSND(const Tag &type, size_t size);

	status writeCOMM();
	status writeSSND();
	status writeMARK();
	status writeINST();
	status writeFVER();
	status writeAESD();
	status writeMiscellaneous();

	void initCompressionParams();
	void initIMACompressionParams();

	bool isAIFFC() const { return m_fileFormat == AF_FILE_AIFFC; }

	bool readPString(char s[256]);
	bool writePString(const char *);
};

#endif
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	AVR.cpp

	This file contains routines for reading and writing AVR (Audio
	Visual Research) sound files.
*/

#include "config.h"
#include "AVR.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"

static const _AFfilesetup avrDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_AVR,		/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

AVRFile::AVRFile()
{
	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
}

bool AVRFile::recognize(File *fh)
{
	uint32_t	magic;

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(&magic, 4) != 4 || memcmp(&magic, "2BIT", 4) != 0)
		return false;

	return true;
}

status AVRFile::readInit(AFfilesetup setup)
{
	uint32_t	magic;
	char		name[8];
	uint16_t	mono, resolution, sign, loop, midi;
	uint32_t	rate, size, loopStart, loopEnd;
	char		reserved[26];
	char		user[64];

	m_fh->seek(0, File::SeekFromBeginning);

	if (m_fh->read(&magic, 4) != 4)
	{
		_af_error(AF_BAD_READ, "could not read AVR file header");
		return AF_FAIL;
	}

	if (memcmp(&magic, "2BIT", 4) != 0)
	{
		_af_error(AF_BAD_FILEFMT, "file is not AVR format");
		return AF_FAIL;
	}

	/* Read name. */
	m_fh->read(name, 8);

	readU16(&mono);
	readU16(&resolution);
	readU16(&sign);
	readU16(&loop);
	readU16(&midi);

	readU32(&rate);
	readU32(&size);
	readU32(&loopStart);
	readU32(&loopEnd);

	m_fh->read(reserved, 26);
	m_fh->read(user, 64);

	Track *track = allocateTrack();
	if (!track)
		return AF_FAIL;

	/* Use only low-order three bytes of sample rate. */
	track->f.sampleRate = rate & 0xffffff;

	if (sign == 0)
		track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
	else if (sign == 0xffff)
		track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
	else
	{
		_af_error(AF_BAD_SAMPFMT, "bad sample format in AVR file");
		return AF_FAIL;
	}

	if (resolution != 8 && resolution != 16)
	{
		_af_error(AF_BAD_WIDTH, "bad sample width %d in AVR file",
			resolution);
		return AF_FAIL;
	}
	track->f.sampleWidth = resolution;

	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	if (mono == 0)
		track->f.channelCount = 1;
	else if (mono == 0xffff)
		track->f.channelCount = 2;
	else
	{
		_af_error(AF_BAD_CHANNELS,
			"invalid number of channels in AVR file");
		return AF_FAIL;
	}

	track->f.compressionType = AF_COMPRESSION_NONE;

	track->f.framesPerPacket = 1;
	track->f.computeBytesPerPacketPCM();

	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);

	track->fpos_first_frame = m_fh->tell();
	track->totalfframes = size;
	track->data_size = track->totalfframes * track->f.bytesPerFrame(false);

	/* The file has been parsed successfully. */
	return AF_SUCCEED;
}

AFfilesetup AVRFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "AVR files must have exactly 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	/* AVR allows only unsigned and two's complement integer data. */
	if (track->f.sampleFormat != AF_SAMPFMT_UNSIGNED &&
		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
	{
		_af_error(AF_BAD_FILEFMT, "AVR format does supports only unsigned and two's complement integer data");
		return AF_NULL_FILESETUP;
	}

	/* For now we support only 8- and 16-bit samples. */
	if (track->f.sampleWidth != 8 && track->f.sampleWidth != 16)
	{
		_af_error(AF_BAD_WIDTH, "invalid sample width %d for AVR file (only 8- and 16-bit sample widths are allowed)", track->f.sampleWidth);
		return AF_NULL_FILESETUP;
	}

	/* AVR does not support compression. */
	if (track->f.compressionType != AF_COMPRESSION_NONE)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression not supported for AVR files");
		return AF_NULL_FILESETUP;
	}

	/* AVR audio data is big-endian. */
	if (track->f.byteOrder != AF_BYTEORDER_BIGENDIAN)
	{
		if (track->byteOrderSet)
		{
			_af_error(AF_BAD_BYTEORDER,
				"AVR format supports only big-endian data");
			return AF_NULL_FILESETUP;
		}
		else
			track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "AVR files do not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "AVR format does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "AVR format does not support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "AVR format does not support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &avrDefaultFileSetup, false);
}

status AVRFile::update()
{
	uint32_t	size, loopStart, loopEnd;

	Track *track = getTrack();

	/* Seek to the position of the size field. */
	m_fh->seek(26, File::SeekFromBeginning);

	size = track->totalfframes;

	/* For the case of no loops, loopStart = 0 and loopEnd = size. */
	loopStart = 0;
	loopEnd = size;

	writeU32(&size);
	writeU32(&loopStart);
	writeU32(&loopEnd);

	return AF_SUCCEED;
}

static char *af_basename (char *filename)
{
	char	*base;
	base = strrchr(filename, '/');
	if (base == NULL)
		return filename;
	else
		return base + 1;
}

status AVRFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	if (m_fh->seek(0, File::SeekFromBeginning) != 0)
	{
		_af_error(AF_BAD_LSEEK, "bad seek");
		return AF_FAIL;
	}

	Track *track = getTrack();

	char name[8];
	uint16_t mono, resolution, sign, loop, midi;
	uint32_t rate, size, loopStart, loopEnd;
	char reserved[26];
	char user[64];

	m_fh->write("2BIT", 4);
	memset(name, 0, 8);
	if (m_fileName != NULL)
		strncpy(name, af_basename(m_fileName), 8);
	m_fh->write(name, 8);

	if (track->f.channelCount == 1)
		mono = 0x0;
	else
		mono = 0xffff;
	writeU16(&mono);

	resolution = track->f.sampleWidth;
	writeU16(&resolution);

	if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
		sign = 0x0;
	else
		sign = 0xffff;
	writeU16(&sign);

	/* We do not currently support loops. */
	loop = 0;
	writeU16(&loop);
	midi = 0xffff;
	writeU16(&midi);

	rate = track->f.sampleRate;
	/* Set the high-order byte of rate to 0xff. */
	rate |= 0xff000000;
	size = track->totalfframes;
	loopStart = 0;
	loopEnd = size;

	writeU32(&rate);
	writeU32(&size);
	writeU32(&loopStart);
	writeU32(&loopEnd);

	memset(reserved, 0, 26);
	m_fh->write(reserved, 26);

	memset(user, 0, 64);
	m_fh->write(user, 64);

	if (track->fpos_first_frame == 0)
		track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	AVR.h

	This file contains headers and constants related to the AVR
	(Audio Visual Research) sound file format.
*/

#ifndef AVR_H
#define AVR_H

#include "Compiler.h"
#include "FileHandle.h"

class AVRFile : public _AFfilehandle
{
public:
	AVRFile();

	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;
};

#endif
/*
	Audio File Library
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "AudioFormat.h"

#include "afinternal.h"
#include "byteorder.h"
#include "compression.h"
#include "units.h"
#include "util.h"
#include <assert.h>
#include <stdio.h>

size_t AudioFormat::bytesPerSample(bool stretch3to4) const
{
	switch (sampleFormat)
	{
		case AF_SAMPFMT_FLOAT:
			return sizeof (float);
		case AF_SAMPFMT_DOUBLE:
			return sizeof (double);
		default:
		{
			int size = (sampleWidth + 7) / 8;
			if (compressionType == AF_COMPRESSION_NONE &&
				size == 3 && stretch3to4)
				size = 4;
			return size;
		}
	}
}

size_t AudioFormat::bytesPerFrame(bool stretch3to4) const
{
	return bytesPerSample(stretch3to4) * channelCount;
}

size_t AudioFormat::bytesPerSample() const
{
	return bytesPerSample(!isPacked());
}

size_t AudioFormat::bytesPerFrame() const
{
	return bytesPerFrame(!isPacked());
}

bool AudioFormat::isInteger() const
{
	return sampleFormat == AF_SAMPFMT_TWOSCOMP ||
		sampleFormat == AF_SAMPFMT_UNSIGNED;
}

bool AudioFormat::isSigned() const
{
	return sampleFormat == AF_SAMPFMT_TWOSCOMP;
}

bool AudioFormat::isUnsigned() const
{
	return sampleFormat == AF_SAMPFMT_UNSIGNED;
}

bool AudioFormat::isFloat() const
{
	return sampleFormat == AF_SAMPFMT_FLOAT ||
		sampleFormat == AF_SAMPFMT_DOUBLE;
}

bool AudioFormat::isCompressed() const
{
	return compressionType != AF_COMPRESSION_NONE;
}

bool AudioFormat::isUncompressed() const
{
	return compressionType == AF_COMPRESSION_NONE;
}

void AudioFormat::computeBytesPerPacketPCM()
{
	assert(isUncompressed());
	int bytesPerSample = (sampleWidth + 7) / 8;
	bytesPerPacket = bytesPerSample * channelCount;
}

std::string AudioFormat::description() const
{
	std::string d;
	char s[1024];
	/* sampleRate, channelCount */
	sprintf(s, "{ %7.2f Hz %d ch ", sampleRate, channelCount);
	d += s;

	/* sampleFormat, sampleWidth */
	switch (sampleFormat)
	{
		case AF_SAMPFMT_TWOSCOMP:
			sprintf(s, "%db 2 ", sampleWidth);
			break;
		case AF_SAMPFMT_UNSIGNED:
			sprintf(s, "%db u ", sampleWidth);
			break;
		case AF_SAMPFMT_FLOAT:
			sprintf(s, "flt ");
			break;
		case AF_SAMPFMT_DOUBLE:
			sprintf(s, "dbl ");
			break;
		default:
			assert(false);
			break;
	}

	d += s;

	/* pcm */
	sprintf(s, "(%.30g+-%.30g [%.30g,%.30g]) ",
		pcm.intercept, pcm.slope,
		pcm.minClip, pcm.maxClip);
	d += s;

	/* byteOrder */
	switch (byteOrder)
	{
		case AF_BYTEORDER_BIGENDIAN:
			d += "big ";
			break;
		case AF_BYTEORDER_LITTLEENDIAN:
			d += "little ";
			break;
		default:
			assert(false);
			break;
	}

	if (isCompressed())
	{
		const CompressionUnit *unit = _af_compression_unit_from_id(compressionType);
		assert(unit);
		d += "compression: ";
		d += unit->label;
	}

	return d;
}
/*
	Audio File Library
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef AUDIOFORMAT_H
#define AUDIOFORMAT_H

#include "aupvlist.h"

#include <sys/types.h>
#include <string>

struct PCMInfo
{
	double slope, intercept, minClip, maxClip;
};

struct AudioFormat
{
	double sampleRate;		/* sampling rate in Hz */
	int sampleFormat;		/* AF_SAMPFMT_... */
	int sampleWidth;		/* sample width in bits */
	int byteOrder;		/* AF_BYTEORDER_... */

	PCMInfo pcm;		/* parameters of PCM data */

	int channelCount;		/* number of channels */

	int compressionType;	/* AF_COMPRESSION_... */
	AUpvlist compressionParams;	/* NULL if no compression */

	bool packed : 1;

	size_t framesPerPacket;
	size_t bytesPerPacket;

	size_t bytesPerSample(bool stretch3to4) const;
	size_t bytesPerFrame(bool stretch3to4) const;
	size_t bytesPerSample() const;
	size_t bytesPerFrame() const;
	bool isInteger() const;
	bool isSigned() const;
	bool isUnsigned() const;
	bool isFloat() const;
	bool isCompressed() const;
	bool isUncompressed() const;
	bool isPacked() const { return packed; }
	bool isByteOrderSignificant() const { return sampleWidth > 8; }

	void computeBytesPerPacketPCM();

	std::string description() const;
};

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "Buffer.h"

#include <string.h>

Buffer::Buffer() : m_data(0), m_size(0)
{
}

Buffer::Buffer(size_t size) : m_data(0), m_size(0)
{
	if (size)
		m_data = ::operator new(size);
	if (m_data)
	{
		m_size = size;
	}
}

Buffer::Buffer(const void *data, size_t size) : m_data(0), m_size(0)
{
	if (size)
		m_data = ::operator new(size);
	if (m_data)
	{
		::memcpy(m_data, data, m_size);
		m_size = size;
	}
}

Buffer::~Buffer()
{
	::operator delete(m_data);
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef Buffer_h
#define Buffer_h

#include "Shared.h"

#include <sys/types.h>

class Buffer : public Shared<Buffer>
{
public:
	Buffer();
	Buffer(size_t size);
	Buffer(const void *data, size_t size);
	~Buffer();

	void *data() { return m_data; }
	const void *data() const { return m_data; }

	size_t size() const { return m_size; }

private:
	void *m_data;
	size_t m_size;
};

#endif
/*
	Audio File Library
	Copyright (C) 2011-2013, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "CAF.h"

#include "Buffer.h"
#include "File.h"
#include "PacketTable.h"
#include "Setup.h"
#include "Tag.h"
#include "Track.h"
#include "byteorder.h"
#include "util.h"

#include <stdint.h>
#include <string.h>
#include <string>
#include <vector>

const int _af_caf_compression_types[_AF_CAF_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW,
	AF_COMPRESSION_IMA,
	AF_COMPRESSION_ALAC
};

enum
{
	kCAFLinearPCMFormatFlagIsFloat = (1L << 0),
	kCAFLinearPCMFormatFlagIsLittleEndian = (1L << 1)
};

enum
{
	kALACFormatFlag_16BitSourceData = 1,
	kALACFormatFlag_20BitSourceData = 2,
	kALACFormatFlag_24BitSourceData = 3,
	kALACFormatFlag_32BitSourceData = 4
};

static const unsigned kALACDefaultFramesPerPacket = 4096;

static const _AFfilesetup cafDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	// valid
	AF_FILE_CAF,			// fileFormat
	true,					// trackSet
	true,					// instrumentSet
	true,					// miscellaneousSet
	1,						// trackCount
	NULL,					// tracks
	1,						// instrumentCount
	NULL,					// instruments
	0,						// miscellaneousCount
	NULL					// miscellaneous
};

CAFFile::CAFFile() :
	m_dataOffset(-1),
	m_cookieDataOffset(-1)
{
	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
}

CAFFile::~CAFFile()
{
}

bool CAFFile::recognize(File *file)
{
	file->seek(0, File::SeekFromBeginning);
	uint8_t buffer[8];
	if (file->read(buffer, 8) != 8 || memcmp(buffer, "caff", 4) != 0)
		return false;
	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
	if (memcmp(buffer + 4, versionAndFlags, 4) != 0)
		return false;
	return true;
}

status CAFFile::readInit(AFfilesetup setup)
{
	m_fh->seek(8, File::SeekFromBeginning);

	if (!allocateTrack())
		return AF_FAIL;

	off_t currentOffset = m_fh->tell();
	off_t fileLength = m_fh->length();

	while (currentOffset < fileLength)
	{
		Tag chunkType;
		int64_t chunkLength;
		if (!readTag(&chunkType) ||
			!readS64(&chunkLength))
			return AF_FAIL;

		currentOffset += 12;

		if (chunkType == "data" && chunkLength == -1)
			chunkLength = fileLength - currentOffset;
		else if (chunkLength < 0)
			_af_error(AF_BAD_HEADER,
				"invalid chunk length %jd for chunk type %s\n",
				static_cast<intmax_t>(chunkLength), chunkType.name().c_str());

		if (chunkType == "desc")
		{
			if (parseDescription(chunkType, chunkLength) == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkType == "data")
		{
			if (parseData(chunkType, chunkLength) == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkType == "pakt")
		{
			if (parsePacketTable(chunkType, chunkLength) == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkType == "kuki")
		{
			if (parseCookieData(chunkType, chunkLength) == AF_FAIL)
				return AF_FAIL;
		}

		currentOffset = m_fh->seek(currentOffset + chunkLength,
			File::SeekFromBeginning);
	}

	return AF_SUCCEED;
}

status CAFFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	initCompressionParams();

	Tag caff("caff");
	if (!writeTag(&caff)) return AF_FAIL;
	const uint8_t versionAndFlags[4] = { 0, 1, 0, 0 };
	if (m_fh->write(versionAndFlags, 4) != 4) return AF_FAIL;

	if (writeDescription() == AF_FAIL)
		return AF_FAIL;
	if (writeCookieData() == AF_FAIL)
		return AF_FAIL;
	if (writeData(false) == AF_FAIL)
		return AF_FAIL;

	return AF_SUCCEED;
}

AFfilesetup CAFFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "CAF file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		if (track->f.isUnsigned())
		{
			_af_error(AF_BAD_FILEFMT, "CAF format does not support unsigned data");
			return AF_NULL_FILESETUP;
		}
	}
	else
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
			track->f.sampleWidth);

	if (track->f.isSigned() && (track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
	{
		_af_error(AF_BAD_WIDTH,
			"invalid sample width %d for CAF file (must be 1-32)",
			track->f.sampleWidth);
		return AF_NULL_FILESETUP;
	}

	if (!track->byteOrderSet)
		track->f.byteOrder = _AF_BYTEORDER_NATIVE;

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
		track->f.compressionType != AF_COMPRESSION_IMA &&
		track->f.compressionType != AF_COMPRESSION_ALAC)
	{
		_af_error(AF_BAD_COMPTYPE,
			"compression format %d not supported in CAF file",
			track->f.compressionType);
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support markers");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "CAF does not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "CAF does not yet support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &cafDefaultFileSetup, true);
}

status CAFFile::update()
{
	if (writeCookieData() == AF_FAIL)
		return AF_FAIL;
	if (writeData(true) == AF_FAIL)
		return AF_FAIL;
	if (writePacketTable() == AF_FAIL)
		return AF_FAIL;
	return AF_SUCCEED;
}

status CAFFile::parseDescription(const Tag &, int64_t)
{
	double sampleRate;
	Tag formatID;
	uint32_t formatFlags;
	uint32_t bytesPerPacket;
	uint32_t framesPerPacket;
	uint32_t channelsPerFrame;
	uint32_t bitsPerChannel;
	if (!readDouble(&sampleRate) ||
		!readTag(&formatID) ||
		!readU32(&formatFlags) ||
		!readU32(&bytesPerPacket) ||
		!readU32(&framesPerPacket) ||
		!readU32(&channelsPerFrame) ||
		!readU32(&bitsPerChannel))
		return AF_FAIL;

	if (!channelsPerFrame)
	{
		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
		return AF_FAIL;
	}

	Track *track = getTrack();
	track->f.channelCount = channelsPerFrame;
	track->f.sampleWidth = bitsPerChannel;
	track->f.sampleRate = sampleRate;
	track->f.framesPerPacket = 1;

	if (formatID == "lpcm")
	{
		track->f.compressionType = AF_COMPRESSION_NONE;
		if (formatFlags & kCAFLinearPCMFormatFlagIsFloat)
		{
			if (bitsPerChannel != 32 && bitsPerChannel != 64)
			{
				_af_error(AF_BAD_WIDTH, "invalid bits per sample %d for floating-point audio data", bitsPerChannel);
				return AF_FAIL;
			}
			track->f.sampleFormat = bitsPerChannel == 32 ? AF_SAMPFMT_FLOAT :
				AF_SAMPFMT_DOUBLE;
		}
		else
		{
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
		}
		track->f.byteOrder = (formatFlags & kCAFLinearPCMFormatFlagIsLittleEndian) ?
			AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;

		if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
			return AF_FAIL;

		track->f.computeBytesPerPacketPCM();
		return AF_SUCCEED;
	}
	else if (formatID == "ulaw")
	{
		track->f.compressionType = AF_COMPRESSION_G711_ULAW;
		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
		track->f.bytesPerPacket = channelsPerFrame;
		return AF_SUCCEED;
	}
	else if (formatID == "alaw")
	{
		track->f.compressionType = AF_COMPRESSION_G711_ALAW;
		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
		track->f.bytesPerPacket = channelsPerFrame;
		return AF_SUCCEED;
	}
	else if (formatID == "ima4")
	{
		track->f.compressionType = AF_COMPRESSION_IMA;
		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
		initIMACompressionParams();
		return AF_SUCCEED;
	}
	else if (formatID == "alac")
	{
		track->f.compressionType = AF_COMPRESSION_ALAC;
		track->f.byteOrder = _AF_BYTEORDER_NATIVE;
		switch (formatFlags)
		{
			case kALACFormatFlag_16BitSourceData:
				track->f.sampleWidth = 16; break;
			case kALACFormatFlag_20BitSourceData:
				track->f.sampleWidth = 20; break;
			case kALACFormatFlag_24BitSourceData:
				track->f.sampleWidth = 24; break;
			case kALACFormatFlag_32BitSourceData:
				track->f.sampleWidth = 32; break;
			default:
				_af_error(AF_BAD_CODEC_TYPE,
					"unsupported format flags for ALAC: %u", formatFlags);
				return AF_FAIL;
		}
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
			track->f.sampleWidth);
		track->f.framesPerPacket = framesPerPacket;
		track->f.bytesPerPacket = 0;
		return AF_SUCCEED;
	}
	else
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "Compression type %s not supported",
			formatID.name().c_str());
		return AF_FAIL;
	}
}

status CAFFile::parseData(const Tag &tag, int64_t length)
{
	uint32_t editCount;
	if (!readU32(&editCount))
		return AF_FAIL;

	Track *track = getTrack();
	if (length == -1)
		track->data_size = m_fh->length() - m_fh->tell();
	else
		track->data_size = length - 4;
	track->fpos_first_frame = m_fh->tell();

	track->computeTotalFileFrames();
	return AF_SUCCEED;
}

static uint32_t readBERInteger(const uint8_t *input, size_t *numBytes)
{
	uint32_t result = 0;
	uint8_t data;
	size_t size = 0;
	do
	{
		data = input[size];
		result = (result << 7) | (data & 0x7f);
		if (++size > 5)
			return 0;
	} while ((data & 0x80) && size < *numBytes);
	*numBytes = size;
	return result;
}

static void encodeBERInteger(uint32_t value, uint8_t *buffer, size_t *numBytes)
{
	if ((value & 0x7f) == value)
	{
		*numBytes = 1;
		buffer[0] = value;
	}
	else if ((value & 0x3fff) == value)
	{
		*numBytes = 2;
		buffer[0] = (value >> 7) | 0x80;
		buffer[1] = value & 0x7f;
	}
	else if ((value & 0x1fffff) == value)
	{
		*numBytes = 3;
		buffer[0] = (value >> 14) | 0x80;
		buffer[1] = ((value >> 7) & 0x7f) | 0x80;
		buffer[2] = value & 0x7f;
	}
	else if ((value & 0x0fffffff) == value)
	{
		*numBytes = 4;
		buffer[0] = (value >> 21) | 0x80;
		buffer[1] = ((value >> 14) & 0x7f) | 0x80;
		buffer[2] = ((value >> 7) & 0x7f) | 0x80;
		buffer[3] = value & 0x7f;
	}
	else
	{
		*numBytes = 5;
		buffer[0] = (value >> 28) | 0x80;
		buffer[1] = ((value >> 21) & 0x7f) | 0x80;
		buffer[2] = ((value >> 14) & 0x7f) | 0x80;
		buffer[3] = ((value >> 7) & 0x7f) | 0x80;
		buffer[4] = value & 0x7f;
	}
}

status CAFFile::parsePacketTable(const Tag &tag, int64_t length)
{
	if (length < 24)
		return AF_FAIL;

	int64_t numPackets;
	int64_t numValidFrames;
	int32_t primingFrames;
	int32_t remainderFrames;
	if (!readS64(&numPackets) ||
		!readS64(&numValidFrames) ||
		!readS32(&primingFrames) ||
		!readS32(&remainderFrames))
	{
		return AF_FAIL;
	}

	if (!numPackets)
		return AF_SUCCEED;

	int64_t tableLength = length - 24;

	SharedPtr<Buffer> buffer = new Buffer(tableLength);
	if (m_fh->read(buffer->data(), tableLength) != tableLength)
		return AF_FAIL;

	SharedPtr<PacketTable> packetTable = new PacketTable(numValidFrames,
		primingFrames, remainderFrames);

	const uint8_t *data = static_cast<const uint8_t *>(buffer->data());
	size_t position = 0;
	while (position < buffer->size())
	{
		size_t sizeRemaining = buffer->size() - position;
		uint32_t bytesPerPacket = readBERInteger(data + position, &sizeRemaining);
		if (bytesPerPacket == 0)
			break;
		packetTable->append(bytesPerPacket);
		position += sizeRemaining;
	}

	assert(numPackets == packetTable->numPackets());

	Track *track = getTrack();
	track->m_packetTable = packetTable;
	track->totalfframes = numValidFrames;

	return AF_SUCCEED;
}

status CAFFile::parseCookieData(const Tag &tag, int64_t length)
{
	m_codecData = new Buffer(length);
	if (m_fh->read(m_codecData->data(), length) != length)
		return AF_FAIL;

	AUpvlist pv = AUpvnew(2);

	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = length;
	AUpvsetval(pv, 0, &l);

	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
	void *v = m_codecData->data();
	AUpvsetval(pv, 1, &v);

	Track *track = getTrack();
	track->f.compressionParams = pv;

	return AF_SUCCEED;
}

status CAFFile::writeDescription()
{
	Track *track = getTrack();

	Tag desc("desc");
	int64_t chunkLength = 32;
	double sampleRate = track->f.sampleRate;
	Tag formatID("lpcm");
	uint32_t formatFlags = 0;
	if (track->f.byteOrder == AF_BYTEORDER_LITTLEENDIAN)
		formatFlags |= kCAFLinearPCMFormatFlagIsLittleEndian;
	if (track->f.isFloat())
		formatFlags |= kCAFLinearPCMFormatFlagIsFloat;
	uint32_t bytesPerPacket = track->f.bytesPerFrame(false);
	uint32_t framesPerPacket = 1;
	uint32_t channelsPerFrame = track->f.channelCount;
	uint32_t bitsPerChannel = track->f.sampleWidth;

	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
	{
		formatID = "ulaw";
		formatFlags = 0;
		bytesPerPacket = channelsPerFrame;
		bitsPerChannel = 8;
	}
	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
	{
		formatID = "alaw";
		formatFlags = 0;
		bytesPerPacket = channelsPerFrame;
		bitsPerChannel = 8;
	}
	else if (track->f.compressionType == AF_COMPRESSION_IMA)
	{
		formatID = "ima4";
		formatFlags = 0;
		bytesPerPacket = track->f.bytesPerPacket;
		framesPerPacket = track->f.framesPerPacket;
		bitsPerChannel = 16;
	}
	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
	{
		formatID = "alac";
		switch (track->f.sampleWidth)
		{
			case 16: formatFlags = kALACFormatFlag_16BitSourceData; break;
			case 20: formatFlags = kALACFormatFlag_20BitSourceData; break;
			case 24: formatFlags = kALACFormatFlag_24BitSourceData; break;
			case 32: formatFlags = kALACFormatFlag_32BitSourceData; break;
		}
		bytesPerPacket = track->f.bytesPerPacket;
		framesPerPacket = track->f.framesPerPacket;
	}

	if (!writeTag(&desc) ||
		!writeS64(&chunkLength) ||
		!writeDouble(&sampleRate) ||
		!writeTag(&formatID) ||
		!writeU32(&formatFlags) ||
		!writeU32(&bytesPerPacket) ||
		!writeU32(&framesPerPacket) ||
		!writeU32(&channelsPerFrame) ||
		!writeU32(&bitsPerChannel))
		return AF_FAIL;
	return AF_SUCCEED;
}

status CAFFile::writeData(bool update)
{
	Track *track = getTrack();

	if (m_dataOffset == -1)
		m_dataOffset = m_fh->tell();
	else
		m_fh->seek(m_dataOffset, File::SeekFromBeginning);

	Tag data("data");
	int64_t dataLength = -1;
	uint32_t editCount = 0;
	if (update)
		dataLength = track->data_size + 4;

	if (!writeTag(&data) ||
		!writeS64(&dataLength) ||
		!writeU32(&editCount))
		return AF_FAIL;
	if (track->fpos_first_frame == 0)
		track->fpos_first_frame = m_fh->tell();
	return AF_SUCCEED;
}

status CAFFile::writePacketTable()
{
	Track *track = getTrack();

	m_fh->seek(track->fpos_after_data, File::SeekFromBeginning);

	SharedPtr<PacketTable> packetTable = track->m_packetTable;
	if (!packetTable)
		return AF_SUCCEED;

	int64_t numPackets = packetTable->numPackets();
	int64_t numValidFrames = packetTable->numValidFrames();
	int32_t primingFrames = packetTable->primingFrames();
	int32_t remainderFrames = packetTable->remainderFrames();

	SharedPtr<Buffer> buffer = new Buffer(packetTable->numPackets() * 5);

	uint8_t *data = static_cast<uint8_t *>(buffer->data());
	size_t position = 0;
	for (unsigned i=0; i<packetTable->numPackets(); i++)
	{
		uint32_t bytesPerPacket = packetTable->bytesPerPacket(i);
		size_t numBytes = 0;
		encodeBERInteger(bytesPerPacket, data + position, &numBytes);
		position += numBytes;
	}

	Tag pakt("pakt");
	int64_t packetTableLength = 24 + position;

	if (!writeTag(&pakt) ||
		!writeS64(&packetTableLength) ||
		!writeS64(&numPackets) ||
		!writeS64(&numValidFrames) ||
		!writeS32(&primingFrames) ||
		!writeS32(&remainderFrames) ||
		m_fh->write(buffer->data(), position) != static_cast<ssize_t>(position))
	{
		return AF_FAIL;
	}

	return AF_SUCCEED;
}

status CAFFile::writeCookieData()
{
	if (!m_codecData)
		return AF_SUCCEED;

	if (m_cookieDataOffset == -1)
		m_cookieDataOffset = m_fh->tell();
	else
		m_fh->seek(m_cookieDataOffset, File::SeekFromBeginning);

	Tag kuki("kuki");
	int64_t cookieDataLength = m_codecData->size();
	if (!writeTag(&kuki) ||
		!writeS64(&cookieDataLength) ||
		m_fh->write(m_codecData->data(), m_codecData->size()) != static_cast<ssize_t>(m_codecData->size()))
	{
		return AF_FAIL;
	}

	return AF_SUCCEED;
}

void CAFFile::initCompressionParams()
{
	Track *track = getTrack();
	if (track->f.compressionType == AF_COMPRESSION_IMA)
		initIMACompressionParams();
	else if (track->f.compressionType == AF_COMPRESSION_ALAC)
		initALACCompressionParams();
}

void CAFFile::initIMACompressionParams()
{
	Track *track = getTrack();

	track->f.bytesPerPacket = 34 * track->f.channelCount;
	track->f.framesPerPacket = 64;

	AUpvlist pv = AUpvnew(1);
	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = _AF_IMA_ADPCM_TYPE_QT;
	AUpvsetval(pv, 0, &l);

	track->f.compressionParams = pv;
}

void CAFFile::initALACCompressionParams()
{
	if (m_access == _AF_READ_ACCESS)
		return;

	Track *track = getTrack();

	track->f.bytesPerPacket = 0;
	track->f.framesPerPacket = kALACDefaultFramesPerPacket;

	const unsigned kALACSpecificConfigSize = 24;
	const unsigned kChannelAtomSize = 12;
	const unsigned kALACAudioChannelLayoutSize = 12;

	unsigned codecDataSize = kALACSpecificConfigSize;
	if (track->f.channelCount > 2)
		codecDataSize += kChannelAtomSize + kALACAudioChannelLayoutSize;
	m_codecData = new Buffer(codecDataSize);
	memset(m_codecData->data(), 0, m_codecData->size());

	AUpvlist pv = AUpvnew(2);

	AUpvsetparam(pv, 0, _AF_CODEC_DATA_SIZE);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = codecDataSize;
	AUpvsetval(pv, 0, &l);

	AUpvsetparam(pv, 1, _AF_CODEC_DATA);
	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
	void *v = m_codecData->data();
	AUpvsetval(pv, 1, &v);

	track->f.compressionParams = pv;

	track->m_packetTable = new PacketTable();
}
/*
	Audio File Library
	Copyright (C) 2011-2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef CAF_H
#define CAF_H

#include "Compiler.h"
#include "File.h"
#include "FileHandle.h"
#include "Tag.h"
#include <stdint.h>

#define _AF_CAF_NUM_COMPTYPES 4
extern const int _af_caf_compression_types[_AF_CAF_NUM_COMPTYPES];

class Buffer;

class CAFFile : public _AFfilehandle
{
public:
	static bool recognize(File *);
	static AFfilesetup completeSetup(AFfilesetup);

	CAFFile();
	~CAFFile();

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
	AFfileoffset m_dataOffset;
	AFfileoffset m_cookieDataOffset;
	SharedPtr<Buffer> m_codecData;

	status parseDescription(const Tag &, int64_t);
	status parseData(const Tag &, int64_t);
	status parsePacketTable(const Tag &, int64_t);
	status parseCookieData(const Tag &, int64_t);

	status writeDescription();
	status writeData(bool update);
	status writePacketTable();
	status writeCookieData();

	void initCompressionParams();
	void initIMACompressionParams();
	void initALACCompressionParams();
};

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef COMPILER_H
#define COMPILER_H

#if defined(__GNUC__) && !defined(__clang__)
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#define GCC_VERSION_AT_LEAST(major, minor, patch) \
	(GCC_VERSION >= (major * 10000 + minor * 100 + patch))
#if GCC_VERSION_AT_LEAST(4, 7, 0) && defined(__cplusplus) && __cplusplus >= 201103L
#define OVERRIDE override
#endif
#endif

#if defined(__clang__)
#if __has_extension(cxx_override_control)
#define OVERRRIDE override
#endif
#endif

#ifndef OVERRIDE
#define OVERRIDE
#endif

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "FLACFile.h"

#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "byteorder.h"
#include "util.h"

#include <string.h>

const int _af_flac_compression_types[_AF_FLAC_NUM_COMPTYPES] =
{
	AF_COMPRESSION_FLAC
};

const _AFfilesetup flacDefaultFileSetup =
{
	_AF_VALID_FILESETUP,
	AF_FILE_FLAC,
	true,
	true,
	true,
	1,		// trackCount
	NULL,	// tracks
	0,		// instrumentCount
	NULL,	// instruments
	0,		// miscellaneousCount
	NULL	// miscellaneous
};

bool FLACFile::recognize(File *file)
{
	file->seek(0, File::SeekFromBeginning);
	uint8_t buffer[4];
	if (file->read(buffer, 4) != 4 || memcmp(buffer, "fLaC", 4) != 0)
		return false;
	return true;
}

FLACFile::FLACFile()
{
}

FLACFile::~FLACFile()
{
}

#if ENABLE(FLAC)

AFfilesetup FLACFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "FLAC file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet &&
		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
	{
		_af_error(AF_BAD_SAMPFMT,
			"FLAC files support only signed integer audio data");
		return AF_NULL_FILESETUP;
	}

	if (track->sampleWidthSet &&
		track->f.sampleWidth != 16 && track->f.sampleWidth != 24)
	{
		_af_error(AF_BAD_WIDTH,
			"FLAC files support only 16- or 24-bit audio data");
		return AF_NULL_FILESETUP;
	}

	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);

	track->f.byteOrder = _AF_BYTEORDER_NATIVE;

	if (track->compressionSet &&
		track->f.compressionType != AF_COMPRESSION_FLAC)
	{
		_af_error(AF_BAD_COMPTYPE, "Only FLAC compression supported in FLAC files");
		return AF_NULL_FILESETUP;
	}

	track->f.compressionType = AF_COMPRESSION_FLAC;

	if (track->markersSet && track->markerCount)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "FLAC does not yet support markers");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "FLAC does not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount)
	{
		_af_error(AF_BAD_FILESETUP, "FLAC does not support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "FLAC does not yet support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &flacDefaultFileSetup, true);
}

status FLACFile::readInit(AFfilesetup)
{
	m_fh->seek(0, File::SeekFromBeginning);

	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();

	if (FLAC__stream_decoder_init_stream(decoder,
		readCallback,
		seekCallback,
		tellCallback,
		lengthCallback,
		eofCallback,
		writeCallback,
		metadataCallback,
		errorCallback,
		this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
	{
		_af_error(AF_BAD_HEADER, "could not read FLAC file");
		return AF_FAIL;
	}

	if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
		return AF_FAIL;

	FLAC__uint64 position;
	if (!FLAC__stream_decoder_get_decode_position(decoder, &position))
		return AF_FAIL;

	Track *track = getTrack();
	if (track)
	{
		track->fpos_first_frame = static_cast<off_t>(position);
		track->data_size = m_fh->length() - track->fpos_first_frame;
	}

	FLAC__stream_decoder_delete(decoder);

	if (!track)
		return AF_FAIL;
	return AF_SUCCEED;
}

status FLACFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	return AF_SUCCEED;
}

status FLACFile::update()
{
	return AF_SUCCEED;
}

void FLACFile::parseStreamInfo(const FLAC__StreamMetadata_StreamInfo &streamInfo)
{
	Track *track = allocateTrack();

	track->f.channelCount = streamInfo.channels;
	track->f.sampleRate = streamInfo.sample_rate;

	track->f.byteOrder = _AF_BYTEORDER_NATIVE;

	track->f.framesPerPacket = 0;
	track->f.bytesPerPacket = 0;

	track->f.compressionType = AF_COMPRESSION_FLAC;
	track->f.compressionParams = NULL;

	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, streamInfo.bits_per_sample);

	track->totalfframes = streamInfo.total_samples;
}

FLAC__StreamDecoderReadStatus FLACFile::readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	ssize_t result = flac->m_fh->read(buffer, *bytes);
	if (result > 0)
	{
		*bytes = result;
		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
	}

	*bytes = 0;
	return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}

FLAC__StreamDecoderSeekStatus FLACFile::seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	if (flac->m_fh->seek(static_cast<off_t>(absoluteByteOffset), File::SeekFromBeginning) < 0)
		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
	return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}

FLAC__StreamDecoderTellStatus FLACFile::tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	off_t result = flac->m_fh->tell();
	if (result < 0)
		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
	*absoluteByteOffset = static_cast<FLAC__uint64>(result);
	return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}

FLAC__StreamDecoderLengthStatus FLACFile::lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	off_t result = flac->m_fh->length();
	if (result < 0)
		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
	*length = result;
	return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}

FLAC__bool FLACFile::eofCallback(const FLAC__StreamDecoder *, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	return flac->m_fh->tell() == flac->m_fh->length();
}

FLAC__StreamDecoderWriteStatus FLACFile::writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData)
{
	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

void FLACFile::metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData)
{
	FLACFile *flac = static_cast<FLACFile *>(clientData);
	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
		flac->parseStreamInfo(metadata->data.stream_info);
}

void FLACFile::errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData)
{
	_af_error(AF_BAD_FILEFMT, "error %d parsing FLAC file", status);
}

#else

AFfilesetup FLACFile::completeSetup(AFfilesetup)
{
	_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
	return AF_NULL_FILESETUP;
}

status FLACFile::readInit(AFfilesetup)
{
	_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
	return AF_FAIL;
}

status FLACFile::writeInit(AFfilesetup)
{
	return AF_FAIL;
}

status FLACFile::update()
{
	return AF_FAIL;
}

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef FLACFile_h
#define FLACFile_h

#include "Compiler.h"
#include "FileHandle.h"
#include "Features.h"

#if ENABLE(FLAC)
#include <FLAC/format.h>
#include <FLAC/stream_decoder.h>
#endif

#define _AF_FLAC_NUM_COMPTYPES 1
extern const int _af_flac_compression_types[_AF_FLAC_NUM_COMPTYPES];

class FLACFile : public _AFfilehandle
{
public:
	static bool recognize(File *);
	static AFfilesetup completeSetup(AFfilesetup);

	FLACFile();
	~FLACFile();

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
#if ENABLE(FLAC)
	void parseStreamInfo(const FLAC__StreamMetadata_StreamInfo &);

	static FLAC__StreamDecoderReadStatus readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData);
	static FLAC__StreamDecoderSeekStatus seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData);
	static FLAC__StreamDecoderTellStatus tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData);
	static FLAC__StreamDecoderLengthStatus lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData);
	static FLAC__bool eofCallback(const FLAC__StreamDecoder *, void *clientData);
	static FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData);
	static void metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData);
	static void errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData);
#endif
};

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef Features_h
#define Features_h

#define ENABLE(FEATURE) (defined ENABLE_##FEATURE && ENABLE_##FEATURE)

#endif
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "File.h"

#include "Compiler.h"
#include "af_vfs.h"

#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

class FilePOSIX : public File
{
public:
	FilePOSIX(int fd, AccessMode mode) : File(mode), m_fd(fd) { }
	virtual ~FilePOSIX() { close(); }

	virtual int close() OVERRIDE;
	virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
	virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
	virtual off_t length() OVERRIDE;
	virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
	virtual off_t tell() OVERRIDE;

private:
	int m_fd;
};

class FileVF : public File
{
public:
	FileVF(AFvirtualfile *vf, AccessMode mode) : File(mode), m_vf(vf) { }
	virtual ~FileVF() { close(); }

	virtual int close() OVERRIDE;
	virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
	virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
	virtual off_t length() OVERRIDE;
	virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
	virtual off_t tell() OVERRIDE;

private:
	AFvirtualfile *m_vf;
};

File *File::open(const char *path, File::AccessMode mode)
{
	int flags = 0;
	if (mode == ReadAccess)
		flags = O_RDONLY;
	else if (mode == WriteAccess)
		flags = O_CREAT | O_WRONLY | O_TRUNC;
#if defined(WIN32) || defined(__CYGWIN__)
	flags |= O_BINARY;
#endif
	int fd = ::open(path, flags, 0666);
	if (fd == -1)
		return NULL;
	File *file = new FilePOSIX(fd, mode);
	return file;
}

File *File::create(int fd, File::AccessMode mode)
{
	return new FilePOSIX(fd, mode);
}

File *File::create(AFvirtualfile *vf, File::AccessMode mode)
{
	return new FileVF(vf, mode);
}

File::~File()
{
}

bool File::canSeek()
{
	return seek(0, File::SeekFromCurrent) != -1;
}

int FilePOSIX::close()
{
	if (m_fd == -1)
		return 0;

	int result = ::close(m_fd);
	m_fd = -1;
	return result;
}

ssize_t FilePOSIX::read(void *data, size_t nbytes)
{
	return ::read(m_fd, data, nbytes);
}

ssize_t FilePOSIX::write(const void *data, size_t nbytes)
{
	return ::write(m_fd, data, nbytes);
}

off_t FilePOSIX::length()
{
	off_t current = tell();
	if (current == -1)
		return -1;
	off_t length = seek(0, SeekFromEnd);
	if (length == -1)
		return -1;
	seek(current, SeekFromBeginning);
	return length;
}

off_t FilePOSIX::seek(off_t offset, File::SeekOrigin origin)
{
	int whence;
	switch (origin)
	{
		case SeekFromBeginning: whence = SEEK_SET; break;
		case SeekFromCurrent: whence = SEEK_CUR; break;
		case SeekFromEnd: whence = SEEK_END; break;
		default: assert(false); return -1;
	}
	return ::lseek(m_fd, offset, whence);
}

off_t FilePOSIX::tell()
{
	return seek(0, File::SeekFromCurrent);
}

int FileVF::close()
{
	if (m_vf)
		af_virtual_file_destroy(m_vf);
	m_vf = 0;
	return 0;
}

ssize_t FileVF::read(void *data, size_t nbytes)
{
	return m_vf->read(m_vf, data, nbytes);
}

ssize_t FileVF::write(const void *data, size_t nbytes)
{
	return m_vf->write(m_vf, data, nbytes);
}

off_t FileVF::length()
{
	return m_vf->length(m_vf);
}

off_t FileVF::seek(off_t offset, SeekOrigin origin)
{
	if (origin == SeekFromEnd)
		offset += length();
	return m_vf->seek(m_vf, offset, origin == SeekFromCurrent);
}

off_t FileVF::tell()
{
	return m_vf->tell(m_vf);
}
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef FILE_H
#define FILE_H

#include "Shared.h"
#include <sys/types.h>

typedef struct _AFvirtualfile AFvirtualfile;

class File : public Shared<File>
{
public:
	enum AccessMode
	{
		ReadAccess,
		WriteAccess
	};

	enum SeekOrigin
	{
		SeekFromBeginning,
		SeekFromCurrent,
		SeekFromEnd
	};

	static File *open(const char *path, AccessMode mode);
	static File *create(int fd, AccessMode mode);
	static File *create(AFvirtualfile *vf, AccessMode mode);

	virtual ~File();
	virtual int close() = 0;
	virtual ssize_t read(void *data, size_t nbytes) = 0;
	virtual ssize_t write(const void *data, size_t nbytes) = 0;
	virtual off_t length() = 0;
	virtual off_t seek(off_t offset, SeekOrigin origin) = 0;
	virtual off_t tell() = 0;

	bool canSeek();

	AccessMode accessMode() const { return m_accessMode; }

private:
	AccessMode m_accessMode;

protected:
	File(AccessMode mode) : m_accessMode(mode) { }
};

#endif // FILE_H
/*
	Audio File Library
	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "FileHandle.h"

#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include <stdlib.h>
#include <assert.h>

#include "AIFF.h"
#include "AVR.h"
#include "CAF.h"
#include "FLACFile.h"
#include "IFF.h"
#include "IRCAM.h"
#include "NeXT.h"
#include "NIST.h"
#include "Raw.h"
#include "SampleVision.h"
#include "VOC.h"
#include "WAVE.h"

#include "File.h"
#include "Instrument.h"
#include "Setup.h"
#include "Tag.h"
#include "Track.h"
#include "units.h"
#include "util.h"

static void freeInstParams (AFPVu *values, int fileFormat)
{
	if (!values)
		return;

	int parameterCount = _af_units[fileFormat].instrumentParameterCount;

	for (int i=0; i<parameterCount; i++)
	{
		if (_af_units[fileFormat].instrumentParameters[i].type == AU_PVTYPE_PTR)
			free(values[i].v);
	}

	free(values);
}

_AFfilehandle *_AFfilehandle::create(int fileFormat)
{
	switch (fileFormat)
	{
		case AF_FILE_RAWDATA:
			return new RawFile();
		case AF_FILE_AIFF:
		case AF_FILE_AIFFC:
			return new AIFFFile();
		case AF_FILE_NEXTSND:
			return new NeXTFile();
		case AF_FILE_WAVE:
			return new WAVEFile();
		case AF_FILE_BICSF:
			return new IRCAMFile();
		case AF_FILE_AVR:
			return new AVRFile();
		case AF_FILE_IFF_8SVX:
			return new IFFFile();
		case AF_FILE_SAMPLEVISION:
			return new SampleVisionFile();
		case AF_FILE_VOC:
			return new VOCFile();
		case AF_FILE_NIST_SPHERE:
			return new NISTFile();
		case AF_FILE_CAF:
			return new CAFFile();
		case AF_FILE_FLAC:
			return new FLACFile();
		default:
			return NULL;
	}
}

_AFfilehandle::_AFfilehandle()
{
	m_valid = _AF_VALID_FILEHANDLE;
	m_access = 0;
	m_seekok = false;
	m_fh = NULL;
	m_fileName = NULL;
	m_fileFormat = AF_FILE_UNKNOWN;
	m_trackCount = 0;
	m_tracks = NULL;
	m_instrumentCount = 0;
	m_instruments = NULL;
	m_miscellaneousCount = 0;
	m_miscellaneous = NULL;
	m_formatByteOrder = 0;
}

_AFfilehandle::~_AFfilehandle()
{
	m_valid = 0;

	free(m_fileName);

	delete [] m_tracks;
	m_tracks = NULL;
	m_trackCount = 0;

	if (m_instruments)
	{
		for (int i=0; i<m_instrumentCount; i++)
		{
			free(m_instruments[i].loops);
			m_instruments[i].loops = NULL;
			m_instruments[i].loopCount = 0;

			freeInstParams(m_instruments[i].values, m_fileFormat);
			m_instruments[i].values = NULL;
		}

		free(m_instruments);
		m_instruments = NULL;
	}
	m_instrumentCount = 0;

	if (m_miscellaneous)
	{
		for (int i=0; i<m_miscellaneousCount; i++)
			free(m_miscellaneous[i].buffer);
		free(m_miscellaneous);
		m_miscellaneous = NULL;
	}
	m_miscellaneousCount = 0;
}

Track *_AFfilehandle::allocateTrack()
{
	assert(!m_trackCount);
	assert(!m_tracks);

	m_trackCount = 1;
	m_tracks = new Track[1];
	return m_tracks;
}

Track *_AFfilehandle::getTrack(int trackID)
{
	for (int i=0; i<m_trackCount; i++)
		if (m_tracks[i].id == trackID)
			return &m_tracks[i];

	_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);

	return NULL;
}

bool _AFfilehandle::checkCanRead()
{
	if (m_access != _AF_READ_ACCESS)
	{
		_af_error(AF_BAD_NOREADACC, "file not opened for read access");
		return false;
	}

	return true;
}

bool _AFfilehandle::checkCanWrite()
{
	if (m_access != _AF_WRITE_ACCESS)
	{
		_af_error(AF_BAD_NOWRITEACC, "file not opened for write access");
		return false;
	}

	return true;
}

Instrument *_AFfilehandle::getInstrument(int instrumentID)
{
	for (int i = 0; i < m_instrumentCount; i++)
		if (m_instruments[i].id == instrumentID)
			return &m_instruments[i];

	_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
	return NULL;
}

Miscellaneous *_AFfilehandle::getMiscellaneous(int miscellaneousID)
{
	for (int i=0; i<m_miscellaneousCount; i++)
	{
		if (m_miscellaneous[i].id == miscellaneousID)
			return &m_miscellaneous[i];
	}

	_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);

	return NULL;
}

status _AFfilehandle::initFromSetup(AFfilesetup setup)
{
	if (copyTracksFromSetup(setup) == AF_FAIL)
		return AF_FAIL;
	if (copyInstrumentsFromSetup(setup) == AF_FAIL)
		return AF_FAIL;
	if (copyMiscellaneousFromSetup(setup) == AF_FAIL)
		return AF_FAIL;
	return AF_SUCCEED;
}

status _AFfilehandle::copyTracksFromSetup(AFfilesetup setup)
{
	if ((m_trackCount = setup->trackCount) == 0)
	{
		m_tracks = NULL;
		return AF_SUCCEED;
	}

	m_tracks = new Track[m_trackCount];
	if (!m_tracks)
		return AF_FAIL;

	for (int i=0; i<m_trackCount; i++)
	{
		Track *track = &m_tracks[i];
		TrackSetup *trackSetup = &setup->tracks[i];

		track->id = trackSetup->id;
		track->f = trackSetup->f;

		if (track->copyMarkers(trackSetup) == AF_FAIL)
			return AF_FAIL;

		track->hasAESData = trackSetup->aesDataSet;
	}

	return AF_SUCCEED;
}

status _AFfilehandle::copyInstrumentsFromSetup(AFfilesetup setup)
{
	if ((m_instrumentCount = setup->instrumentCount) == 0)
	{
		m_instruments = NULL;
		return AF_SUCCEED;
	}

	m_instruments = static_cast<Instrument *>(_af_calloc(m_instrumentCount,
		sizeof (Instrument)));
	if (!m_instruments)
		return AF_FAIL;

	for (int i=0; i<m_instrumentCount; i++)
	{
		m_instruments[i].id = setup->instruments[i].id;

		// Copy loops.
		if ((m_instruments[i].loopCount = setup->instruments[i].loopCount) == 0)
		{
			m_instruments[i].loops = NULL;
		}
		else
		{
			m_instruments[i].loops =
				static_cast<Loop *>(_af_calloc(m_instruments[i].loopCount,
					sizeof (Loop)));
			if (!m_instruments[i].loops)
				return AF_FAIL;
			for (int j=0; j<m_instruments[i].loopCount; j++)
			{
				Loop *loop = &m_instruments[i].loops[j];
				loop->id = setup->instruments[i].loops[j].id;
				loop->mode = AF_LOOP_MODE_NOLOOP;
				loop->count = 0;
				loop->trackid = AF_DEFAULT_TRACK;
				loop->beginMarker = 2*j + 1;
				loop->endMarker = 2*j + 2;
			}
		}

		int instParamCount;
		// Copy instrument parameters.
		if ((instParamCount = _af_units[setup->fileFormat].instrumentParameterCount) == 0)
		{
			m_instruments[i].values = NULL;
		}
		else
		{
			m_instruments[i].values =
				static_cast<AFPVu *>(_af_calloc(instParamCount, sizeof (AFPVu)));
			if (!m_instruments[i].values)
				return AF_FAIL;
			for (int j=0; j<instParamCount; j++)
			{
				m_instruments[i].values[j] = _af_units[setup->fileFormat].instrumentParameters[j].defaultValue;
			}
		}
	}

	return AF_SUCCEED;
}

status _AFfilehandle::copyMiscellaneousFromSetup(AFfilesetup setup)
{
	if ((m_miscellaneousCount = setup->miscellaneousCount) == 0)
	{
		m_miscellaneous = NULL;
		return AF_SUCCEED;
	}

	m_miscellaneous = static_cast<Miscellaneous *>(_af_calloc(m_miscellaneousCount,
		sizeof (Miscellaneous)));
	if (!m_miscellaneous)
		return AF_FAIL;

	for (int i=0; i<m_miscellaneousCount; i++)
	{
		m_miscellaneous[i].id = setup->miscellaneous[i].id;
		m_miscellaneous[i].type = setup->miscellaneous[i].type;
		m_miscellaneous[i].size = setup->miscellaneous[i].size;
		m_miscellaneous[i].position = 0;
		m_miscellaneous[i].buffer = NULL;
	}

	return AF_SUCCEED;
}

template <typename T>
static bool readValue(File *f, T *value)
{
	return f->read(value, sizeof (*value)) == sizeof (*value);
}

template <typename T>
static bool writeValue(File *f, const T *value)
{
	return f->write(value, sizeof (*value)) == sizeof (*value);
}

template <typename T>
static T swapValue(T value, int order)
{
	if (order == AF_BYTEORDER_BIGENDIAN)
		return bigToHost(value);
	else if (order == AF_BYTEORDER_LITTLEENDIAN)
		return littleToHost(value);
	return value;
}

template <typename T>
static bool readSwap(File *f, T *value, int order)
{
	if (!readValue(f, value)) return false;
	*value = swapValue(*value, order);
	return true;
}

template <typename T>
static bool writeSwap(File *f, const T *value, int order)
{
	T t = swapValue(*value, order);
	return writeValue(f, &t);
}

bool _AFfilehandle::readU8(uint8_t *v) { return readValue(m_fh, v); }
bool _AFfilehandle::readS8(int8_t *v) { return readValue(m_fh, v); }

bool _AFfilehandle::readU16(uint16_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readS16(int16_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readU32(uint32_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readS32(int32_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readU64(uint64_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readS64(int64_t *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readFloat(float *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readDouble(double *v)
{
	return readSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeU8(const uint8_t *v) { return writeValue(m_fh, v); }
bool _AFfilehandle::writeS8(const int8_t *v) { return writeValue(m_fh, v); }

bool _AFfilehandle::writeU16(const uint16_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeS16(const int16_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeU32(const uint32_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeS32(const int32_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeU64(const uint64_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeS64(const int64_t *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeFloat(const float *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::writeDouble(const double *v)
{
	return writeSwap(m_fh, v, m_formatByteOrder);
}

bool _AFfilehandle::readTag(Tag *t)
{
	uint32_t v;
	if (m_fh->read(&v, sizeof (v)) == sizeof (v))
	{
		*t = Tag(v);
		return true;
	}
	return false;
}

bool _AFfilehandle::writeTag(const Tag *t)
{
	uint32_t v = t->value();
	return m_fh->write(&v, sizeof (v)) == sizeof (v);
}
/*
	Audio File Library
	Copyright (C) 2010-2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef FILEHANDLE_H
#define FILEHANDLE_H

#include "afinternal.h"
#include <stdint.h>

class File;
class Tag;
struct Instrument;
struct Miscellaneous;
struct Track;

struct _AFfilehandle
{
	static _AFfilehandle *create(int fileFormat);

	int m_valid;	// _AF_VALID_FILEHANDLE
	int m_access;	// _AF_READ_ACCESS or _AF_WRITE_ACCESS

	bool m_seekok;

	File *m_fh;

	char *m_fileName;

	int m_fileFormat;

	int m_trackCount;
	Track *m_tracks;

	int m_instrumentCount;
	Instrument *m_instruments;

	int m_miscellaneousCount;
	Miscellaneous *m_miscellaneous;

private:
	int m_formatByteOrder;

	status copyTracksFromSetup(AFfilesetup setup);
	status copyInstrumentsFromSetup(AFfilesetup setup);
	status copyMiscellaneousFromSetup(AFfilesetup setup);

public:
	virtual ~_AFfilehandle();

	virtual int getVersion() { return 0; }
	virtual status readInit(AFfilesetup) = 0;
	virtual status writeInit(AFfilesetup) = 0;
	virtual status update() = 0;
	virtual bool isInstrumentParameterValid(AUpvlist, int) { return false; }

	bool checkCanRead();
	bool checkCanWrite();

	Track *allocateTrack();
	Track *getTrack(int trackID = AF_DEFAULT_TRACK);
	Instrument *getInstrument(int instrumentID);
	Miscellaneous *getMiscellaneous(int miscellaneousID);

protected:
	_AFfilehandle();

	status initFromSetup(AFfilesetup setup);

	void setFormatByteOrder(int byteOrder) { m_formatByteOrder = byteOrder; }

	bool readU8(uint8_t *);
	bool readS8(int8_t *);
	bool readU16(uint16_t *);
	bool readS16(int16_t *);
	bool readU32(uint32_t *);
	bool readS32(int32_t *);
	bool readU64(uint64_t *);
	bool readS64(int64_t *);
	bool readFloat(float *);
	bool readDouble(double *);

	bool writeU8(const uint8_t *);
	bool writeS8(const int8_t *);
	bool writeU16(const uint16_t *);
	bool writeS16(const int16_t *);
	bool writeU32(const uint32_t *);
	bool writeS32(const int32_t *);
	bool writeU64(const uint64_t *);
	bool writeS64(const int64_t *);
	bool writeFloat(const float *);
	bool writeDouble(const double *);

	bool readTag(Tag *t);
	bool writeTag(const Tag *t);
};

#endif
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	IFF.cpp

	This file contains routines for reading and writing IFF/8SVX
	sound files.
*/

#include "config.h"
#include "IFF.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Marker.h"
#include "Setup.h"
#include "Tag.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"

static const _AFfilesetup iffDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_IFF_8SVX,	/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

bool IFFFile::recognize(File *fh)
{
	uint8_t buffer[8];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
		return false;
	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "8SVX", 4) != 0)
		return false;

	return true;
}

IFFFile::IFFFile()
{
	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);

	m_miscellaneousPosition = 0;
	m_VHDR_offset = 0;
	m_BODY_offset = 0;
}

/*
	Parse miscellaneous data chunks such as name, author, copyright,
	and annotation chunks.
*/
status IFFFile::parseMiscellaneous(const Tag &type, size_t size)
{
	int misctype = AF_MISC_UNRECOGNIZED;

	assert(type == "NAME" || type == "AUTH" ||
		type == "(c) " || type == "ANNO");

	/* Skip zero-length miscellaneous chunks. */
	if (size == 0)
		return AF_FAIL;

	m_miscellaneousCount++;
	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
		m_miscellaneousCount * sizeof (Miscellaneous));

	if (type == "NAME")
		misctype = AF_MISC_NAME;
	else if (type == "AUTH")
		misctype = AF_MISC_AUTH;
	else if (type == "(c) ")
		misctype = AF_MISC_COPY;
	else if (type == "ANNO")
		misctype = AF_MISC_ANNO;

	m_miscellaneous[m_miscellaneousCount - 1].id = m_miscellaneousCount;
	m_miscellaneous[m_miscellaneousCount - 1].type = misctype;
	m_miscellaneous[m_miscellaneousCount - 1].size = size;
	m_miscellaneous[m_miscellaneousCount - 1].position = 0;
	m_miscellaneous[m_miscellaneousCount - 1].buffer = _af_malloc(size);
	m_fh->read(m_miscellaneous[m_miscellaneousCount - 1].buffer, size);

	return AF_SUCCEED;
}

/*
	Parse voice header chunk.
*/
status IFFFile::parseVHDR(const Tag &type, size_t size)
{
	assert(type == "VHDR");

	Track *track = getTrack();

	uint32_t oneShotSamples, repeatSamples, samplesPerRepeat;
	uint16_t sampleRate;
	uint8_t octaves, compression;
	uint32_t volume;

	readU32(&oneShotSamples);
	readU32(&repeatSamples);
	readU32(&samplesPerRepeat);
	readU16(&sampleRate);
	readU8(&octaves);
	readU8(&compression);
	readU32(&volume);

	track->f.sampleWidth = 8; 
	track->f.sampleRate = sampleRate;
	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
	track->f.compressionType = AF_COMPRESSION_NONE;
	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
	track->f.channelCount = 1;

	track->f.framesPerPacket = 1;
	track->f.computeBytesPerPacketPCM();

	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);

	return AF_SUCCEED;
}

status IFFFile::parseBODY(const Tag &type, size_t size)
{
	Track *track = getTrack();

	/*
		IFF/8SVX files have only one audio channel with one
		byte per sample, so the number of frames is equal to
		the number of bytes.
	*/
	track->totalfframes = size;
	track->data_size = size;

	/* Sound data follows. */
	track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}

status IFFFile::readInit(AFfilesetup setup)
{
	m_fh->seek(0, File::SeekFromBeginning);

	Tag type;
	uint32_t size;
	Tag formtype;

	readTag(&type);
	readU32(&size);
	readTag(&formtype);

	if (type != "FORM" || formtype != "8SVX")
		return AF_FAIL;

	/* IFF/8SVX files have only one track. */
	Track *track = allocateTrack();
	if (!track)
		return AF_FAIL;

	/* Set the index to include the form type ('8SVX' in this case). */
	size_t index = 4;
	while (index < size)
	{
		Tag chunkid;
		uint32_t chunksize = 0;
		status result = AF_SUCCEED;

		readTag(&chunkid);
		readU32(&chunksize);

		if (chunkid == "VHDR")
		{
			result = parseVHDR(chunkid, chunksize);
		}
		else if (chunkid == "BODY")
		{
			result = parseBODY(chunkid, chunksize);
		}
		else if (chunkid == "NAME" ||
			chunkid == "AUTH" ||
			chunkid == "(c) " ||
			chunkid == "ANNO")
		{
			parseMiscellaneous(chunkid, chunksize);
		}

		if (result == AF_FAIL)
			return AF_FAIL;

		/*
			Increment the index by the size of the chunk
			plus the size of the chunk header.
		*/
		index += chunksize + 8;

		/* All chunks must be aligned on an even number of bytes. */
		if ((index % 2) != 0)
			index++;

		/* Set the seek position to the beginning of the next chunk. */
		m_fh->seek(index + 8, File::SeekFromBeginning);
	}

	/* The file has been successfully parsed. */
	return AF_SUCCEED;
}

AFfilesetup IFFFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "IFF/8SVX file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet &&
		track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
	{
		_af_error(AF_BAD_SAMPFMT,
			"IFF/8SVX format supports only two's complement integer data");
		return AF_NULL_FILESETUP;
	}

	if (track->sampleFormatSet && track->f.sampleWidth != 8)
	{
		_af_error(AF_BAD_WIDTH,
			"IFF/8SVX file allows only 8 bits per sample "
			"(%d bits requested)", track->f.sampleWidth);
		return AF_NULL_FILESETUP;
	}

	if (track->channelCountSet && track->f.channelCount != 1)
	{
		_af_error(AF_BAD_CHANNELS,
			"invalid channel count (%d) for IFF/8SVX format "
			"(only 1 channel supported)",
			track->f.channelCount);
		return AF_NULL_FILESETUP;
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"IFF/8SVX does not support compression");
		return AF_NULL_FILESETUP;
	}

	/* Ignore requested byte order since samples are only one byte. */
	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
	/* Either one channel was requested or no request was made. */
	track->f.channelCount = 1;
	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 8);

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_NUMMARKS,
			"IFF/8SVX format does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "IFF/8SVX format does not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_NUMINSTS,
			"IFF/8SVX format does not support instruments");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &iffDefaultFileSetup, true);
}

status IFFFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	uint32_t fileSize = 0;

	m_fh->write("FORM", 4);
	writeU32(&fileSize);

	m_fh->write("8SVX", 4);

	writeVHDR();
	writeMiscellaneous();
	writeBODY();

	return AF_SUCCEED;
}

status IFFFile::update()
{
	uint32_t length;

	writeVHDR();
	writeMiscellaneous();
	writeBODY();

	/* Get the length of the file. */
	length = m_fh->length();
	length -= 8;

	/* Set the length of the FORM chunk. */
	m_fh->seek(4, File::SeekFromBeginning);
	writeU32(&length);

	return AF_SUCCEED;
}

status IFFFile::writeVHDR()
{
	uint32_t chunkSize;
	uint32_t oneShotSamples, repeatSamples, samplesPerRepeat;
	uint16_t sampleRate;
	uint8_t octaves, compression;
	uint32_t volume;

	/*
		If VHDR_offset hasn't been set yet, set it to the
		current offset.
	*/
	if (m_VHDR_offset == 0)
		m_VHDR_offset = m_fh->tell();
	else
		m_fh->seek(m_VHDR_offset, File::SeekFromBeginning);

	Track *track = getTrack();

	m_fh->write("VHDR", 4);

	chunkSize = 20;
	writeU32(&chunkSize);

	/*
		IFF/8SVX files have only one audio channel, so the
		number of samples is equal to the number of frames.
	*/
	oneShotSamples = track->totalfframes;
	writeU32(&oneShotSamples);
	repeatSamples = 0;
	writeU32(&repeatSamples);
	samplesPerRepeat = 0;
	writeU32(&samplesPerRepeat);

	sampleRate = track->f.sampleRate;
	writeU16(&sampleRate);

	octaves = 0;
	compression = 0;
	writeU8(&octaves);
	writeU8(&compression);

	/* Volume is in fixed-point notation; 65536 means gain of 1.0. */
	volume = 65536;
	writeU32(&volume);

	return AF_SUCCEED;
}

status IFFFile::writeBODY()
{
	uint32_t chunkSize;

	Track *track = getTrack();

	if (m_BODY_offset == 0)
		m_BODY_offset = m_fh->tell();
	else
		m_fh->seek(m_BODY_offset, File::SeekFromBeginning);

	m_fh->write("BODY", 4);

	/*
		IFF/8SVX supports only one channel, so the number of
		frames is equal to the number of samples, and each
		sample is one byte.
	*/
	chunkSize = track->totalfframes;
	writeU32(&chunkSize);

	if (track->fpos_first_frame == 0)
		track->fpos_first_frame = m_fh->tell();

	/* Add a pad byte to the end of the chunk if the chunk size is odd. */
	if ((chunkSize % 2) == 1)
	{
		uint8_t zero = 0;
		m_fh->seek(m_BODY_offset + 8 + chunkSize, File::SeekFromBeginning);
		writeU8(&zero);
	}

	return AF_SUCCEED;
}

/*
	WriteMiscellaneous writes all the miscellaneous data chunks in a
	file handle structure to an IFF/8SVX file.
*/
status IFFFile::writeMiscellaneous()
{
	if (m_miscellaneousPosition == 0)
		m_miscellaneousPosition = m_fh->tell();
	else
		m_fh->seek(m_miscellaneousPosition, File::SeekFromBeginning);

	for (int i=0; i<m_miscellaneousCount; i++)
	{
		Miscellaneous *misc = &m_miscellaneous[i];
		Tag chunkType;
		uint32_t chunkSize;
		uint8_t padByte = 0;

		switch (misc->type)
		{
			case AF_MISC_NAME:
				chunkType = "NAME"; break;
			case AF_MISC_AUTH:
				chunkType = "AUTH"; break;
			case AF_MISC_COPY:
				chunkType = "(c) "; break;
			case AF_MISC_ANNO:
				chunkType = "ANNO"; break;
		}

		writeTag(&chunkType);

		chunkSize = misc->size;
		writeU32(&chunkSize);

		/*
			Write the miscellaneous buffer and then a pad byte
			if necessary.  If the buffer is null, skip the space
			for now.
		*/
		if (misc->buffer != NULL)
			m_fh->write(misc->buffer, misc->size);
		else
			m_fh->seek(misc->size, File::SeekFromCurrent);

		if (misc->size % 2 != 0)
			writeU8(&padByte);
	}

	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	IFF.h

	This file declares constants and functions related to the
	IFF/8SVX file format.
*/

#ifndef IFF_H
#define IFF_H

#include "Compiler.h"
#include "FileHandle.h"

class IFFFile : public _AFfilehandle
{
public:
	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	IFFFile();
	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
	AFfileoffset m_miscellaneousPosition;
	AFfileoffset m_VHDR_offset;
	AFfileoffset m_BODY_offset;

	status parseMiscellaneous(const Tag &type, size_t size);
	status parseVHDR(const Tag &type, size_t size);
	status parseBODY(const Tag &type, size_t size);

	status writeVHDR();
	status writeMiscellaneous();
	status writeBODY();
};

#endif
/*
	Audio File Library
	Copyright (C) 2001, Silicon Graphics, Inc.
	Copyright (C) 2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	IRCAM.cpp

	This file contains routines for reading and writing
	Berkeley/IRCAM/CARL sound files.
*/

#include "config.h"
#include "IRCAM.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Marker.h"
#include "Setup.h"
#include "Track.h"
#include "byteorder.h"
#include "util.h"

enum
{
	SF_CHAR = 1,
	SF_SHORT = 2,
	SF_24INT = 3,
	SF_LONG = 0x40004,
	SF_FLOAT = 4,
	SF_DOUBLE = 8,
	SF_ALAW = 0x10001,
	SF_ULAW = 0x20001
};

#define SF_MAXCHAN 4
#define SF_MAXCOMMENT 512
#define SF_MINCOMMENT 256

enum
{
	SF_END,
	SF_MAXAMP,
	SF_COMMENT,
	SF_LINKCODE
};

#define SIZEOF_BSD_HEADER 1024

static const uint8_t ircam_vax_le_magic[4] = {0x64, 0xa3, 0x01, 0x00},
	ircam_vax_be_magic[4] = {0x00, 0x01, 0xa3, 0x64},
	ircam_sun_be_magic[4] = {0x64, 0xa3, 0x02, 0x00},
	ircam_sun_le_magic[4] = {0x00, 0x02, 0xa3, 0x64},
	ircam_mips_le_magic[4] = {0x64, 0xa3, 0x03, 0x00},
	ircam_mips_be_magic[4] = {0x00, 0x03, 0xa3, 0x64},
	ircam_next_be_magic[4] = {0x64, 0xa3, 0x04, 0x00},
	ircam_next_le_magic[4] = {0x00, 0x04, 0xa3, 0x64};

static const _AFfilesetup ircam_default_filesetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_IRCAM,		/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

const int _af_ircam_compression_types[_AF_IRCAM_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW
};

bool IRCAMFile::recognize(File *fh)
{
	uint8_t buffer[4];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 4) != 4)
		return false;

	/* Check to see if the file's magic number matches. */
	if (!memcmp(buffer, ircam_vax_le_magic, 4) ||
		!memcmp(buffer, ircam_vax_be_magic, 4) ||
		!memcmp(buffer, ircam_sun_be_magic, 4) ||
		!memcmp(buffer, ircam_sun_le_magic, 4) ||
		!memcmp(buffer, ircam_mips_le_magic, 4) ||
		!memcmp(buffer, ircam_mips_be_magic, 4) ||
		!memcmp(buffer, ircam_next_be_magic, 4) ||
		!memcmp(buffer, ircam_next_le_magic, 4))
	{
		return true;
	}

	return false;
}

AFfilesetup IRCAMFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "BICSF file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		if (track->f.isUnsigned())
		{
			_af_error(AF_BAD_SAMPFMT,
				"BICSF format does not support unsigned data");
			return AF_NULL_FILESETUP;
		}

		if (track->f.isSigned() &&
			track->f.sampleWidth != 8 &&
			track->f.sampleWidth != 16 &&
			track->f.sampleWidth != 24 &&
			track->f.sampleWidth != 32)
		{
			_af_error(AF_BAD_WIDTH,
				"BICSF format supports only 8-, 16-, 24-, or 32-bit "
				"two's complement audio data");
			return AF_NULL_FILESETUP;
		}
	}

	if (track->rateSet && track->f.sampleRate <= 0.0)
	{
		_af_error(AF_BAD_RATE,
			"invalid sample rate %.30g for BICSF file",
			track->f.sampleRate);
		return AF_NULL_FILESETUP;
	}

	if (track->channelCountSet && track->f.channelCount != 1 &&
		track->f.channelCount != 2 && track->f.channelCount != 4)
	{
		_af_error(AF_BAD_CHANNELS,
			"invalid channel count (%d) for BICSF format "
			"(1, 2, or 4 channels only)",
			track->f.channelCount);
		return AF_NULL_FILESETUP;
	}

	if (track->compressionSet &&
		track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED,
			"BICSF format does not support compression type %d",
			track->f.compressionType);
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "BICSF file cannot have AES data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_NUMMARKS, "BICSF format does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_NUMINSTS, "BICSF format does not support instruments");
		return AF_NULL_FILESETUP;
	}

	/* XXXmpruett: We don't support miscellaneous chunks for now. */
	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "BICSF format does not currently support miscellaneous chunks");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &ircam_default_filesetup, true);
}

status IRCAMFile::readInit(AFfilesetup setup)
{
	float maxAmp = 1.0;

	m_fh->seek(0, File::SeekFromBeginning);

	uint8_t magic[4];
	if (m_fh->read(magic, 4) != 4)
	{
		_af_error(AF_BAD_READ, "Could not read BICSF file header");
		return AF_FAIL;
	}

	if (memcmp(magic, ircam_vax_le_magic, 4) != 0 &&
		memcmp(magic, ircam_vax_be_magic, 4) != 0 &&
		memcmp(magic, ircam_sun_be_magic, 4) != 0 &&
		memcmp(magic, ircam_sun_le_magic, 4) != 0 &&
		memcmp(magic, ircam_mips_le_magic, 4) != 0 &&
		memcmp(magic, ircam_mips_be_magic, 4) != 0 &&
		memcmp(magic, ircam_next_be_magic, 4) != 0 &&
		memcmp(magic, ircam_next_le_magic, 4) != 0)
	{
		_af_error(AF_BAD_FILEFMT,
			"file is not a BICSF file (bad magic number)");
		return AF_FAIL;
	}

	// Check whether the file's magic number indicates little-endian data.
	bool isLittleEndian = !memcmp(magic, ircam_vax_le_magic, 4) ||
		!memcmp(magic, ircam_sun_le_magic, 4) ||
		!memcmp(magic, ircam_mips_le_magic, 4) ||
		!memcmp(magic, ircam_next_le_magic, 4);

	setFormatByteOrder(isLittleEndian ? AF_BYTEORDER_LITTLEENDIAN :
		AF_BYTEORDER_BIGENDIAN);

	float rate;
	readFloat(&rate);
	uint32_t channels;
	readU32(&channels);
	uint32_t packMode;
	readU32(&packMode);

	Track *track = allocateTrack();
	if (!track)
		return AF_FAIL;

	track->f.sampleRate = rate;
	track->f.compressionType = AF_COMPRESSION_NONE;

	if (isLittleEndian)
		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
	else
		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	if (channels != 1 && channels != 2 && channels != 4)
	{
		_af_error(AF_BAD_FILEFMT,
			"invalid channel count (%d) for BICSF format (1, 2, or 4 only)",
			channels);
		return AF_FAIL;
	}

	track->f.channelCount = channels;

	track->f.framesPerPacket = 1;

	switch (packMode)
	{
		case SF_CHAR:
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 8;
			break;
		case SF_SHORT:
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 16;
			break;
		case SF_24INT:
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 24;
			break;
		case SF_LONG:
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 32;
			break;
		case SF_FLOAT:
			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
			track->f.sampleWidth = 32;
			break;
		case SF_DOUBLE:
			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
			track->f.sampleWidth = 64;
			break;
		case SF_ALAW:
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 16;
			track->f.bytesPerPacket = channels;
			break;
		case SF_ULAW:
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.sampleWidth = 16;
			track->f.bytesPerPacket = channels;
			break;
		default:
			_af_error(AF_BAD_NOT_IMPLEMENTED,
				"BICSF data format %d not supported", packMode);
			return AF_FAIL;
	}

	if (track->f.isUncompressed())
		track->f.computeBytesPerPacketPCM();

	if (_af_set_sample_format(&track->f, track->f.sampleFormat,
		track->f.sampleWidth) == AF_FAIL)
	{
		return AF_FAIL;
	}

	if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
		track->f.pcm.slope = maxAmp;

	track->data_size = m_fh->length() - SIZEOF_BSD_HEADER;
	track->computeTotalFileFrames();

	track->fpos_first_frame = SIZEOF_BSD_HEADER;

	return AF_SUCCEED;
}

/* We write IRCAM files using the native byte order. */
status IRCAMFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	uint32_t dataOffset = SIZEOF_BSD_HEADER;

	Track *track = getTrack();
	track->fpos_first_frame = dataOffset;

	/* Choose the magic number appropriate for the byte order. */
	const uint8_t *magic;
#ifdef WORDS_BIGENDIAN
	magic = ircam_sun_be_magic;
#else
	magic = ircam_vax_le_magic;
#endif

	uint32_t channels = track->f.channelCount;
	float rate = track->f.sampleRate;

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
	{
		_af_error(AF_BAD_COMPTYPE,
			"unsupported compression type %d in IRCAM sound file",
			track->f.compressionType);
		return AF_FAIL;
	}

	uint32_t packMode = 0;
	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
		packMode = SF_ULAW;
	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
		packMode = SF_ALAW;
	else if (track->f.isSigned())
	{
		switch (track->f.bytesPerSample(false))
		{
			case 1: packMode = SF_CHAR; break;
			case 2: packMode = SF_SHORT; break;
			case 3: packMode = SF_24INT; break;
			case 4: packMode = SF_LONG; break;
			default:
				_af_error(AF_BAD_SAMPFMT,
					"unsupported sample width %d for two's complement BICSF file",
					track->f.sampleWidth);
				return AF_FAIL;
		}
	}
	else if (track->f.isFloat())
	{
		if (track->f.sampleWidth == 32)
			packMode = SF_FLOAT;
		else if (track->f.sampleWidth == 64)
			packMode = SF_DOUBLE;
		else
		{
			_af_error(AF_BAD_SAMPFMT,
				"unsupported sample width %d for BICSF file",
				track->f.sampleWidth);
			return AF_FAIL;
		}
	}
	else if (track->f.isUnsigned())
	{
		_af_error(AF_BAD_SAMPFMT, "BICSF format does not support unsigned integer audio data");
		return AF_FAIL;
	}

	m_fh->seek(0, File::SeekFromBeginning);
	m_fh->write(magic, 4);
	writeFloat(&rate);
	writeU32(&channels);
	writeU32(&packMode);

	/* Zero the entire description block. */
	uint8_t zeros[SIZEOF_BSD_HEADER];
	memset(zeros, 0, SIZEOF_BSD_HEADER);
	m_fh->write(zeros, SIZEOF_BSD_HEADER - 4*4);

	return AF_SUCCEED;
}

status IRCAMFile::update()
{
	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2001, Silicon Graphics, Inc.
	Copyright (C) 2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	IRCAM.h

	This file contains constants and function prototypes related to
	the Berkeley/IRCAM/CARL Sound File format.
*/

#ifndef IRCAM_H
#define IRCAM_H

#include "Compiler.h"
#include "FileHandle.h"

#define _AF_IRCAM_NUM_COMPTYPES 2
extern const int _af_ircam_compression_types[_AF_IRCAM_NUM_COMPTYPES];

class IRCAMFile : public _AFfilehandle
{
public:
	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;
};

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Instrument.cpp

	Info about instrument parameters:

	Each unit has an array of _InstParamInfo structures, one for
	each instrument parameter.  Each of these structures describes
	the inst parameters.

	id: a 4-byte id as in AIFF file
	type: data type AU_PVLIST_*
	name: text name
	defaultValue: default value, to which it is set when a file with
		instruments is first opened for writing.

	Each inst has only an array of values (_AFPVu's).  Each value in the
	instrument's array is the value of the corresponding index into the
	unit's instparaminfo array.

	So for a unit u and an instrument i, u.instparam[N] describes
	the parameter whose value is given in i.value[N].
*/

#include "config.h"

#include "FileHandle.h"
#include "Instrument.h"
#include "Setup.h"
#include "afinternal.h"
#include "audiofile.h"
#include "units.h"
#include "util.h"

#include <stdlib.h>

bool InstrumentSetup::allocateLoops(int count)
{
	freeLoops();
	loops = (LoopSetup *) _af_calloc(count, sizeof (LoopSetup));
	if (loops)
	{
		loopCount = count;
		return true;
	}
	return false;
}

void InstrumentSetup::freeLoops()
{
	if (loops)
		free(loops);
	loops = NULL;
	loopCount = 0;
}

/*
	Initialize instrument id list for audio file.
*/
void afInitInstIDs (AFfilesetup setup, const int *instids, int ninsts)
{
	if (!_af_filesetup_ok(setup))
		return;

	if (!_af_unique_ids(instids, ninsts, "instrument", AF_BAD_INSTID))
		return;

	_af_setup_free_instruments(setup);

	setup->instrumentCount = ninsts;
	setup->instrumentSet = true;

	setup->instruments = _af_instsetup_new(setup->instrumentCount);

	for (int i=0; i < setup->instrumentCount; i++)
		setup->instruments[i].id = instids[i];
}

int afGetInstIDs (AFfilehandle file, int *instids)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (instids)
		for (int i=0; i < file->m_instrumentCount; i++)
			instids[i] = file->m_instruments[i].id;

	return file->m_instrumentCount;
}

/*
	This routine checks and sets instrument parameters.
	npv is number of valid AUpvlist pairs.
*/
void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
{
	if (!_af_filehandle_ok(file))
		return;

	if (!file->checkCanWrite())
		return;

	Instrument *instrument = file->getInstrument(instid);
	if (!instrument)
		return;

	if (AUpvgetmaxitems(pvlist) < npv)
	npv = AUpvgetmaxitems(pvlist);

	for (int i=0; i < npv; i++)
	{
		int	param;

		AUpvgetparam(pvlist, i, &param);

		int j;
		if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
			/* no parameter with that id; ignore */
			continue;

		if (!file->isInstrumentParameterValid(pvlist, i))
			/* bad parameter value; ignore */
			continue;

		int	type = _af_units[file->m_fileFormat].instrumentParameters[j].type;

		switch (type)
		{
			case AU_PVTYPE_LONG:
				AUpvgetval(pvlist, i, &instrument->values[j].l);
				break;
			case AU_PVTYPE_DOUBLE:
				AUpvgetval(pvlist, i, &instrument->values[j].d);
				break;
			case AU_PVTYPE_PTR:
				AUpvgetval(pvlist, i, &instrument->values[j].v);
				break;
			default:
				return;
		}
	}
}

void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
{
	_af_instparam_set(file, instid, pvlist, npv);
}

void afSetInstParamLong (AFfilehandle file, int instid, int param, long value)
{
	AUpvlist pvlist = AUpvnew(1);

	AUpvsetparam(pvlist, 0, param);
	AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
	AUpvsetval(pvlist, 0, &value);

	_af_instparam_set(file, instid, pvlist, 1);

	AUpvfree(pvlist);
}

/*
	This routine gets instrument parameters.
	npv is number of valid AUpvlist pairs
*/
void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist, int npv,
	bool forceLong)
{
	if (!_af_filehandle_ok(file))
		return;

	Instrument *instrument = file->getInstrument(instid);
	if (!instrument)
		return;

	if (AUpvgetmaxitems(pvlist) < npv)
		npv = AUpvgetmaxitems(pvlist);

	for (int i=0; i < npv; i++)
	{
		int param;
		AUpvgetparam(pvlist, i, &param);

		int j;
		if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
			/* no parameter with that id; ignore */
			continue;

		int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;

		/*
			forceLong is true when this routine called by
			afGetInstParamLong().
		*/
		if (forceLong && type != AU_PVTYPE_LONG)
		{
			_af_error(AF_BAD_INSTPTYPE, "type of instrument parameter %d is not AU_PVTYPE_LONG", param);
			continue;
		}

		AUpvsetvaltype(pvlist, i, type);

		switch (type)
		{
			case AU_PVTYPE_LONG:
				AUpvsetval(pvlist, i, &instrument->values[j].l);
				break;
			case AU_PVTYPE_DOUBLE:
				AUpvsetval(pvlist, i, &instrument->values[j].d);
				break;
			case AU_PVTYPE_PTR:
				AUpvsetval(pvlist, i, &instrument->values[j].v);
				break;

			default:
				_af_error(AF_BAD_INSTPTYPE, "invalid instrument parameter type %d", type);
				return;
		}
	}
}

/*
	afGetInstParams -- get a parameter-value array containing
	instrument parameters for the specified instrument chunk
*/
void afGetInstParams (AFfilehandle file, int inst, AUpvlist pvlist, int npv)
{
	_af_instparam_get(file, inst, pvlist, npv, false);
}

long afGetInstParamLong (AFfilehandle file, int inst, int param)
{
	long val;
	AUpvlist pvlist = AUpvnew(1);

	AUpvsetparam(pvlist, 0, param);
	AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);

	_af_instparam_get(file, inst, pvlist, 1, true);

	AUpvgetval(pvlist, 0, &val);
	AUpvfree(pvlist);

	return(val);
}

/*
	Search _af_units[fileFormat].instrumentParameters for the instrument
	parameter with the specified id.

	Report an error and return -1 if no such instrument parameter
	exists.
*/

int _af_instparam_index_from_id (int filefmt, int id)
{
	int i;

	for (i = 0; i < _af_units[filefmt].instrumentParameterCount; i++)
		if (_af_units[filefmt].instrumentParameters[i].id == id)
			break;

	if (i == _af_units[filefmt].instrumentParameterCount)
	{
		_af_error(AF_BAD_INSTPID, "invalid instrument parameter id %d",
			id);
		return -1;
	}

	return i;
}

Loop *Instrument::getLoop(int loopID)
{
	for (int i=0; i<loopCount; i++)
		if (loops[i].id == loopID)
			return &loops[i];
	
	_af_error(AF_BAD_LOOPID, "no loop with id %d for instrument %d\n",
		loopID, id);
	return NULL;
}
/*
	Audio File Library
	Copyright (C) 2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Instrument.h

	This file declares routines for dealing with instruments.
*/

#ifndef INSTRUMENT_H
#define INSTRUMENT_H

#include "afinternal.h"
#include "audiofile.h"
#include "aupvlist.h"

struct LoopSetup;
struct Loop;

struct InstrumentSetup
{
	int	id;

	int loopCount;
	LoopSetup *loops;

	bool loopSet;

	bool allocateLoops(int count);
	void freeLoops();
};

struct Instrument
{
	int id;

	int loopCount;
	Loop *loops;

	AFPVu *values;

	Loop *getLoop(int loopID);
};

void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist,
	int npv, bool forceLong);

void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist,
	int npv);

int _af_instparam_index_from_id (int fileFormat, int id);

#endif /* INSTRUMENT_H */
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Loop.cpp

	All routines that operate on loops.
*/

#include "config.h"

#include "FileHandle.h"
#include "Instrument.h"
#include "Setup.h"
#include "afinternal.h"
#include "audiofile.h"
#include "util.h"

void afInitLoopIDs (AFfilesetup setup, int instid, const int *loopids, int nloops)
{
	if (!_af_filesetup_ok(setup))
		return;

	if (!_af_unique_ids(loopids, nloops, "loop", AF_BAD_LOOPID))
		return;

	InstrumentSetup *instrument = setup->getInstrument(instid);
	if (!instrument)
		return;

	instrument->freeLoops();
	if (!instrument->allocateLoops(nloops))
		return;

	for (int i=0; i < nloops; i++)
		instrument->loops[i].id = loopids[i];
}

int afGetLoopIDs (AFfilehandle file, int instid, int *loopids)
{
	if (!_af_filehandle_ok(file))
		return AF_FAIL;

	Instrument *instrument = file->getInstrument(instid);
	if (!instrument)
		return AF_FAIL;

	if (loopids)
		for (int i=0; i < instrument->loopCount; i++)
			loopids[i] = instrument->loops[i].id;

	return instrument->loopCount;
}

/*
	getLoop returns pointer to requested loop if it exists, and if
	mustWrite is true, only if handle is writable.
*/

static Loop *getLoop (AFfilehandle handle, int instid, int loopid,
	bool mustWrite)
{
	if (!_af_filehandle_ok(handle))
		return NULL;

	if (mustWrite && !handle->checkCanWrite())
		return NULL;

	Instrument *instrument = handle->getInstrument(instid);
	if (!instrument)
		return NULL;

	return instrument->getLoop(loopid);
}

/*
	Set loop mode (as in AF_LOOP_MODE_...).
*/
void afSetLoopMode (AFfilehandle file, int instid, int loopid, int mode)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop)
		return;

	if (mode != AF_LOOP_MODE_NOLOOP &&
		mode != AF_LOOP_MODE_FORW &&
		mode != AF_LOOP_MODE_FORWBAKW)
	{
		_af_error(AF_BAD_LOOPMODE, "unrecognized loop mode %d", mode);
		return;
	}

	loop->mode = mode;
}

/*
	Get loop mode (as in AF_LOOP_MODE_...).
*/
int afGetLoopMode (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	return loop->mode;
}

/*
	Set loop count.
*/
int afSetLoopCount (AFfilehandle file, int instid, int loopid, int count)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop)
		return AF_FAIL;

	if (count < 1)
	{
		_af_error(AF_BAD_LOOPCOUNT, "invalid loop count: %d", count);
		return AF_FAIL;
	}

	loop->count = count;
	return AF_SUCCEED;
}

/*
	Get loop count.
*/
int afGetLoopCount(AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	return loop->count;
}

/*
	Set loop start marker id in the file structure
*/
void afSetLoopStart(AFfilehandle file, int instid, int loopid, int markid)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop)
		return;

	loop->beginMarker = markid;
}

/*
	Get loop start marker id.
*/
int afGetLoopStart (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	return loop->beginMarker;
}

/*
	Set loop start frame in the file structure.
*/
int afSetLoopStartFrame (AFfilehandle file, int instid, int loopid, AFframecount startFrame)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop)
		return -1;

	if (startFrame < 0)
	{
		_af_error(AF_BAD_FRAME, "loop start frame must not be negative");
		return AF_FAIL;
	}

	int	trackid = loop->trackid;
	int beginMarker = loop->beginMarker;

	afSetMarkPosition(file, trackid, beginMarker, startFrame);
	return AF_SUCCEED;
}

/*
	Get loop start frame.
*/
AFframecount afGetLoopStartFrame (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);
	if (!loop)
		return -1;

	int trackid = loop->trackid;
	int beginMarker = loop->beginMarker;

	return afGetMarkPosition(file, trackid, beginMarker);
}

/*
	Set loop track id.
*/
void afSetLoopTrack (AFfilehandle file, int instid, int loopid, int track)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop) return;

	loop->trackid = track;
}

/*
	Get loop track.
*/
int afGetLoopTrack (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	return loop->trackid;
}

/*
	Set loop end frame marker id.
*/
void afSetLoopEnd (AFfilehandle file, int instid, int loopid, int markid)
{
	Loop *loop = getLoop(file, instid, loopid, true);

	if (!loop)
		return;

	loop->endMarker = markid;
}

/*
	Get loop end frame marker id.
*/
int afGetLoopEnd (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	return loop->endMarker;
}

/*
	Set loop end frame.
*/
int afSetLoopEndFrame (AFfilehandle file, int instid, int loopid, AFframecount endFrame)
{
	Loop *loop = getLoop(file, instid, loopid, true);
	if (!loop)
		return -1;

	if (endFrame < 0)
	{
		_af_error(AF_BAD_FRAME, "loop end frame must not be negative");
		return AF_FAIL;
	}

	int trackid = loop->trackid;
	int endMarker = loop->endMarker;

	afSetMarkPosition(file, trackid, endMarker, endFrame);
	return AF_SUCCEED;
}

/*
	Get loop end frame.
*/

AFframecount afGetLoopEndFrame (AFfilehandle file, int instid, int loopid)
{
	Loop *loop = getLoop(file, instid, loopid, false);

	if (!loop)
		return -1;

	int trackid = loop->trackid;
	int endMarker = loop->endMarker;

	return afGetMarkPosition(file, trackid, endMarker);
}
SUBDIRS = alac modules

lib_LTLIBRARIES = libaudiofile.la

EXTRA_DIST = audiofile.exports

libaudiofile_la_SOURCES = \
	AIFF.cpp \
	AIFF.h \
	AVR.cpp \
	AVR.h \
	AudioFormat.cpp \
	AudioFormat.h \
	Buffer.cpp \
	Buffer.h \
	CAF.cpp \
	CAF.h \
	Compiler.h \
	FLACFile.cpp \
	FLACFile.h \
	Features.h \
	File.cpp \
	File.h \
	FileHandle.cpp \
	FileHandle.h \
	IFF.cpp \
	IFF.h \
	IRCAM.cpp \
	IRCAM.h \
	Instrument.cpp \
	Instrument.h \
	Loop.cpp \
	Marker.cpp \
	Marker.h \
	Miscellaneous.cpp \
	NIST.cpp \
	NIST.h \
	NeXT.cpp \
	NeXT.h \
	PacketTable.cpp \
	PacketTable.h \
	Raw.cpp \
	Raw.h \
	SampleVision.cpp \
	SampleVision.h \
	Setup.cpp \
	Setup.h \
	Shared.h \
	Tag.h \
	Track.cpp \
	Track.h \
	UUID.cpp \
	UUID.h \
	VOC.cpp \
	VOC.h \
	WAVE.cpp \
	WAVE.h \
	aes.cpp \
	af_vfs.cpp \
	af_vfs.h \
	afinternal.h \
	aupv.c \
	aupvinternal.h \
	aupvlist.h \
	byteorder.h \
	byteorder.h \
	compression.cpp \
	compression.h \
	data.cpp \
	debug.cpp \
	debug.h \
	error.c \
	error.h \
	extended.c \
	extended.h \
	format.cpp \
	g711.c \
	g711.h \
	openclose.cpp \
	pcm.cpp \
	pcm.h \
	query.cpp \
	units.cpp \
	units.h \
	util.cpp \
	util.h \
	util.h

libaudiofile_la_LIBADD = \
	modules/libmodules.la \
	alac/libalac.la \
	$(COVERAGE_LIBS) \
	$(FLAC_LIBS) \
	-lm

libaudiofile_la_LDFLAGS = -version-info $(AUDIOFILE_VERSION_INFO) \
	-no-undefined \
	-export-symbols $(srcdir)/audiofile.exports

include_HEADERS = audiofile.h aupvlist.h af_vfs.h

TESTS = UnitTests

check_PROGRAMS = $(TESTS)

if ENABLE_VALGRIND
VALGRIND_FLAGS = --quiet --leak-check=full --show-reachable=yes --error-exitcode=1
TESTS_ENVIRONMENT = $(top_builddir)/libtool --mode=execute $(VALGRIND) $(VALGRIND_FLAGS)
endif

LIBGTEST = ../gtest/libgtest.la

UnitTests_SOURCES = modules/UT_RebufferModule.cpp
UnitTests_LDADD = libaudiofile.la $(LIBGTEST)
UnitTests_CPPFLAGS = -I$(top_srcdir)
UnitTests_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
UnitTests_LDFLAGS = -static

# GNU gcc
# AM_CFLAGS = -Wall -g
# SGI MIPSpro cc
# AM_CFLAGS = -fullwarn -g
# No debugging.
AM_CFLAGS = -DNDEBUG -Wall $(WERROR_CFLAGS) $(COVERAGE_CFLAGS) $(FLAC_CFLAGS) -fvisibility=hidden
AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden

CLEANFILES = *.gcda *.gcno
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Marker.cpp

	This file contains routines for dealing with loop markers.
*/

#include "config.h"
#include "Marker.h"

#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "util.h"

void afInitMarkIDs(AFfilesetup setup, int trackid, const int *markids, int nmarks)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (track->markers != NULL)
	{
		for (int i=0; i<track->markerCount; i++)
		{
			if (track->markers[i].name != NULL)
				free(track->markers[i].name);
			if (track->markers[i].comment != NULL)
				free(track->markers[i].comment);
		}
		free(track->markers);
	}

	track->markers = (MarkerSetup *) _af_calloc(nmarks, sizeof (struct MarkerSetup));
	track->markerCount = nmarks;

	for (int i=0; i<nmarks; i++)
	{
		track->markers[i].id = markids[i];
		track->markers[i].name = _af_strdup("");
		track->markers[i].comment = _af_strdup("");
	}

	track->markersSet = true;
}

void afInitMarkName(AFfilesetup setup, int trackid, int markid,
	const char *namestr)
{
	int	markno;
	int	length;

	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	for (markno=0; markno<track->markerCount; markno++)
	{
		if (track->markers[markno].id == markid)
			break;
	}

	if (markno == track->markerCount)
	{
		_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
		return;
	}

	length = strlen(namestr);
	if (length > 255)
	{
		_af_error(AF_BAD_STRLEN,
			"warning: marker name truncated to 255 characters");
		length = 255;
	}

	if (track->markers[markno].name)
		free(track->markers[markno].name);
	if ((track->markers[markno].name = (char *) _af_malloc(length+1)) == NULL)
		return;
	strncpy(track->markers[markno].name, namestr, length);
	/*
		The null terminator is not set by strncpy if
		strlen(namestr) > length.  Set it here.
	*/
	track->markers[markno].name[length] = '\0';
}

void afInitMarkComment(AFfilesetup setup, int trackid, int markid,
	const char *commstr)
{
	int	markno;
	int	length;

	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	for (markno=0; markno<track->markerCount; markno++)
	{
		if (track->markers[markno].id == markid)
			break;
	}

	if (markno == track->markerCount)
	{
		_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
		return;
	}

	length = strlen(commstr);

	if (track->markers[markno].comment)
		free(track->markers[markno].comment);
	if ((track->markers[markno].comment = (char *) _af_malloc(length+1)) == NULL)
		return;
	strcpy(track->markers[markno].comment, commstr);
}

char *afGetMarkName (AFfilehandle file, int trackid, int markid)
{
	if (!_af_filehandle_ok(file))
		return NULL;

	Track *track = file->getTrack(trackid);
	if (!track)
		return NULL;

	Marker *marker = track->getMarker(markid);
	if (!marker)
		return NULL;

	return marker->name;
}

char *afGetMarkComment (AFfilehandle file, int trackid, int markid)
{
	if (!_af_filehandle_ok(file))
		return NULL;

	Track *track = file->getTrack(trackid);
	if (!track)
		return NULL;

	Marker *marker = track->getMarker(markid);
	if (!marker)
		return NULL;

	return marker->comment;
}

void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
	AFframecount position)
{
	if (!_af_filehandle_ok(file))
		return;

	if (!file->checkCanWrite())
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	Marker *marker = track->getMarker(markid);
	if (!marker)
		return;

	if (position < 0)
	{
		_af_error(AF_BAD_MARKPOS, "invalid marker position %jd",
			static_cast<intmax_t>(position));
		position = 0;
	}

	marker->position = position;
}

int afGetMarkIDs (AFfilehandle file, int trackid, int markids[])
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (markids != NULL)
	{
		for (int i=0; i<track->markerCount; i++)
		{
			markids[i] = track->markers[i].id;
		}
	}

	return track->markerCount;
}

AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid)
{
	if (!_af_filehandle_ok(file))
		return 0L;

	Track *track = file->getTrack(trackid);
	if (!track)
		return 0L;

	Marker *marker = track->getMarker(markid);
	if (!marker)
		return 0L;

	return marker->position;
}

Marker *_af_marker_new (int count)
{
	Marker	*markers = (Marker *) _af_calloc(count, sizeof (Marker));
	if (markers == NULL)
		return NULL;

	return markers;
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef MARKER_H
#define MARKER_H

struct MarkerSetup
{
	int id;
	char *name, *comment;
};

struct Marker
{
	short id;
	unsigned long position;
	char *name;
	char *comment;
};

struct Track;

Marker *_af_marker_new (int count);
Marker *_af_marker_find_by_id (Track *track, int id);

#endif /* MARKER_H */
/*
	Audio File Library
	Copyright (C) 1998, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Miscellaneous.cpp

	This file contains routines for dealing with the Audio File
	Library's internal miscellaneous data types.
*/

#include "config.h"

#include <algorithm>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "FileHandle.h"
#include "Setup.h"
#include "afinternal.h"
#include "audiofile.h"
#include "util.h"

void afInitMiscIDs (AFfilesetup setup, const int *ids, int nids)
{
	if (!_af_filesetup_ok(setup))
		return;

	if (setup->miscellaneous != NULL)
	{
		free(setup->miscellaneous);
	}

	setup->miscellaneousCount = nids;

	if (nids == 0)
		setup->miscellaneous = NULL;
	else
	{
		setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(nids,
			sizeof (MiscellaneousSetup));

		if (setup->miscellaneous == NULL)
			return;

		for (int i=0; i<nids; i++)
		{
			setup->miscellaneous[i].id = ids[i];
			setup->miscellaneous[i].type = 0;
			setup->miscellaneous[i].size = 0;
		}
	}

	setup->miscellaneousSet = true;
}

int afGetMiscIDs (AFfilehandle file, int *ids)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (ids != NULL)
	{
		for (int i=0; i<file->m_miscellaneousCount; i++)
		{
			ids[i] = file->m_miscellaneous[i].id;
		}
	}

	return file->m_miscellaneousCount;
}

void afInitMiscType (AFfilesetup setup, int miscellaneousid, int type)
{
	if (!_af_filesetup_ok(setup))
		return;

	MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
	if (miscellaneous)
		miscellaneous->type = type;
}

int afGetMiscType (AFfilehandle file, int miscellaneousid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
	if (miscellaneous)
		return miscellaneous->type;
	return -1;
}

void afInitMiscSize (AFfilesetup setup, int miscellaneousid, int size)
{
	if (!_af_filesetup_ok(setup))
		return;

	MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
	if (miscellaneous)
		miscellaneous->size = size;
}

int afGetMiscSize (AFfilehandle file, int miscellaneousid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
	if (miscellaneous)
		return miscellaneous->size;
	return -1;
}

int afWriteMisc (AFfilehandle file, int miscellaneousid, const void *buf, int bytes)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (!file->checkCanWrite())
		return -1;

	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
	if (!miscellaneous)
		return -1;

	if (bytes <= 0)
	{
		_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
		return -1;
	}

	if (miscellaneous->buffer == NULL && miscellaneous->size != 0)
	{
		miscellaneous->buffer = _af_malloc(miscellaneous->size);
		if (miscellaneous->buffer == NULL)
			return -1;
		memset(miscellaneous->buffer, 0, miscellaneous->size);
	}

	int localsize = std::min(bytes,
		miscellaneous->size - miscellaneous->position);
	memcpy((char *) miscellaneous->buffer + miscellaneous->position,
		buf, localsize);
	miscellaneous->position += localsize;
	return localsize;
}

int afReadMisc (AFfilehandle file, int miscellaneousid, void *buf, int bytes)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (!file->checkCanRead())
		return -1;

	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
	if (!miscellaneous)
		return -1;

	if (bytes <= 0)
	{
		_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
		return -1;
	}

	int localsize = std::min(bytes,
		miscellaneous->size - miscellaneous->position);
	memcpy(buf, (char *) miscellaneous->buffer + miscellaneous->position,
		localsize);
	miscellaneous->position += localsize;
	return localsize;
}

int afSeekMisc (AFfilehandle file, int miscellaneousid, int offset)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
	if (!miscellaneous)
		return -1;

	if (offset >= miscellaneous->size)
	{
		_af_error(AF_BAD_MISCSEEK,
			"offset %d too big for miscellaneous chunk %d "
			"(%d data bytes)",
			offset, miscellaneousid, miscellaneous->size);
		return -1;
	}

	miscellaneous->position = offset;

	return offset;
}
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	NIST.cpp

	This file contains code for reading NIST SPHERE files.
*/

#include "config.h"
#include "NIST.h"

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Setup.h"
#include "Track.h"
#include "File.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"

#define NIST_SPHERE_HEADER_LENGTH 1024
#define NIST_SPHERE_MAX_FIELD_LENGTH 80

static const _AFfilesetup nistDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_NIST_SPHERE,	/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

bool NISTFile::recognize(File *fh)
{
	uint8_t buffer[16];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 16) != 16)
		return false;

	/* Check to see if the file's magic number matches. */
	if (memcmp(buffer, "NIST_1A\n   1024\n", 16) == 0)
		return true;

	return false;
}

AFfilesetup NISTFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "NIST SPHERE file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		/* XXXmpruett: Currently we allow only 1-16 bit sample width. */
		if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
			(track->f.sampleWidth < 1 || track->f.sampleWidth > 16))
		{
			_af_error(AF_BAD_WIDTH,
				"invalid sample width %d bits for NIST SPHERE format",
				track->f.sampleWidth);
			return AF_NULL_FILESETUP;
		}
		else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
		{
			_af_error(AF_BAD_SAMPFMT,
				"NIST SPHERE format does not support unsigned data");
			return AF_NULL_FILESETUP;
		}
		else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
			track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
		{
			_af_error(AF_BAD_SAMPFMT,
				"NIST SPHERE format does not support floating-point data");
			return AF_NULL_FILESETUP;
		}
	}

	if (track->rateSet && track->f.sampleRate <= 0.0)
	{
		_af_error(AF_BAD_RATE,
			"invalid sample rate %.30g for NIST SPHERE file",
			track->f.sampleRate);
		return AF_NULL_FILESETUP;
	}

	if (track->compressionSet && track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED,
			"NIST SPHERE format supports only G.711 u-law or A-law compression");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "NIST SPHERE file cannot have AES data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_NUMMARKS, "NIST SPHERE format does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_NUMINSTS, "NIST SPHERE format does not support instruments");
		return AF_NULL_FILESETUP;
	}

	/* XXXmpruett: We don't support miscellaneous chunks for now. */
	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "NIST SPHERE format does not currently support miscellaneous chunks");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &nistDefaultFileSetup, true);
}

static bool nist_header_read_int (const char *header, const char *key, int *val)
{
	const char *cp;
	char keystring[256], scanstring[256];

	snprintf(keystring, 256, "\n%s -i", key);

	if ((cp = strstr(header, keystring)) != NULL)
	{
		snprintf(scanstring, 256, "\n%s -i %%d", key);
		sscanf(cp, scanstring, val);
		return true;
	}

	return false;
}

static bool nist_header_read_string (const char *header, const char *key, int *length, char *val)
{
	const char *cp;
	char keystring[256], scanstring[256];

	snprintf(keystring, 256, "\n%s -s", key);

	if ((cp = strstr(header, keystring)) != NULL)
	{
		snprintf(scanstring, 256, "\n%s -s%%d %%79s", key);
		sscanf(cp, scanstring, length, val);
		return true;
	}

	return false;
}

status NISTFile::readInit(AFfilesetup setup)
{
	char header[NIST_SPHERE_HEADER_LENGTH + 1];
	int intval;
	char strval[NIST_SPHERE_MAX_FIELD_LENGTH];
	int sample_n_bytes;

	m_fh->seek(0, File::SeekFromBeginning);

	if (m_fh->read(header, NIST_SPHERE_HEADER_LENGTH) != NIST_SPHERE_HEADER_LENGTH)
	{
		_af_error(AF_BAD_READ, "Could not read NIST SPHERE file header");
		return AF_FAIL;
	}

	header[NIST_SPHERE_HEADER_LENGTH] = '\0';

	if (memcmp(header, "NIST_1A\n   1024\n", 16) != 0)
	{
		_af_error(AF_BAD_FILEFMT, "Bad NIST SPHERE file header");
		return AF_FAIL;
	}

	Track *track = allocateTrack();
	if (!track)
		return AF_FAIL;

	// Read channel count.
	if (nist_header_read_int(header, "channel_count", &intval))
	{
		if (intval < 1)
		{
			_af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
				intval);
			return AF_FAIL;
		}
		track->f.channelCount = intval;
	}
	else
	{
		_af_error(AF_BAD_HEADER, "number of channels not specified");
		return AF_FAIL;
	}

	// Read number of bytes per sample.
	if (!nist_header_read_int(header, "sample_n_bytes", &sample_n_bytes))
	{
		_af_error(AF_BAD_HEADER, "bytes per sample not specified");
		return AF_FAIL;
	}

	track->f.framesPerPacket = 1;

	/*
		Since some older NIST SPHERE files lack a sample_coding
		field, if sample_n_bytes is 1, assume mu-law;
		otherwise assume linear PCM.
	*/
	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
	if (sample_n_bytes == 1)
	{
		track->f.compressionType = AF_COMPRESSION_G711_ULAW;
		track->f.sampleWidth = 16;
		track->f.bytesPerPacket = track->f.channelCount;
	}
	else
	{
		track->f.compressionType = AF_COMPRESSION_NONE;
		track->f.sampleWidth = sample_n_bytes * 8;
		track->f.computeBytesPerPacketPCM();
	}

	if (nist_header_read_string(header, "sample_coding", &intval, strval))
	{
		if (strcmp(strval, "pcm") == 0)
			;
		else if (strcmp(strval, "ulaw") == 0 || strcmp(strval, "mu-law") == 0)
		{
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
			track->f.sampleWidth = 16;
		}
		else if (strcmp(strval, "alaw") == 0)
		{
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
			track->f.sampleWidth = 16;
		}
		else
		{
			_af_error(AF_BAD_SAMPFMT,
				"unrecognized NIST SPHERE sample format %s", strval);
			return AF_FAIL;
		}
	}

	// Read string representing byte order.
	if (nist_header_read_string(header, "sample_byte_format", &intval, strval))
	{
		if (intval > 1)
		{
			if (strncmp(strval, "01", 2) == 0)
				track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
			else
				track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
		}
		else
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
	}
	else
	{
		/*
			Fail if this field is not present and sample
			width is more than one byte.
		*/
		if (track->f.compressionType == AF_COMPRESSION_NONE &&
			track->f.sampleWidth > 8)
		{
			_af_error(AF_BAD_HEADER, "sample byte order not specified");
			return AF_FAIL;
		}
	}

	// Read significant bits per sample.
	if (nist_header_read_int(header, "sample_sig_bits", &intval))
	{
		if (intval < 1 || intval > 32)
		{
			_af_error(AF_BAD_WIDTH, "invalid sample width %d bits\n",
				intval);
			return AF_FAIL;
		}

		/*
			Use specified significant bits value as the
			sample width for uncompressed data as long
			as the number of bytes per sample remains
			unchanged.
		*/
		if (track->f.compressionType == AF_COMPRESSION_NONE &&
			(intval + 7) / 8 == sample_n_bytes)
		{
			track->f.sampleWidth = intval;
		}
	}

	// Read sample rate.
	if (nist_header_read_int(header, "sample_rate", &intval))
	{
		if (intval <= 0)
		{
			_af_error(AF_BAD_RATE, "invalid sample rate %d Hz\n", intval);
			return AF_FAIL;
		}
		track->f.sampleRate = intval;
	}
	else
	{
		_af_error(AF_BAD_HEADER, "sample rate not specified");
		return AF_FAIL;
	}

	// Read sample count.
	if (nist_header_read_int(header, "sample_count", &intval))
	{
		track->totalfframes = intval;
	}
	else
	{
		_af_error(AF_BAD_HEADER, "number of samples not specified");
		return AF_FAIL;
	}

	if (_af_set_sample_format(&track->f, track->f.sampleFormat,
		track->f.sampleWidth) == AF_FAIL)
	{
		return AF_FAIL;
	}

	track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;
	track->data_size = m_fh->length() - NIST_SPHERE_HEADER_LENGTH;

	return AF_SUCCEED;
}

static const char *sample_byte_format (AudioFormat *fmt)
{
	int nbytes = _af_format_sample_size(fmt, false);

	assert(nbytes == 1 || nbytes == 2);

	if (nbytes == 1)
		return "0";
	else if (nbytes == 2)
	{
		if (fmt->byteOrder == AF_BYTEORDER_BIGENDIAN)
			return "10";
		else
			return "01";
	}

	/* NOTREACHED */
	return NULL;
}

static const char *sample_coding (AudioFormat *fmt)
{
	if (fmt->compressionType == AF_COMPRESSION_NONE)
		return "pcm";
	else if (fmt->compressionType == AF_COMPRESSION_G711_ULAW)
		return "ulaw";
	else if (fmt->compressionType == AF_COMPRESSION_G711_ALAW)
		return "alaw";

	/* NOTREACHED */
	return NULL;
}

status NISTFile::writeHeader()
{
	Track *track = getTrack();

	char header[NIST_SPHERE_HEADER_LENGTH];
	int printed = snprintf(header, NIST_SPHERE_HEADER_LENGTH,
		"NIST_1A\n   1024\n"
		"channel_count -i %d\n"
		"sample_count -i %d\n"
		"sample_rate -i %d\n"
		"sample_n_bytes -i %d\n"
		"sample_byte_format -s%d %s\n"
		"sample_sig_bits -i %d\n"
		"sample_coding -s%d %s\n"
		"end_head\n",
		track->f.channelCount,
		(int) track->totalfframes,
		(int) track->f.sampleRate,
		(int) _af_format_sample_size(&track->f, false),
		(int) _af_format_sample_size(&track->f, false), sample_byte_format(&track->f),
		track->f.sampleWidth,
		(int) strlen(sample_coding(&track->f)), sample_coding(&track->f));

	/* Fill the remaining space in the buffer with space characters. */
	if (printed < NIST_SPHERE_HEADER_LENGTH)
		memset(header + printed, ' ', NIST_SPHERE_HEADER_LENGTH - printed);

	return m_fh->write(header, NIST_SPHERE_HEADER_LENGTH) == NIST_SPHERE_HEADER_LENGTH ? AF_SUCCEED : AF_FAIL;
}

status NISTFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	Track *track = getTrack();

	track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;

	m_fh->seek(0, File::SeekFromBeginning);
	writeHeader();

	return AF_SUCCEED;
}

status NISTFile::update()
{
	m_fh->seek(0, File::SeekFromBeginning);
	writeHeader();

	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2004, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	NIST.h

	This file declares code for reading and writing NIST SPHERE files.
*/

#ifndef NIST_H
#define NIST_H

#include "Compiler.h"
#include "FileHandle.h"

class NISTFile : public _AFfilehandle
{
public:
	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup setup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
	status writeHeader();
};

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, 2011-2013, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	NeXT.cpp

	This file contains routines for reading and writing NeXT/Sun
	.snd/.au sound files.
*/

#include "config.h"
#include "NeXT.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"

const int _af_next_compression_types[_AF_NEXT_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW
};

static const _AFfilesetup nextDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_NEXTSND,	/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

enum
{
	_AU_FORMAT_UNSPECIFIED = 0,
	_AU_FORMAT_MULAW_8 = 1,		/* CCITT G.711 mu-law 8-bit */
	_AU_FORMAT_LINEAR_8 = 2,
	_AU_FORMAT_LINEAR_16 = 3,
	_AU_FORMAT_LINEAR_24 = 4,
	_AU_FORMAT_LINEAR_32 = 5,
	_AU_FORMAT_FLOAT = 6,
	_AU_FORMAT_DOUBLE = 7,
	_AU_FORMAT_INDIRECT = 8,
	_AU_FORMAT_NESTED = 9,
	_AU_FORMAT_DSP_CORE = 10,
	_AU_FORMAT_DSP_DATA_8 = 11,	/* 8-bit fixed point */
	_AU_FORMAT_DSP_DATA_16 = 12,	/* 16-bit fixed point */
	_AU_FORMAT_DSP_DATA_24 = 13,	/* 24-bit fixed point */
	_AU_FORMAT_DSP_DATA_32 = 14,	/* 32-bit fixed point */
	_AU_FORMAT_DISPLAY = 16,
	_AU_FORMAT_MULAW_SQUELCH = 17,	/* 8-bit mu-law, squelched */
	_AU_FORMAT_EMPHASIZED = 18,
	_AU_FORMAT_COMPRESSED = 19,
	_AU_FORMAT_COMPRESSED_EMPHASIZED = 20,
	_AU_FORMAT_DSP_COMMANDS = 21,
	_AU_FORMAT_DSP_COMMANDS_SAMPLES = 22,
	_AU_FORMAT_ADPCM_G721 = 23,	/* CCITT G.721 ADPCM 32 kbits/s */
	_AU_FORMAT_ADPCM_G722 = 24,	/* CCITT G.722 ADPCM */
	_AU_FORMAT_ADPCM_G723_3 = 25,	/* CCITT G.723 ADPCM 24 kbits/s */
	_AU_FORMAT_ADPCM_G723_5 = 26,	/* CCITT G.723 ADPCM 40 kbits/s */
	_AU_FORMAT_ALAW_8 = 27,		/* CCITT G.711 a-law */
	_AU_FORMAT_AES = 28,
	_AU_FORMAT_DELTA_MULAW_8 = 29
};

static const uint32_t _AU_LENGTH_UNSPECIFIED = 0xffffffff;

NeXTFile::NeXTFile()
{
	setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
}

status NeXTFile::readInit(AFfilesetup setup)
{
	uint32_t id, offset, length, encoding, sampleRate, channelCount;

	m_fh->seek(0, File::SeekFromBeginning);

	m_fh->read(&id, 4);
	assert(!memcmp(&id, ".snd", 4));

	readU32(&offset);
	readU32(&length);
	readU32(&encoding);
	readU32(&sampleRate);
	readU32(&channelCount);

	if (!channelCount)
	{
		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
		return AF_FAIL;
	}

	Track *track = allocateTrack();
	if (!track)
		return AF_FAIL;

	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
	track->f.sampleRate = sampleRate;
	track->f.channelCount = channelCount;
	track->f.framesPerPacket = 1;

	/* Override the compression type later if necessary. */
	track->f.compressionType = AF_COMPRESSION_NONE;

	track->fpos_first_frame = offset;

	off_t lengthAvailable = m_fh->length() - offset;
	if (length == _AU_LENGTH_UNSPECIFIED || static_cast<off_t>(length) > lengthAvailable)
		length = lengthAvailable;

	track->data_size = length;

	switch (encoding)
	{
		case _AU_FORMAT_MULAW_8:
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.bytesPerPacket = track->f.channelCount;
			break;
		case _AU_FORMAT_ALAW_8:
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.bytesPerPacket = track->f.channelCount;
			break;
		case _AU_FORMAT_LINEAR_8:
			track->f.sampleWidth = 8;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			break;
		case _AU_FORMAT_LINEAR_16:
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			break;
		case _AU_FORMAT_LINEAR_24:
			track->f.sampleWidth = 24;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			break;
		case _AU_FORMAT_LINEAR_32:
			track->f.sampleWidth = 32;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			break;
		case _AU_FORMAT_FLOAT:
			track->f.sampleWidth = 32;
			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
			break;
		case _AU_FORMAT_DOUBLE:
			track->f.sampleWidth = 64;
			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
			break;

		default:
			/*
				This encoding method is not recognized.
			*/
			_af_error(AF_BAD_SAMPFMT, "bad sample format");
			return AF_FAIL;
	}

	if (track->f.isUncompressed())
		track->f.computeBytesPerPacketPCM();

	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);

	track->computeTotalFileFrames();

	return AF_SUCCEED;
}

bool NeXTFile::recognize(File *fh)
{
	uint8_t buffer[4];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 4) != 4 || memcmp(buffer, ".snd", 4) != 0)
		return false;

	return true;
}

AFfilesetup NeXTFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "NeXT files must have exactly 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
	{
		_af_error(AF_BAD_FILEFMT, "NeXT format does not support unsigned data");
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
	}

	if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
	{
		if (track->f.sampleWidth != 8 &&
			track->f.sampleWidth != 16 &&
			track->f.sampleWidth != 24 &&
			track->f.sampleWidth != 32)
		{
			_af_error(AF_BAD_WIDTH, "invalid sample width %d for NeXT file (only 8-, 16-, 24-, and 32-bit data are allowed)", track->f.sampleWidth);
			return AF_NULL_FILESETUP;
		}
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not implemented for NeXT files");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed() &&
		track->byteOrderSet &&
		track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
		track->f.isByteOrderSignificant())
	{
		_af_error(AF_BAD_BYTEORDER, "NeXT format supports only big-endian data");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed())
		track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "NeXT files cannot have AES data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "NeXT format does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "NeXT format does not support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
	{
		_af_error(AF_BAD_FILESETUP, "NeXT format does not support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &nextDefaultFileSetup, false);
}

static uint32_t nextencodingtype (AudioFormat *format);

status NeXTFile::update()
{
	writeHeader();
	return AF_SUCCEED;
}

status NeXTFile::writeHeader()
{
	Track *track = getTrack();

	if (m_fh->seek(0, File::SeekFromBeginning) != 0)
		_af_error(AF_BAD_LSEEK, "bad seek");

	uint32_t offset = track->fpos_first_frame;
	uint32_t length = track->data_size;
	uint32_t encoding = nextencodingtype(&track->f);
	uint32_t sampleRate = track->f.sampleRate;
	uint32_t channelCount = track->f.channelCount;

	m_fh->write(".snd", 4);
	writeU32(&offset);
	writeU32(&length);
	writeU32(&encoding);
	writeU32(&sampleRate);
	writeU32(&channelCount);

	return AF_SUCCEED;
}

static uint32_t nextencodingtype (AudioFormat *format)
{
	uint32_t encoding = 0;

	if (format->compressionType != AF_COMPRESSION_NONE)
	{
		if (format->compressionType == AF_COMPRESSION_G711_ULAW)
			encoding = _AU_FORMAT_MULAW_8;
		else if (format->compressionType == AF_COMPRESSION_G711_ALAW)
			encoding = _AU_FORMAT_ALAW_8;
	}
	else if (format->sampleFormat == AF_SAMPFMT_TWOSCOMP)
	{
		if (format->sampleWidth == 8)
			encoding = _AU_FORMAT_LINEAR_8;
		else if (format->sampleWidth == 16)
			encoding = _AU_FORMAT_LINEAR_16;
		else if (format->sampleWidth == 24)
			encoding = _AU_FORMAT_LINEAR_24;
		else if (format->sampleWidth == 32)
			encoding = _AU_FORMAT_LINEAR_32;
	}
	else if (format->sampleFormat == AF_SAMPFMT_FLOAT)
		encoding = _AU_FORMAT_FLOAT;
	else if (format->sampleFormat == AF_SAMPFMT_DOUBLE)
		encoding = _AU_FORMAT_DOUBLE;

	return encoding;
}

status NeXTFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	writeHeader();

	Track *track = getTrack();
	track->fpos_first_frame = 28;

	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	NeXT.h

	This file contains headers and constants related to the NeXT/Sun
	.snd audio file format.
*/

#ifndef NEXT_H
#define NEXT_H

#include "Compiler.h"
#include "FileHandle.h"

#define _AF_NEXT_NUM_COMPTYPES 2
extern const int _af_next_compression_types[_AF_NEXT_NUM_COMPTYPES];

class NeXTFile : public _AFfilehandle
{
public:
	NeXTFile();

	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
	status writeHeader();
};

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "PacketTable.h"

PacketTable::PacketTable(int64_t numValidFrames, int32_t primingFrames,
	int32_t remainderFrames) :
	m_numValidFrames(numValidFrames),
	m_primingFrames(primingFrames),
	m_remainderFrames(remainderFrames)
{
}

PacketTable::PacketTable()
{
	m_numValidFrames = 0;
	m_primingFrames = 0;
	m_remainderFrames = 0;
}

PacketTable::~PacketTable()
{
}

void PacketTable::setNumValidFrames(int64_t numValidFrames)
{
	m_numValidFrames = numValidFrames;
}

void PacketTable::setPrimingFrames(int32_t primingFrames)
{
	m_primingFrames = primingFrames;
}

void PacketTable::setRemainderFrames(int32_t remainderFrames)
{
	m_remainderFrames = remainderFrames;
}

void PacketTable::append(size_t bytesPerPacket)
{
	m_bytesPerPacket.push_back(bytesPerPacket);
}

AFfileoffset PacketTable::startOfPacket(size_t packet) const
{
	AFfileoffset offset = 0;
	for (size_t i=0; i<packet; i++)
		offset += m_bytesPerPacket[i];
	return offset;
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef PacketTable_h
#define PacketTable_h

#include "Shared.h"

#include <audiofile.h>

#include <stdint.h>
#include <sys/types.h>
#include <vector>

class PacketTable : public Shared<PacketTable>
{
public:
	PacketTable();
	PacketTable(int64_t numValidFrames,
		int32_t primingFrames,
		int32_t remainderFrames);
	~PacketTable();

	size_t numPackets() const { return m_bytesPerPacket.size(); }
	int64_t numValidFrames() const { return m_numValidFrames; }
	void setNumValidFrames(int64_t numValidFrames);
	int32_t primingFrames() const { return m_primingFrames; }
	void setPrimingFrames(int32_t primingFrames);
	int32_t remainderFrames() const { return m_remainderFrames; }
	void setRemainderFrames(int32_t remainderFrames);

	void append(size_t bytesPerPacket);
	size_t bytesPerPacket(size_t packet) const { return m_bytesPerPacket[packet]; }
	AFfileoffset startOfPacket(size_t packet) const;

private:
	int64_t m_numValidFrames;
	int32_t m_primingFrames;
	int32_t m_remainderFrames;

	std::vector<size_t> m_bytesPerPacket;
};

#endif
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Raw.cpp

	This file contains code for reading and writing raw audio
	data files.
*/

#include "config.h"
#include "Raw.h"

#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "util.h"

static const _AFfilesetup rawDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	// valid
	AF_FILE_RAWDATA,		// fileFormat
	true,	// trackSet
	true,	// instrumentSet
	true,	// miscellaneousSet
	1,		// trackCount
	NULL,	// tracks
	0,		// instrumentCount
	NULL,	// instruments
	0,		// miscellaneousCount
	NULL	// miscellaneous
};

const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW
};

bool RawFile::recognize(File *fh)
{
	return false;
}

status RawFile::readInit(AFfilesetup fileSetup)
{
	if (!fileSetup)
	{
		_af_error(AF_BAD_FILESETUP, "a valid AFfilesetup is required for reading raw data");
		return AF_FAIL;
	}

	if (initFromSetup(fileSetup) == AF_FAIL)
		return AF_FAIL;

	TrackSetup *trackSetup = fileSetup->getTrack();
	if (!trackSetup)
		return AF_FAIL;

	Track *track = getTrack();

	/* Set the track's data offset. */
	if (trackSetup->dataOffsetSet)
		track->fpos_first_frame = trackSetup->dataOffset;
	else
		track->fpos_first_frame = 0;

	/* Set the track's frame count. */
	if (trackSetup->frameCountSet)
	{
		track->totalfframes = trackSetup->frameCount;
	}
	else
	{
		AFfileoffset filesize = m_fh->length();
		if (filesize == -1)
			track->totalfframes = -1;
		else
		{
			/* Ensure that the data offset is valid. */
			if (track->fpos_first_frame > filesize)
			{
				_af_error(AF_BAD_FILESETUP, "data offset is larger than file size");
				return AF_FAIL;
			}

			filesize -= track->fpos_first_frame;
			track->totalfframes = filesize / (int) _af_format_frame_size(&track->f, false);
		}
		track->data_size = filesize;
	}

	return AF_SUCCEED;
}

status RawFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	TrackSetup *trackSetup = setup->getTrack();
	if (!trackSetup)
		return AF_FAIL;

	Track *track = getTrack();

	if (trackSetup->dataOffsetSet)
		track->fpos_first_frame = trackSetup->dataOffset;
	else
		track->fpos_first_frame = 0;

	return AF_SUCCEED;
}

status RawFile::update()
{
	return AF_SUCCEED;
}

AFfilesetup RawFile::completeSetup(AFfilesetup setup)
{
	AFfilesetup	newSetup;

	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_FILESETUP, "raw file must have exactly one track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
	{
		_af_error(AF_BAD_FILESETUP, "could not access track in file setup");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "raw file cannot have AES data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount != 0)
	{
		_af_error(AF_BAD_NUMMARKS, "raw file cannot have markers");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount != 0)
	{
		_af_error(AF_BAD_NUMINSTS, "raw file cannot have instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
	{
		_af_error(AF_BAD_NUMMISC, "raw file cannot have miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	newSetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
	*newSetup = rawDefaultFileSetup;

	newSetup->tracks = (TrackSetup *) _af_malloc(sizeof (TrackSetup));
	newSetup->tracks[0] = setup->tracks[0];
	newSetup->tracks[0].f.compressionParams = NULL;

	newSetup->tracks[0].markerCount = 0;
	newSetup->tracks[0].markers = NULL;

	return newSetup;
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Raw.h
*/

#ifndef RAW_H
#define RAW_H

#include "Compiler.h"
#include "FileHandle.h"

#define _AF_RAW_NUM_COMPTYPES 2
extern const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES];

class RawFile : public _AFfilehandle
{
public:
	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup setup) OVERRIDE;
	status writeInit(AFfilesetup setup) OVERRIDE;
	status update() OVERRIDE;
};

#endif
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "SampleVision.h"

#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "util.h"
#include <string.h>

static const char *kSMPMagic = "SOUND SAMPLE DATA ";
static const unsigned kSMPMagicLength = 18;
static const char *kSMPVersion = "2.1 ";
static const unsigned kSMPVersionLength = 4;
static const unsigned kSMPNameLength = 30;
static const unsigned kSMPCommentLength = 60;
static const unsigned kSMPMarkerNameLength = 10;
static const uint32_t kSMPInvalidSamplePosition = 0xffffffffu;

static const uint8_t kSMPMIDIUnityPlaybackNote = 60;

static const _AFfilesetup sSampleVisionDefaultFileSetup =
{
	_AF_VALID_FILESETUP,
	AF_FILE_SAMPLEVISION,
	true,	// trackSet
	true,	// instrumentSet
	true,	// miscellaneousSet
	1,		// trackCount
	NULL,	// tracks
	1,		// instrumentCount
	NULL,	// instruments
	0,		// miscellaneousCount
	NULL	// miscellaneous
};

static void trimTrailingSpaces(char *s)
{
	int n = strlen(s);
	if (!n)
		return;
	while (--n > 0 && s[n] == ' ')
		;
	s[n+1] = '\0';
}

SampleVisionFile::SampleVisionFile() :
	m_frameCountOffset(-1)
{
	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
}

SampleVisionFile::~SampleVisionFile()
{
}

bool SampleVisionFile::recognize(File *fh)
{
	fh->seek(0, File::SeekFromBeginning);
	char magic[kSMPMagicLength];
	if (fh->read(magic, kSMPMagicLength) != (ssize_t) kSMPMagicLength)
		return false;
	return !strncmp(magic, kSMPMagic, kSMPMagicLength);
}

AFfilesetup SampleVisionFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "SampleVision file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		if (!track->f.isSigned() || track->f.sampleWidth != 16)
		{
			_af_error(AF_BAD_SAMPFMT,
				"SampleVision format supports only 16-bit signed integer audio data");
			return AF_NULL_FILESETUP;
		}
	}
	else
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
			track->f.sampleWidth);

	if (track->byteOrderSet && track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN)
	{
		// Treat error as correctable.
		_af_error(AF_BAD_BYTEORDER, "SampleVision supports only little-endian data");
	}

	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;

	if (track->compressionSet && !track->f.isUncompressed())
	{
		_af_error(AF_BAD_COMPTYPE, "SampleVision does not support compressed audio data");
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount)
	{
		_af_error(AF_BAD_NUMMARKS, "SampleVision does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "SampleVision does not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount)
	{
		_af_error(AF_BAD_FILESETUP, "SampleVision does not support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount)
	{
		_af_error(AF_BAD_FILESETUP, "SampleVision does not support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &sSampleVisionDefaultFileSetup, true);
}

status SampleVisionFile::readInit(AFfilesetup)
{
	m_fh->seek(0, File::SeekFromBeginning);

	char magic[kSMPMagicLength];
	if (m_fh->read(magic, kSMPMagicLength) != (ssize_t) kSMPMagicLength)
		return AF_FAIL;
	if (strncmp(magic, kSMPMagic, kSMPMagicLength) != 0)
		return AF_FAIL;

	char version[kSMPVersionLength];
	if (m_fh->read(version, kSMPVersionLength) != (ssize_t) kSMPVersionLength)
		return AF_FAIL;
	if (strncmp(version, kSMPVersion, kSMPVersionLength) != 0)
		return AF_FAIL;

	Track *track = allocateTrack();

	char name[kSMPNameLength + 1];
	m_fh->read(name, kSMPNameLength);
	name[kSMPNameLength] = '\0';
	trimTrailingSpaces(name);
	if (strlen(name) > 0)
		addMiscellaneous(AF_MISC_NAME, name);

	char comment[kSMPCommentLength + 1];
	m_fh->read(comment, kSMPCommentLength);
	comment[kSMPCommentLength] = '\0';
	trimTrailingSpaces(comment);
	if (strlen(comment) > 0)
		addMiscellaneous(AF_MISC_COMMENT, comment);

	uint32_t frameCount;
	readU32(&frameCount);
	track->totalfframes = frameCount;
	track->fpos_first_frame = m_fh->tell();
	track->data_size = 2 * frameCount;

	m_fh->seek(track->data_size, File::SeekFromCurrent);

	uint16_t reserved;
	readU16(&reserved);

	parseLoops();
	parseMarkers();

	uint8_t midiNote;
	uint32_t sampleRate;
	uint32_t smpteOffset;
	uint32_t cycleLength;

	readU8(&midiNote);
	readU32(&sampleRate);
	readU32(&smpteOffset);
	readU32(&cycleLength);

	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
	track->f.sampleRate = sampleRate;
	track->f.channelCount = 1;
	track->f.compressionType = AF_COMPRESSION_NONE;
	track->f.framesPerPacket = 1;
	_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
	track->f.computeBytesPerPacketPCM();

	return AF_SUCCEED;
}

status SampleVisionFile::parseLoops()
{
	for (int i=0; i<8; i++)
	{
		uint32_t startFrame, endFrame;
		uint8_t type;
		uint16_t count;
		readU32(&startFrame);
		readU32(&endFrame);
		readU8(&type);
		readU16(&count);
	}
	return AF_SUCCEED;
}

status SampleVisionFile::parseMarkers()
{
	for (int i=0; i<8; i++)
	{
		char name[kSMPMarkerNameLength + 1];
		m_fh->read(name, kSMPMarkerNameLength);
		name[kSMPMarkerNameLength] = '\0';
		uint32_t position;
		readU32(&position);
	}
	return AF_SUCCEED;
}

void SampleVisionFile::addMiscellaneous(int type, const char *data)
{
	m_miscellaneousCount++;
	m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
		m_miscellaneousCount * sizeof (Miscellaneous));

	Miscellaneous &m = m_miscellaneous[m_miscellaneousCount - 1];
	m.id = m_miscellaneousCount;
	m.type = type;
	m.size = strlen(data);
	m.position = 0;
	m.buffer = _af_malloc(m.size);
	memcpy(m.buffer, data, m.size);
}

status SampleVisionFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	m_fh->write(kSMPMagic, kSMPMagicLength);
	m_fh->write(kSMPVersion, kSMPVersionLength);

	char name[kSMPNameLength + 1];
	char comment[kSMPCommentLength + 1];
	memset(name, ' ', kSMPNameLength);
	memset(comment, ' ', kSMPCommentLength);
	m_fh->write(name, kSMPNameLength);
	m_fh->write(comment, kSMPCommentLength);

	uint32_t frameCount = 0;
	m_frameCountOffset = m_fh->tell();
	writeU32(&frameCount);

	Track *track = getTrack();
	track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}

status SampleVisionFile::update()
{
	m_fh->seek(m_frameCountOffset, File::SeekFromBeginning);
	Track *track = getTrack();
	uint32_t frameCount = track->totalfframes;
	writeU32(&frameCount);
	writeTrailer();
	return AF_SUCCEED;
}

status SampleVisionFile::writeTrailer()
{
	Track *track = getTrack();

	m_fh->seek(track->fpos_after_data, File::SeekFromBeginning);

	uint16_t reserved = 0;
	writeU16(&reserved);

	writeLoops();
	writeMarkers();

	uint8_t midiNote = kSMPMIDIUnityPlaybackNote;
	uint32_t sampleRate = track->f.sampleRate;
	uint32_t smpteOffset = 0;
	uint32_t cycleLength = 0;

	writeU8(&midiNote);
	writeU32(&sampleRate);
	writeU32(&smpteOffset);
	writeU32(&cycleLength);
	return AF_SUCCEED;
}

status SampleVisionFile::writeLoops()
{
	for (int i=0; i<8; i++)
	{
		uint32_t startFrame = kSMPInvalidSamplePosition, endFrame = 0;
		uint8_t type = 0;
		uint16_t count = 0;
		writeU32(&startFrame);
		writeU32(&endFrame);
		writeU8(&type);
		writeU16(&count);
	}
	return AF_SUCCEED;
}

status SampleVisionFile::writeMarkers()
{
	for (int i=0; i<8; i++)
	{
		char name[kSMPMarkerNameLength + 1];
		memset(name, ' ', kSMPMarkerNameLength);
		name[kSMPMarkerNameLength] = '\0';
		m_fh->write(name, kSMPMarkerNameLength);
		uint32_t position = kSMPInvalidSamplePosition;
		writeU32(&position);
	}
	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef SAMPLE_VISION_H
#define SAMPLE_VISION_H

#include "Compiler.h"
#include "FileHandle.h"

class SampleVisionFile : public _AFfilehandle
{
public:
	SampleVisionFile();
	virtual ~SampleVisionFile();

	static bool recognize(File *fh);

	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;

	status update() OVERRIDE;

private:
	AFfileoffset m_frameCountOffset;

	status parseLoops();
	status parseMarkers();
	status writeTrailer();
	status writeLoops();
	status writeMarkers();

	void addMiscellaneous(int type, const char *data);
};

#endif
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	Setup.cpp
*/

#include "config.h"
#include "Setup.h"

#include <stdlib.h>
#include <string.h>

#include "FileHandle.h"
#include "Instrument.h"
#include "Marker.h"
#include "Track.h"
#include "afinternal.h"
#include "byteorder.h"
#include "audiofile.h"
#include "pcm.h"
#include "units.h"
#include "util.h"

static const _AFfilesetup _af_default_file_setup =
{
	_AF_VALID_FILESETUP,	/* valid */
#if WORDS_BIGENDIAN
	AF_FILE_AIFFC,	/* file format */
#else
	AF_FILE_WAVE,	/* file format */
#endif
	false,		/* trackSet */
	false,		/* instrumentSet */
	false,		/* miscellaneousSet */
	1,		/* trackCount */
	NULL,		/* tracks */
	1,		/* instrumentCount */
	NULL,		/* instruments */
	0,		/* miscellaneousCount */
	NULL		/* miscellaneous */
};

static const InstrumentSetup _af_default_instrumentsetup =
{
	0,		/* id */
	2,		/* loopCount */
	NULL,		/* loops */
	false		/* loopSet */
};

static const TrackSetup _af_default_tracksetup =
{
	0,
	{
		44100.0,
		AF_SAMPFMT_TWOSCOMP,
		16,
		_AF_BYTEORDER_NATIVE,
		{ SLOPE_INT16, 0, MIN_INT16, MAX_INT16 },
		2,
		AF_COMPRESSION_NONE,
		NULL
	},
	false,		/* rateSet */
	false,		/* sampleFormatSet */
	false,		/* sampleWidthSet */
	false,		/* byteOrderSet */
	false,		/* channelCountSet */
	false,		/* compressionSet */
	false,		/* aesDataSet */
	false,		/* markersSet */
	false,		/* dataOffsetSet */
	false,		/* frameCountSet */

	4,		/* markerCount */
	NULL,		/* markers */
	0,		/* dataOffset */
	0		/* frameCount */
};

TrackSetup *_af_tracksetup_new (int trackCount)
{
	TrackSetup	*tracks;

	if (trackCount == 0)
		return NULL;

	tracks = (TrackSetup *) _af_calloc(trackCount, sizeof (TrackSetup));
	if (tracks == NULL)
		return NULL;

	for (int i=0; i<trackCount; i++)
	{
		tracks[i] = _af_default_tracksetup;

		tracks[i].id = AF_DEFAULT_TRACK + i;

		/* XXXmpruett deal with compression */

		_af_set_sample_format(&tracks[i].f, tracks[i].f.sampleFormat,
			tracks[i].f.sampleWidth);

		if (tracks[i].markerCount == 0)
			tracks[i].markers = NULL;
		else
		{
			tracks[i].markers = (MarkerSetup *) _af_calloc(tracks[i].markerCount,
				sizeof (MarkerSetup));

			if (tracks[i].markers == NULL)
				return NULL;

			for (int j=0; j<tracks[i].markerCount; j++)
			{
				tracks[i].markers[j].id = j+1;

				tracks[i].markers[j].name = _af_strdup("");
				if (tracks[i].markers[j].name == NULL)
					return NULL;

				tracks[i].markers[j].comment = _af_strdup("");
				if (tracks[i].markers[j].comment == NULL)
					return NULL;
			}
		}
	}

	return tracks;
}

InstrumentSetup *_af_instsetup_new (int instrumentCount)
{
	InstrumentSetup	*instruments;

	if (instrumentCount == 0)
		return NULL;
	instruments = (InstrumentSetup *) _af_calloc(instrumentCount, sizeof (InstrumentSetup));
	if (instruments == NULL)
		return NULL;

	for (int i=0; i<instrumentCount; i++)
	{
		instruments[i] = _af_default_instrumentsetup;
		instruments[i].id = AF_DEFAULT_INST + i;
		if (instruments[i].loopCount == 0)
			instruments[i].loops = NULL;
		else
		{
			instruments[i].loops = (LoopSetup *) _af_calloc(instruments[i].loopCount, sizeof (LoopSetup));
			if (instruments[i].loops == NULL)
				return NULL;

			for (int j=0; j<instruments[i].loopCount; j++)
				instruments[i].loops[j].id = j+1;
		}
	}

	return instruments;
}

AFfilesetup afNewFileSetup (void)
{
	AFfilesetup	setup;

	setup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
	if (setup == NULL) return AF_NULL_FILESETUP;

	*setup = _af_default_file_setup;

	setup->tracks = _af_tracksetup_new(setup->trackCount);

	setup->instruments = _af_instsetup_new(setup->instrumentCount);

	if (setup->miscellaneousCount == 0)
		setup->miscellaneous = NULL;
	else
	{
		setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(setup->miscellaneousCount,
			sizeof (MiscellaneousSetup));
		for (int i=0; i<setup->miscellaneousCount; i++)
		{
			setup->miscellaneous[i].id = i+1;
			setup->miscellaneous[i].type = 0;
			setup->miscellaneous[i].size = 0;
		}
	}

	return setup;
}

/*
	Free the specified track's markers and their subfields.
*/
void _af_setup_free_markers (AFfilesetup setup, int trackno)
{
	if (setup->tracks[trackno].markerCount != 0)
	{
		for (int i=0; i<setup->tracks[trackno].markerCount; i++)
		{
			free(setup->tracks[trackno].markers[i].name);
			free(setup->tracks[trackno].markers[i].comment);
		}

		free(setup->tracks[trackno].markers);
	}

	setup->tracks[trackno].markers = NULL;
	setup->tracks[trackno].markerCount = 0;
}

/*
	Free the specified setup's tracks and their subfields.
*/
void _af_setup_free_tracks (AFfilesetup setup)
{
	if (setup->tracks)
	{
		for (int i=0; i<setup->trackCount; i++)
		{
			_af_setup_free_markers(setup, i);
		}

		free(setup->tracks);
	}

	setup->tracks = NULL;
	setup->trackCount = 0;
}

/*
	Free the specified setup's instruments and their subfields.
*/
void _af_setup_free_instruments (AFfilesetup setup)
{
	if (setup->instruments)
	{
		for (int i=0; i < setup->instrumentCount; i++)
			setup->instruments[i].freeLoops();

		free(setup->instruments);
	}

	setup->instruments = NULL;
	setup->instrumentCount = 0;
}

void afFreeFileSetup (AFfilesetup setup)
{
	if (!_af_filesetup_ok(setup))
		return;

	_af_setup_free_tracks(setup);

	_af_setup_free_instruments(setup);

	if (setup->miscellaneousCount)
	{
		free(setup->miscellaneous);
		setup->miscellaneous = NULL;
		setup->miscellaneousCount = 0;
	}

	memset(setup, 0, sizeof (_AFfilesetup));
	free(setup);
}

void afInitFileFormat (AFfilesetup setup, int filefmt)
{
	if (!_af_filesetup_ok(setup))
		return;

	if (filefmt < 0 || filefmt >= _AF_NUM_UNITS)
	{
		_af_error(AF_BAD_FILEFMT, "unrecognized file format %d",
			filefmt);
		return;
	}

	if (!_af_units[filefmt].implemented)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED,
			"%s format not currently supported",
			_af_units[filefmt].name);
		return;
	}

	setup->fileFormat = filefmt;
}

void afInitChannels (AFfilesetup setup, int trackid, int channels)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (channels < 1)
	{
		_af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
			channels);
		return;
	}

	track->f.channelCount = channels;
	track->channelCountSet = true;
}

void afInitSampleFormat (AFfilesetup setup, int trackid, int sampfmt, int sampwidth)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	_af_set_sample_format(&track->f, sampfmt, sampwidth);

	track->sampleFormatSet = true;
	track->sampleWidthSet = true;
}

void afInitByteOrder (AFfilesetup setup, int trackid, int byteorder)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (byteorder != AF_BYTEORDER_BIGENDIAN &&
		byteorder != AF_BYTEORDER_LITTLEENDIAN)
	{
		_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
		return;
	}

	track->f.byteOrder = byteorder;
	track->byteOrderSet = true;
}

void afInitRate (AFfilesetup setup, int trackid, double rate)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (rate <= 0.0)
	{
		_af_error(AF_BAD_RATE, "invalid sample rate %.30g", rate);
		return;
	}

	track->f.sampleRate = rate;
	track->rateSet = true;
}

/*
	track data: data offset within the file (initialized for raw reading only)
*/
void afInitDataOffset (AFfilesetup setup, int trackid, AFfileoffset offset)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (offset < 0)
	{
		_af_error(AF_BAD_DATAOFFSET, "invalid data offset %jd",
			static_cast<intmax_t>(offset));
		return;
	}

	track->dataOffset = offset;
	track->dataOffsetSet = true;
}

/*
	track data: data offset within the file (initialized for raw reading only)
*/
void afInitFrameCount (AFfilesetup setup, int trackid, AFfileoffset count)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (count < 0)
	{
		_af_error(AF_BAD_FRAMECNT, "invalid frame count %jd",
			static_cast<intmax_t>(count));
		return;
	}

	track->frameCount = count;
	track->frameCountSet = true;
}

#define alloccopy(type, n, var, copyfrom) \
{ \
	if (n == 0) \
		var = NULL; \
	else \
	{ \
		if ((var = (type *) _af_calloc(n, sizeof (type))) == NULL) \
			goto fail; \
		memcpy((var), (copyfrom), (n) * sizeof (type)); \
	} \
}

AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
	const _AFfilesetup *defaultSetup, bool copyMarks)
{
	AFfilesetup newsetup;
	int instrumentCount, miscellaneousCount, trackCount;

	newsetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
	if (newsetup == AF_NULL_FILESETUP)
		return AF_NULL_FILESETUP;

	*newsetup = *defaultSetup;

	newsetup->tracks = NULL;
	newsetup->instruments = NULL;
	newsetup->miscellaneous = NULL;

	/* Copy tracks. */
	trackCount = setup->trackSet ? setup->trackCount :
		newsetup->trackSet ? newsetup->trackCount : 0;
	alloccopy(TrackSetup, trackCount, newsetup->tracks, setup->tracks);
	newsetup->trackCount = trackCount;

	/* Copy instruments. */
	instrumentCount = setup->instrumentSet ? setup->instrumentCount :
		newsetup->instrumentSet ? newsetup->instrumentCount : 0;
	alloccopy(InstrumentSetup, instrumentCount, newsetup->instruments, setup->instruments);
	newsetup->instrumentCount = instrumentCount;

	/* Copy miscellaneous information. */
	miscellaneousCount = setup->miscellaneousSet ? setup->miscellaneousCount :
		newsetup->miscellaneousSet ? newsetup->miscellaneousCount : 0;
	alloccopy(MiscellaneousSetup, miscellaneousCount, newsetup->miscellaneous, setup->miscellaneous);
	newsetup->miscellaneousCount = miscellaneousCount;

	for (int i=0; i<setup->trackCount; i++)
	{
		TrackSetup	*track = &newsetup->tracks[i];

		/* XXXmpruett set compression information */

		if (!setup->tracks[i].markersSet && !copyMarks)
		{
			track->markers = NULL;
			track->markerCount = 0;
			continue;
		}

		alloccopy(MarkerSetup, setup->tracks[i].markerCount,
			track->markers, setup->tracks[i].markers);
		track->markerCount = setup->tracks[i].markerCount;

		for (int j=0; j<setup->tracks[i].markerCount; j++)
		{
			track->markers[j].name =
				_af_strdup(setup->tracks[i].markers[j].name);
			if (track->markers[j].name == NULL)
				goto fail;

			track->markers[j].comment =
				_af_strdup(setup->tracks[i].markers[j].comment);
			if (track->markers[j].comment == NULL)
				goto fail;
		}
	}

	for (int i=0; i<newsetup->instrumentCount; i++)
	{
		InstrumentSetup	*instrument = &newsetup->instruments[i];
		alloccopy(LoopSetup, setup->instruments[i].loopCount,
			instrument->loops, setup->instruments[i].loops);
	}

	return newsetup;

	fail:
		if (newsetup->miscellaneous)
			free(newsetup->miscellaneous);
		if (newsetup->instruments)
			free(newsetup->instruments);
		if (newsetup->tracks)
			free(newsetup->tracks);
		if (newsetup)
			free(newsetup);

	return AF_NULL_FILESETUP;
}

TrackSetup *_AFfilesetup::getTrack(int trackID)
{
	for (int i=0; i<trackCount; i++)
	{
		if (tracks[i].id == trackID)
			return &tracks[i];
	}

	_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);
	return NULL;
}

InstrumentSetup *_AFfilesetup::getInstrument(int instrumentID)
{
	for (int i=0; i < instrumentCount; i++)
		if (instruments[i].id == instrumentID)
			return &instruments[i];

	_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
	return NULL;
}

MiscellaneousSetup *_AFfilesetup::getMiscellaneous(int miscellaneousID)
{
	for (int i=0; i<miscellaneousCount; i++)
	{
		if (miscellaneous[i].id == miscellaneousID)
			return &miscellaneous[i];
	}

	_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);

	return NULL;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef SETUP_H
#define SETUP_H

#include "afinternal.h"

struct InstrumentSetup;
struct MiscellaneousSetup;
struct TrackSetup;

struct _AFfilesetup
{
	int	valid;

	int fileFormat;

	bool trackSet, instrumentSet, miscellaneousSet;

	int trackCount;
	TrackSetup *tracks;

	int instrumentCount;
	InstrumentSetup *instruments;

	int miscellaneousCount;
	MiscellaneousSetup *miscellaneous;

	TrackSetup *getTrack(int trackID = AF_DEFAULT_TRACK);
	InstrumentSetup *getInstrument(int instrumentID);
	MiscellaneousSetup *getMiscellaneous(int miscellaneousID);
};

void _af_setup_free_markers (AFfilesetup setup, int trackno);
void _af_setup_free_tracks (AFfilesetup setup);
void _af_setup_free_instruments (AFfilesetup setup);

AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
	const _AFfilesetup *defaultSetup, bool copyMarks);

InstrumentSetup *_af_instsetup_new (int count);

#endif
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef SHARED_H
#define SHARED_H

template <typename T>
class Shared
{
public:
	Shared() : m_refCount(0)
	{
	}
	void retain() { m_refCount++; }
	void release() { if (--m_refCount == 0) delete static_cast<T *>(this); }

protected:
	~Shared()
	{
	}

private:
	int m_refCount;

	Shared(const Shared &);
	Shared &operator =(const Shared &);
};

template <typename T>
class SharedPtr
{
public:
	SharedPtr() : m_ptr(0)
	{
	}
	SharedPtr(T *ptr) : m_ptr(ptr)
	{
		if (m_ptr) m_ptr->retain();
	}
	SharedPtr(const SharedPtr &p) : m_ptr(p.m_ptr)
	{
		if (m_ptr) m_ptr->retain();
	}
	~SharedPtr()
	{
		if (T *p = m_ptr) p->release();
	}

	SharedPtr &operator =(T *ptr)
	{
		if (m_ptr != ptr)
		{
			if (ptr) ptr->retain();
			if (m_ptr) m_ptr->release();
			m_ptr = ptr;
		}
		return *this;
	}
	SharedPtr &operator =(const SharedPtr &p)
	{
		if (m_ptr != p.m_ptr)
		{
			if (p.m_ptr) p.m_ptr->retain();
			if (m_ptr) m_ptr->release();
			m_ptr = p.m_ptr;
		}
		return *this;
	}

	T *get() const { return m_ptr; }
	T &operator *() const { return *m_ptr; }
	T *operator ->() const { return m_ptr; }

	typedef T *SharedPtr::*UnspecifiedBoolType;
	operator UnspecifiedBoolType() const { return m_ptr ? &SharedPtr::m_ptr : 0; }

	bool operator !() const { return !m_ptr; }

private:
	T *m_ptr;
};

#endif
/*
	Audio File Library
	Copyright (C) 2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef TAG_H
#define TAG_H

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <string>

class Tag
{
public:
	Tag() : m_value(0) { }
	Tag(uint32_t value) : m_value(value) { }
	Tag(const char *s)
	{
		assert(strlen(s) == 4);
		memcpy(&m_value, s, 4);
	}

	uint32_t value() const { return m_value; }

	bool operator==(const Tag &t) const { return m_value == t.m_value; }
	bool operator!=(const Tag &t) const { return m_value != t.m_value; }

	std::string name() const
	{
		char s[5];
		memcpy(s, &m_value, 4);
		s[4] = '\0';
		return std::string(s);
	}

private:
	uint32_t m_value;
};

#endif
/*
	Audio File Library
	Copyright (C) 1998, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	track.c

	This file contains functions for dealing with tracks within an
	audio file.
*/

#include "config.h"
#include "Track.h"

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include "audiofile.h"
#include "afinternal.h"
#include "util.h"
#include "Marker.h"
#include "PacketTable.h"
#include "modules/Module.h"
#include "modules/ModuleState.h"

void afInitTrackIDs (AFfilesetup file, const int *trackids, int trackCount)
{
	assert(file);
	assert(trackids);
	assert(trackCount == 1);
	assert(trackids[0] == AF_DEFAULT_TRACK);
}

int afGetTrackIDs (AFfilehandle file, int *trackids)
{
	assert(file);

	if (trackids != NULL)
		trackids[0] = AF_DEFAULT_TRACK;

	return 1;
}

Track::Track()
{
	id = AF_DEFAULT_TRACK;

	f.compressionParams = NULL;
	v.compressionParams = NULL;

	channelMatrix = NULL;

	markerCount = 0;
	markers = NULL;

	hasAESData = false;
	memset(aesData, 0, 24);

	totalfframes = 0;
	nextfframe = 0;
	frames2ignore = 0;
	fpos_first_frame = 0;
	fpos_next_frame = 0;
	fpos_after_data = 0;
	totalvframes = 0;
	nextvframe = 0;
	data_size = 0;
}

Track::~Track()
{
	if (f.compressionParams)
	{
		AUpvfree(f.compressionParams);
		f.compressionParams = NULL;
	}

	if (v.compressionParams)
	{
		AUpvfree(v.compressionParams);
		v.compressionParams = NULL;
	}

	free(channelMatrix);
	channelMatrix = NULL;

	if (markers)
	{
		for (int j=0; j<markerCount; j++)
		{
			free(markers[j].name);
			markers[j].name = NULL;
			free(markers[j].comment);
			markers[j].comment = NULL;
		}

		free(markers);
		markers = NULL;
	}
}

void Track::print()
{
	fprintf(stderr, "totalfframes %jd\n", (intmax_t) totalfframes);
	fprintf(stderr, "nextfframe %jd\n", (intmax_t) nextfframe);
	fprintf(stderr, "frames2ignore %jd\n", (intmax_t) frames2ignore);
	fprintf(stderr, "fpos_first_frame %jd\n", (intmax_t) fpos_first_frame);
	fprintf(stderr, "fpos_next_frame %jd\n", (intmax_t) fpos_next_frame);
	fprintf(stderr, "fpos_after_data %jd\n", (intmax_t) fpos_after_data);
	fprintf(stderr, "totalvframes %jd\n", (intmax_t) totalvframes);
	fprintf(stderr, "nextvframe %jd\n", (intmax_t) nextvframe);
	fprintf(stderr, "data_size %jd\n", (intmax_t) data_size);
}

Marker *Track::getMarker(int markerID)
{
	for (int i=0; i<markerCount; i++)
		if (markers[i].id == markerID)
			return &markers[i];

	_af_error(AF_BAD_MARKID, "no marker with id %d found in track %d",
		markerID, id);

	return NULL;
}

status Track::copyMarkers(TrackSetup *setup)
{
	if ((markerCount = setup->markerCount) == 0)
	{
		markers = NULL;
		return AF_SUCCEED;
	}

	markers = _af_marker_new(markerCount);
	if (!markers)
		return AF_FAIL;

	for (int i=0; i<markerCount; i++)
	{
		markers[i].id = setup->markers[i].id;
		markers[i].name = _af_strdup(setup->markers[i].name);
		if (!markers[i].name)
			return AF_FAIL;

		markers[i].comment = _af_strdup(setup->markers[i].comment);
		if (!markers[i].comment)
			return AF_FAIL;
		markers[i].position = 0;
	}

	return AF_SUCCEED;
}

void Track::computeTotalFileFrames()
{
	if (f.bytesPerPacket && f.framesPerPacket)
		totalfframes = (data_size / f.bytesPerPacket) * f.framesPerPacket;
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	track.h
*/

#ifndef TRACK_H
#define TRACK_H

#include "AudioFormat.h"
#include "Shared.h"
#include "afinternal.h"

class ModuleState;
class PacketTable;
struct Marker;
struct MarkerSetup;

struct TrackSetup
{
	int id;

	AudioFormat f;

	bool rateSet, sampleFormatSet, sampleWidthSet, byteOrderSet,
		channelCountSet, compressionSet, aesDataSet, markersSet,
		dataOffsetSet, frameCountSet;

	int markerCount;
	MarkerSetup *markers;

	AFfileoffset dataOffset;
	AFframecount frameCount;
};

struct Track
{
	Track();
	~Track();

	int	id;	/* usually AF_DEFAULT_TRACKID */

	AudioFormat f, v;	/* file and virtual audio formats */

	SharedPtr<PacketTable> m_packetTable;

	double *channelMatrix;

	int markerCount;
	Marker *markers;

	bool hasAESData;	/* Is AES nonaudio data present? */
	unsigned char aesData[24];	/* AES nonaudio data */

	AFframecount totalfframes;		/* frameCount */
	AFframecount nextfframe;		/* currentFrame */
	AFframecount frames2ignore;
	AFfileoffset fpos_first_frame;	/* dataStart */
	AFfileoffset fpos_next_frame;
	AFfileoffset fpos_after_data;
	AFframecount totalvframes;
	AFframecount nextvframe;
	AFfileoffset data_size;		/* trackBytes */

	SharedPtr<ModuleState> ms;

	double taper, dynamic_range;
	bool ratecvt_filter_params_set;

	bool filemodhappy;

	void print();

	Marker *getMarker(int markerID);
	status copyMarkers(TrackSetup *setup);

	void computeTotalFileFrames();
};

#endif
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "UUID.h"

#include <stdio.h>
#include <string.h>

bool UUID::operator==(const UUID &u) const
{
	return !memcmp(data, u.data, 16);
}

bool UUID::operator!=(const UUID &u) const
{
	return memcmp(data, u.data, 16) != 0;
}

std::string UUID::name() const
{
	char s[37];
	uint32_t u1 =
		(data[0] << 24) |
		(data[1] << 16) |
		(data[2] << 8) |
		data[3];
	uint16_t u2 =
		(data[4] << 8) |
		data[5];
	uint16_t u3 =
		(data[6] << 8) |
		data[7];
	uint16_t u4 =
		(data[8] << 8) |
		data[9];
	snprintf(s, 37, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
		u1, u2, u3, u4,
		data[10], data[11], data[12], data[13], data[14], data[15]);
	return std::string(s);
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef UUID_H
#define UUID_H

#include <stdint.h>
#include <string>

struct UUID
{
	uint8_t data[16];

	bool operator==(const UUID &) const;
	bool operator!=(const UUID &) const;
	std::string name() const;
};

#endif
/*
	Audio File Library
	Copyright (C) 2011-2013, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "VOC.h"

#include "File.h"
#include "Track.h"
#include "Setup.h"
#include "byteorder.h"
#include "util.h"

#include <string.h>
#include <assert.h>

const int _af_voc_compression_types[_AF_VOC_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW
};

static const int kVOCMagicLength = 20;
static const char kVOCMagic[kVOCMagicLength + 1] = "Creative Voice File\x1a";

enum
{
	kVOCTerminator = 0,
	kVOCSoundData = 1,
	kVOCSoundDataContinuation = 2,
	kVOCSilence = 3,
	kVOCMarker = 4,
	kVOCText = 5,
	kVOCRepeatStart = 6,
	kVOCRepeatEnd = 7,
	kVOCExtendedInfo = 8,
	kVOCSoundDataNew = 9
};

enum
{
	kVOCFormatU8 = 0,
	kVOCFormatCreativeADPCM4_8 = 1,
	kVOCFormatCreativeADPCM3_8 = 2,
	kVOCFormatCreativeADPCM2_8 = 3,
	kVOCFormatS16 = 4,
	kVOCFormatAlaw = 6,
	kVOCFormatUlaw = 7,
	kVOCFormatCreativeADPCM4_16 = 0x200,
};

static const _AFfilesetup vocDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	// valid
	AF_FILE_VOC,			// fileFormat
	true,	// trackSet
	true,	// instrumentSet
	true,	// miscellaneousSet
	1,		// trackCount
	NULL,	// tracks
	1,		// instrumentCount
	NULL,	// instruments
	0,		// miscellaneousCount
	NULL	// miscellaneous
};

VOCFile::VOCFile() :
	m_soundDataOffset(-1)
{
	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
}

bool VOCFile::recognize(File *f)
{
	f->seek(0, File::SeekFromBeginning);
	char buffer[kVOCMagicLength];
	if (f->read(buffer, kVOCMagicLength) != kVOCMagicLength)
		return false;
	if (memcmp(buffer, kVOCMagic, kVOCMagicLength) != 0)
		return false;
	return true;
}

AFfilesetup VOCFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "VOC file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->sampleFormatSet)
	{
		if (!track->f.isInteger())
		{
			_af_error(AF_BAD_SAMPFMT,
				"VOC format supports only integer audio data");
			return AF_NULL_FILESETUP;
		}

		if ((track->f.isSigned() && track->f.sampleWidth != 16) ||
			(track->f.isUnsigned() && track->f.sampleWidth != 8))
		{
			_af_error(AF_BAD_SAMPFMT,
				"VOC format supports only 16-bit signed or 8-bit unsigned data");
			return AF_NULL_FILESETUP;
		}
	}
	else
		_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
			track->f.sampleWidth);

	if (track->f.isUncompressed() &&
		track->byteOrderSet &&
		track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
		track->f.isByteOrderSignificant())
	{
		_af_error(AF_BAD_BYTEORDER, "VOC supports only little-endian data");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed())
		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW)
	{
		_af_error(AF_BAD_COMPTYPE,
			"compression format %d not supported in VOC file",
			track->f.compressionType);
		return AF_NULL_FILESETUP;
	}

	if (track->markersSet && track->markerCount)
	{
		_af_error(AF_BAD_NUMMARKS, "VOC does not support markers");
		return AF_NULL_FILESETUP;
	}

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "VOC does not support AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet && setup->instrumentCount)
	{
		_af_error(AF_BAD_FILESETUP, "VOC does not support instruments");
		return AF_NULL_FILESETUP;
	}

	if (setup->miscellaneousSet && setup->miscellaneousCount)
	{
		_af_error(AF_BAD_FILESETUP, "VOC does not support miscellaneous data");
		return AF_NULL_FILESETUP;
	}

	return _af_filesetup_copy(setup, &vocDefaultFileSetup, true);
}

status VOCFile::readInit(AFfilesetup)
{
	m_fh->seek(20, File::SeekFromBeginning);

	uint16_t dataOffset, version, checksum;
	readU16(&dataOffset);
	readU16(&version);
	readU16(&checksum);

	Track *track = allocateTrack();

	bool hasExtendedInfo = false;
	bool foundSoundData = false;

	off_t position = m_fh->tell();
	off_t fileLength = m_fh->length();
	while (position < fileLength)
	{
		uint32_t blockHeader;
		if (!readU32(&blockHeader))
			break;
		uint8_t blockType = blockHeader & 0xff;
		uint32_t blockSize = blockHeader >> 8;

		if (blockType == kVOCSoundData)
		{
			if (foundSoundData)
			{
				_af_error(AF_BAD_HEADER, "VOC file contains multiple sound data blocks");
				return AF_FAIL;
			}

			foundSoundData = true;

			uint8_t frequencyDivisor, codec;
			readU8(&frequencyDivisor);
			readU8(&codec);

			if (!hasExtendedInfo)
			{
				track->f.channelCount = 1;
				track->f.sampleRate = 1000000 / (256 - frequencyDivisor);
			}

			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
			track->f.framesPerPacket = 1;

			if (codec == kVOCFormatU8)
			{
				_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, 8);
				track->f.computeBytesPerPacketPCM();
			}
			else if (codec == kVOCFormatCreativeADPCM4_8 ||
				codec == kVOCFormatCreativeADPCM3_8 ||
				codec == kVOCFormatCreativeADPCM2_8)
			{
				_af_error(AF_BAD_NOT_IMPLEMENTED,
					"Creative ADPCM compression is not currently suppported");
				return AF_FAIL;
			}
			else
			{
				_af_error(AF_BAD_CODEC_TYPE,
					"VOC file contains unrecognized codec type %d", codec);
				return AF_FAIL;
			}

			track->fpos_first_frame = m_fh->tell();
			track->data_size = m_fh->length() - 1 - track->fpos_first_frame;
			track->computeTotalFileFrames();
		}
		else if (blockType == kVOCExtendedInfo)
		{
			if (foundSoundData)
			{
				_af_error(AF_BAD_HEADER, "VOC extended information found after sound data");
				return AF_FAIL;
			}

			hasExtendedInfo = true;

			uint16_t frequencyDivisor;
			uint8_t bitsPerSample;
			uint8_t isStereo;
			readU16(&frequencyDivisor);
			readU8(&bitsPerSample);
			readU8(&isStereo);

			track->f.sampleWidth = bitsPerSample;
			track->f.channelCount = isStereo ? 2 : 1;
			uint32_t frequencyDividend = 256000000 / (isStereo ? 2 : 1);
			track->f.sampleRate = frequencyDividend / (65536 - frequencyDivisor);
		}
		else if (blockType == kVOCSoundDataNew)
		{
			if (foundSoundData)
			{
				_af_error(AF_BAD_HEADER, "VOC file contains multiple sound data blocks");
				return AF_FAIL;
			}

			foundSoundData = true;

			uint32_t sampleRate;
			uint8_t bitsPerSample, channels;
			uint16_t format;
			uint32_t pad;
			readU32(&sampleRate);
			readU8(&bitsPerSample);
			readU8(&channels);
			readU16(&format);
			readU32(&pad);

			if (!channels)
			{
				_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
				return AF_FAIL;
			}

			track->fpos_first_frame = m_fh->tell();
			track->data_size = blockSize - 12;

			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
			track->f.sampleRate = sampleRate;
			track->f.channelCount = channels;
			track->f.framesPerPacket = 1;

			if (format == kVOCFormatU8)
			{
				_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, 8);
				track->f.computeBytesPerPacketPCM();
			}
			else if (format == kVOCFormatS16)
			{
				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
				track->f.computeBytesPerPacketPCM();
			}
			else if (format == kVOCFormatAlaw)
			{
				track->f.compressionType = AF_COMPRESSION_G711_ALAW;
				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
				track->f.bytesPerPacket = track->f.channelCount;
				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
			}
			else if (format == kVOCFormatUlaw)
			{
				track->f.compressionType = AF_COMPRESSION_G711_ULAW;
				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
				track->f.bytesPerPacket = track->f.channelCount;
				_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
			}
			else if (format == kVOCFormatCreativeADPCM4_8 ||
				format == kVOCFormatCreativeADPCM3_8 ||
				format == kVOCFormatCreativeADPCM2_8 ||
				format == kVOCFormatCreativeADPCM4_16)
			{
				_af_error(AF_BAD_NOT_IMPLEMENTED,
					"Creative ADPCM compression is not currently supported");
				return AF_FAIL;
			}
			else
			{
				_af_error(AF_BAD_CODEC_TYPE,
					"VOC file contains unrecognized codec type %d", format);
				return AF_FAIL;
			}

			track->computeTotalFileFrames();
		}

		position += 4 + blockSize;

		m_fh->seek(position, File::SeekFromBeginning);
	}

	return AF_SUCCEED;
}

status VOCFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	m_fh->write(kVOCMagic, kVOCMagicLength);
	uint16_t dataOffset = 0x001a;
	uint16_t version = 0x0114;
	uint16_t checksum = 0x1234 + ~version;
	writeU16(&dataOffset);
	writeU16(&version);
	writeU16(&checksum);

	return writeSoundData();
}

status VOCFile::update()
{
	if (writeSoundData() == AF_FAIL || writeTerminator() == AF_FAIL)
		return AF_FAIL;
	return AF_SUCCEED;
}

status VOCFile::writeSoundData()
{
	if (m_soundDataOffset == -1)
		m_soundDataOffset = m_fh->tell();
	else
		m_fh->seek(m_soundDataOffset, File::SeekFromBeginning);

	Track *track = getTrack();

	assert((track->f.isSigned() && track->f.sampleWidth == 16) ||
		(track->f.isUnsigned() && track->f.sampleWidth == 8));

	uint8_t blockType = kVOCSoundDataNew;
	uint32_t blockSize = 12 + track->data_size;
	uint32_t blockHeader = blockSize << 8 | blockType;
	if (!writeU32(&blockHeader))
		return AF_FAIL;

	uint32_t sampleRate = track->f.sampleRate;
	uint8_t bitsPerSample = track->f.sampleWidth;
	uint8_t channels = track->f.channelCount;
	uint16_t format;
	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
	{
		format = kVOCFormatUlaw;
		bitsPerSample = 8;
	}
	else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
	{
		format = kVOCFormatAlaw;
		bitsPerSample = 8;
	}
	else if (track->f.compressionType == AF_COMPRESSION_NONE)
	{
		if (track->f.isUnsigned())
			format = kVOCFormatU8;
		else
			format = kVOCFormatS16;
	}
	uint32_t pad = 0;
	if (!writeU32(&sampleRate) ||
		!writeU8(&bitsPerSample) ||
		!writeU8(&channels) ||
		!writeU16(&format) ||
		!writeU32(&pad))
		return AF_FAIL;

	if (track->fpos_first_frame == 0)
		track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}

status VOCFile::writeTerminator()
{
	Track *track = getTrack();
	m_fh->seek(track->fpos_first_frame + track->data_size, File::SeekFromBeginning);
	uint8_t terminator = kVOCTerminator;
	if (!writeU8(&terminator))
		return AF_FAIL;
	return AF_SUCCEED;
}
/*
	Audio File Library
	Copyright (C) 2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef VOC_H
#define VOC_H

#include "Compiler.h"
#include "FileHandle.h"

#define _AF_VOC_NUM_COMPTYPES 2
extern const int _af_voc_compression_types[_AF_VOC_NUM_COMPTYPES];

class VOCFile : public _AFfilehandle
{
public:
	VOCFile();

	static bool recognize(File *);
	static AFfilesetup completeSetup(AFfilesetup);

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;
	status update() OVERRIDE;

private:
	status writeSoundData();
	status writeTerminator();

	AFfileoffset m_soundDataOffset;
};

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, 2003-2004, 2010-2013, Michael Pruett <michael@68k.org>
	Copyright (C) 2000-2002, Silicon Graphics, Inc.
	Copyright (C) 2002-2003, Davy Durham

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	WAVE.cpp

	This file contains code for reading and writing RIFF WAVE format
	sound files.
*/

#include "config.h"
#include "WAVE.h"

#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "Instrument.h"
#include "Marker.h"
#include "Setup.h"
#include "Tag.h"
#include "Track.h"
#include "UUID.h"
#include "byteorder.h"
#include "util.h"

/* These constants are from RFC 2361. */
enum
{
	WAVE_FORMAT_UNKNOWN = 0x0000,	/* Microsoft Unknown Wave Format */
	WAVE_FORMAT_PCM = 0x0001,	/* Microsoft PCM Format */
	WAVE_FORMAT_ADPCM = 0x0002,	/* Microsoft ADPCM Format */
	WAVE_FORMAT_IEEE_FLOAT = 0x0003,	/* IEEE Float */
	WAVE_FORMAT_VSELP = 0x0004,	/* Compaq Computer's VSELP */
	WAVE_FORMAT_IBM_CVSD = 0x0005,	/* IBM CVSD */
	WAVE_FORMAT_ALAW = 0x0006,	/* Microsoft ALAW */
	WAVE_FORMAT_MULAW = 0x0007,	/* Microsoft MULAW */
	WAVE_FORMAT_OKI_ADPCM = 0x0010,	/* OKI ADPCM */
	WAVE_FORMAT_DVI_ADPCM = 0x0011,	/* Intel's DVI ADPCM */
	WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012,	/* Videologic's MediaSpace ADPCM */
	WAVE_FORMAT_SIERRA_ADPCM = 0x0013,	/* Sierra ADPCM */
	WAVE_FORMAT_G723_ADPCM = 0x0014,	/* G.723 ADPCM */
	WAVE_FORMAT_DIGISTD = 0x0015,	/* DSP Solutions' DIGISTD */
	WAVE_FORMAT_DIGIFIX = 0x0016,	/* DSP Solutions' DIGIFIX */
	WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017,	/* Dialogic OKI ADPCM */
	WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018,	/* MediaVision ADPCM */
	WAVE_FORMAT_CU_CODEC = 0x0019,	/* HP CU */
	WAVE_FORMAT_YAMAHA_ADPCM = 0x0020,	/* Yamaha ADPCM */
	WAVE_FORMAT_SONARC = 0x0021,	/* Speech Compression's Sonarc */
	WAVE_FORMAT_DSP_TRUESPEECH = 0x0022,	/* DSP Group's True Speech */
	WAVE_FORMAT_ECHOSC1 = 0x0023,	/* Echo Speech's EchoSC1 */
	WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024,	/* Audiofile AF36 */
	WAVE_FORMAT_APTX = 0x0025,	/* APTX */
	WAVE_FORMAT_DOLBY_AC2 = 0x0030,	/* Dolby AC2 */
	WAVE_FORMAT_GSM610 = 0x0031,	/* GSM610 */
	WAVE_FORMAT_MSNAUDIO = 0x0032,	/* MSNAudio */
	WAVE_FORMAT_ANTEX_ADPCME = 0x0033,	/* Antex ADPCME */

	WAVE_FORMAT_MPEG = 0x0050,		/* MPEG */
	WAVE_FORMAT_MPEGLAYER3 = 0x0055,	/* MPEG layer 3 */
	WAVE_FORMAT_LUCENT_G723 = 0x0059,	/* Lucent G.723 */
	WAVE_FORMAT_G726_ADPCM = 0x0064,	/* G.726 ADPCM */
	WAVE_FORMAT_G722_ADPCM = 0x0065,	/* G.722 ADPCM */

	IBM_FORMAT_MULAW = 0x0101,
	IBM_FORMAT_ALAW = 0x0102,
	IBM_FORMAT_ADPCM = 0x0103,

	WAVE_FORMAT_CREATIVE_ADPCM = 0x0200,

	WAVE_FORMAT_EXTENSIBLE = 0xfffe
};

const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES] =
{
	AF_COMPRESSION_G711_ULAW,
	AF_COMPRESSION_G711_ALAW,
	AF_COMPRESSION_IMA,
	AF_COMPRESSION_MS_ADPCM
};

const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS] =
{
	{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
	{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
	{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
	{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
	{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
	{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
	{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} }
};

static const _AFfilesetup waveDefaultFileSetup =
{
	_AF_VALID_FILESETUP,	/* valid */
	AF_FILE_WAVE,		/* fileFormat */
	true,			/* trackSet */
	true,			/* instrumentSet */
	true,			/* miscellaneousSet  */
	1,			/* trackCount */
	NULL,			/* tracks */
	0,			/* instrumentCount */
	NULL,			/* instruments */
	0,			/* miscellaneousCount */
	NULL			/* miscellaneous */
};

static const UUID _af_wave_guid_pcm =
{{
	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_ieee_float =
{{
	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_ulaw =
{{
	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_alaw =
{{
	0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};

WAVEFile::WAVEFile()
{
	setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);

	m_factOffset = 0;
	m_miscellaneousOffset = 0;
	m_markOffset = 0;
	m_dataSizeOffset = 0;

	m_msadpcmNumCoefficients = 0;
}

status WAVEFile::parseFrameCount(const Tag &id, uint32_t size)
{
	Track *track = getTrack();

	uint32_t totalFrames;
	readU32(&totalFrames);

	track->totalfframes = totalFrames;

	return AF_SUCCEED;
}

status WAVEFile::parseFormat(const Tag &id, uint32_t size)
{
	Track *track = getTrack();

	uint16_t formatTag;
	readU16(&formatTag);
	uint16_t channelCount;
	readU16(&channelCount);
	uint32_t sampleRate;
	readU32(&sampleRate);
	uint32_t averageBytesPerSecond;
	readU32(&averageBytesPerSecond);
	uint16_t blockAlign;
	readU16(&blockAlign);

	if (!channelCount)
	{
		_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
		return AF_FAIL;
	}

	track->f.channelCount = channelCount;
	track->f.sampleRate = sampleRate;
	track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;

	/* Default to uncompressed audio data. */
	track->f.compressionType = AF_COMPRESSION_NONE;
	track->f.framesPerPacket = 1;

	switch (formatTag)
	{
		case WAVE_FORMAT_PCM:
		{
			uint16_t bitsPerSample;
			readU16(&bitsPerSample);

			track->f.sampleWidth = bitsPerSample;

			if (bitsPerSample == 0 || bitsPerSample > 32)
			{
				_af_error(AF_BAD_WIDTH,
					"bad sample width of %d bits",
					bitsPerSample);
				return AF_FAIL;
			}

			if (bitsPerSample <= 8)
				track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
			else
				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
		}
		break;

		case WAVE_FORMAT_MULAW:
		case IBM_FORMAT_MULAW:
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
			track->f.bytesPerPacket = track->f.channelCount;
			break;

		case WAVE_FORMAT_ALAW:
		case IBM_FORMAT_ALAW:
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
			track->f.bytesPerPacket = track->f.channelCount;
			break;

		case WAVE_FORMAT_IEEE_FLOAT:
		{
			uint16_t bitsPerSample;
			readU16(&bitsPerSample);

			if (bitsPerSample == 64)
			{
				track->f.sampleWidth = 64;
				track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
			}
			else
			{
				track->f.sampleWidth = 32;
				track->f.sampleFormat = AF_SAMPFMT_FLOAT;
			}
		}
		break;

		case WAVE_FORMAT_ADPCM:
		{
			uint16_t bitsPerSample, extraByteCount,
					samplesPerBlock, numCoefficients;

			if (track->f.channelCount != 1 &&
				track->f.channelCount != 2)
			{
				_af_error(AF_BAD_CHANNELS,
					"WAVE file with MS ADPCM compression "
					"must have 1 or 2 channels");
			}

			readU16(&bitsPerSample);
			readU16(&extraByteCount);
			readU16(&samplesPerBlock);
			readU16(&numCoefficients);

			/* numCoefficients should be at least 7. */
			assert(numCoefficients >= 7 && numCoefficients <= 255);
			if (numCoefficients < 7 || numCoefficients > 255)
			{
				_af_error(AF_BAD_HEADER,
						"Bad number of coefficients");
				return AF_FAIL;
			}

			m_msadpcmNumCoefficients = numCoefficients;

			for (int i=0; i<m_msadpcmNumCoefficients; i++)
			{
				readS16(&m_msadpcmCoefficients[i][0]);
				readS16(&m_msadpcmCoefficients[i][1]);
			}

			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.compressionType = AF_COMPRESSION_MS_ADPCM;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;

			track->f.framesPerPacket = samplesPerBlock;
			track->f.bytesPerPacket = blockAlign;

			// Create the parameter list.
			AUpvlist pv = AUpvnew(2);
			AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
			AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
			long l = m_msadpcmNumCoefficients;
			AUpvsetval(pv, 0, &l);

			AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
			AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
			void *v = m_msadpcmCoefficients;
			AUpvsetval(pv, 1, &v);

			track->f.compressionParams = pv;
		}
		break;

		case WAVE_FORMAT_DVI_ADPCM:
		{
			uint16_t bitsPerSample, extraByteCount, samplesPerBlock;

			readU16(&bitsPerSample);
			readU16(&extraByteCount);
			readU16(&samplesPerBlock);

			if (bitsPerSample != 4)
			{
				_af_error(AF_BAD_NOT_IMPLEMENTED,
					"IMA ADPCM compression supports only 4 bits per sample");
			}

			int bytesPerBlock = (samplesPerBlock + 14) / 8 * 4 * channelCount;
			if (bytesPerBlock > blockAlign || (samplesPerBlock % 8) != 1)
			{
				_af_error(AF_BAD_CODEC_CONFIG,
					"Invalid samples per block for IMA ADPCM compression");
			}

			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			track->f.compressionType = AF_COMPRESSION_IMA;
			track->f.byteOrder = _AF_BYTEORDER_NATIVE;

			initIMACompressionParams();

			track->f.framesPerPacket = samplesPerBlock;
			track->f.bytesPerPacket = blockAlign;
		}
		break;

		case WAVE_FORMAT_EXTENSIBLE:
		{
			uint16_t bitsPerSample;
			readU16(&bitsPerSample);
			uint16_t extraByteCount;
			readU16(&extraByteCount);
			uint16_t reserved;
			readU16(&reserved);
			uint32_t channelMask;
			readU32(&channelMask);
			UUID subformat;
			readUUID(&subformat);
			if (subformat == _af_wave_guid_pcm)
			{
				track->f.sampleWidth = bitsPerSample;

				if (bitsPerSample == 0 || bitsPerSample > 32)
				{
					_af_error(AF_BAD_WIDTH,
						"bad sample width of %d bits",
						bitsPerSample);
					return AF_FAIL;
				}

				// Use valid bits per sample if bytes per sample is the same.
				if (reserved <= bitsPerSample &&
					(reserved + 7) / 8 == (bitsPerSample + 7) / 8)
					track->f.sampleWidth = reserved;

				if (bitsPerSample <= 8)
					track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
				else
					track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			}
			else if (subformat == _af_wave_guid_ieee_float)
			{
				if (bitsPerSample == 64)
				{
					track->f.sampleWidth = 64;
					track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
				}
				else
				{
					track->f.sampleWidth = 32;
					track->f.sampleFormat = AF_SAMPFMT_FLOAT;
				}
			}
			else if (subformat == _af_wave_guid_alaw ||
				subformat == _af_wave_guid_ulaw)
			{
				track->f.compressionType = subformat == _af_wave_guid_alaw ?
					AF_COMPRESSION_G711_ALAW : AF_COMPRESSION_G711_ULAW;
				track->f.sampleWidth = 16;
				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
				track->f.byteOrder = _AF_BYTEORDER_NATIVE;
				track->f.bytesPerPacket = channelCount;
			}
			else
			{
				_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE extensible data format %s is not currently supported", subformat.name().c_str());
				return AF_FAIL;
			}
		}
		break;

		case WAVE_FORMAT_YAMAHA_ADPCM:
		case WAVE_FORMAT_OKI_ADPCM:
		case WAVE_FORMAT_CREATIVE_ADPCM:
		case IBM_FORMAT_ADPCM:
			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE ADPCM data format 0x%x is not currently supported", formatTag);
			return AF_FAIL;
			break;

		case WAVE_FORMAT_MPEG:
			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG data format is not supported");
			return AF_FAIL;
			break;

		case WAVE_FORMAT_MPEGLAYER3:
			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG layer 3 data format is not supported");
			return AF_FAIL;
			break;

		default:
			_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE file data format 0x%x not currently supported != 0xfffe ? %d, != EXTENSIBLE? %d", formatTag, formatTag != 0xfffe, formatTag != WAVE_FORMAT_EXTENSIBLE);
			return AF_FAIL;
			break;
	}

	if (track->f.isUncompressed())
		track->f.computeBytesPerPacketPCM();

	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);

	return AF_SUCCEED;
}

status WAVEFile::parseData(const Tag &id, uint32_t size)
{
	Track *track = getTrack();

	track->fpos_first_frame = m_fh->tell();
	track->data_size = size;

	return AF_SUCCEED;
}

status WAVEFile::parsePlayList(const Tag &id, uint32_t size)
{
	uint32_t segmentCount;
	readU32(&segmentCount);

	if (segmentCount == 0)
	{
		m_instrumentCount = 0;
		m_instruments = NULL;
		return AF_SUCCEED;
	}

	for (unsigned segment=0; segment<segmentCount; segment++)
	{
		uint32_t startMarkID, loopLength, loopCount;

		readU32(&startMarkID);
		readU32(&loopLength);
		readU32(&loopCount);
	}

	return AF_SUCCEED;
}

status WAVEFile::parseCues(const Tag &id, uint32_t size)
{
	Track *track = getTrack();

	uint32_t markerCount;
	readU32(&markerCount);
	track->markerCount = markerCount;

	if (markerCount == 0)
	{
		track->markers = NULL;
		return AF_SUCCEED;
	}

	if ((track->markers = _af_marker_new(markerCount)) == NULL)
		return AF_FAIL;

	for (unsigned i=0; i<markerCount; i++)
	{
		uint32_t id, position, chunkid;
		uint32_t chunkByteOffset, blockByteOffset;
		uint32_t sampleFrameOffset;
		Marker *marker = &track->markers[i];

		readU32(&id);
		readU32(&position);
		readU32(&chunkid);
		readU32(&chunkByteOffset);
		readU32(&blockByteOffset);

		/*
			sampleFrameOffset represents the position of
			the mark in units of frames.
		*/
		readU32(&sampleFrameOffset);

		marker->id = id;
		marker->position = sampleFrameOffset;
		marker->name = _af_strdup("");
		marker->comment = _af_strdup("");
	}

	return AF_SUCCEED;
}

/* Parse an adtl sub-chunk within a LIST chunk. */
status WAVEFile::parseADTLSubChunk(const Tag &id, uint32_t size)
{
	Track *track = getTrack();

	AFfileoffset endPos = m_fh->tell() + size;

	while (m_fh->tell() < endPos)
	{
		Tag chunkID;
		uint32_t chunkSize;

		readTag(&chunkID);
		readU32(&chunkSize);

		if (chunkID == "labl" || chunkID == "note")
		{
			uint32_t id;
			long length=chunkSize-4;
			char *p = (char *) _af_malloc(length);

			readU32(&id);
			m_fh->read(p, length);

			Marker *marker = track->getMarker(id);

			if (marker)
			{
				if (chunkID == "labl")
				{
					free(marker->name);
					marker->name = p;
				}
				else if (chunkID == "note")
				{
					free(marker->comment);
					marker->comment = p;
				}
				else
					free(p);
			}
			else
				free(p);

			/*
				If chunkSize is odd, skip an extra byte
				at the end of the chunk.
			*/
			if ((chunkSize % 2) != 0)
				m_fh->seek(1, File::SeekFromCurrent);
		}
		else
		{
			/* If chunkSize is odd, skip an extra byte. */
			m_fh->seek(chunkSize + (chunkSize % 2), File::SeekFromCurrent);
		}
	}
	return AF_SUCCEED;
}

/* Parse an INFO sub-chunk within a LIST chunk. */
status WAVEFile::parseINFOSubChunk(const Tag &id, uint32_t size)
{
	AFfileoffset endPos = m_fh->tell() + size;

	while (m_fh->tell() < endPos)
	{
		int misctype = AF_MISC_UNRECOGNIZED;
		Tag miscid;
		uint32_t miscsize;

		readTag(&miscid);
		readU32(&miscsize);

		if (miscid == "IART")
			misctype = AF_MISC_AUTH;
		else if (miscid == "INAM")
			misctype = AF_MISC_NAME;
		else if (miscid == "ICOP")
			misctype = AF_MISC_COPY;
		else if (miscid == "ICMT")
			misctype = AF_MISC_ICMT;
		else if (miscid == "ICRD")
			misctype = AF_MISC_ICRD;
		else if (miscid == "ISFT")
			misctype = AF_MISC_ISFT;

		if (misctype != AF_MISC_UNRECOGNIZED)
		{
			char *string = (char *) _af_malloc(miscsize);

			m_fh->read(string, miscsize);

			m_miscellaneousCount++;
			m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous, sizeof (Miscellaneous) * m_miscellaneousCount);

			m_miscellaneous[m_miscellaneousCount-1].id = m_miscellaneousCount;
			m_miscellaneous[m_miscellaneousCount-1].type = misctype;
			m_miscellaneous[m_miscellaneousCount-1].size = miscsize;
			m_miscellaneous[m_miscellaneousCount-1].position = 0;
			m_miscellaneous[m_miscellaneousCount-1].buffer = string;
		}
		else
		{
			m_fh->seek(miscsize, File::SeekFromCurrent);
		}

		/* Make the current position an even number of bytes.  */
		if (miscsize % 2 != 0)
			m_fh->seek(1, File::SeekFromCurrent);
	}
	return AF_SUCCEED;
}

status WAVEFile::parseList(const Tag &id, uint32_t size)
{
	Tag typeID;
	readTag(&typeID);
	size-=4;

	if (typeID == "adtl")
	{
		/* Handle adtl sub-chunks. */
		return parseADTLSubChunk(typeID, size);
	}
	else if (typeID == "INFO")
	{
		/* Handle INFO sub-chunks. */
		return parseINFOSubChunk(typeID, size);
	}
	else
	{
		/* Skip unhandled sub-chunks. */
		m_fh->seek(size, File::SeekFromCurrent);
		return AF_SUCCEED;
	}
	return AF_SUCCEED;
}

status WAVEFile::parseInstrument(const Tag &id, uint32_t size)
{
	uint8_t baseNote;
	int8_t detune, gain;
	uint8_t lowNote, highNote, lowVelocity, highVelocity;
	uint8_t padByte;

	readU8(&baseNote);
	readS8(&detune);
	readS8(&gain);
	readU8(&lowNote);
	readU8(&highNote);
	readU8(&lowVelocity);
	readU8(&highVelocity);
	readU8(&padByte);

	return AF_SUCCEED;
}

bool WAVEFile::recognize(File *fh)
{
	uint8_t buffer[8];

	fh->seek(0, File::SeekFromBeginning);

	if (fh->read(buffer, 8) != 8 || memcmp(buffer, "RIFF", 4) != 0)
		return false;
	if (fh->read(buffer, 4) != 4 || memcmp(buffer, "WAVE", 4) != 0)
		return false;

	return true;
}

status WAVEFile::readInit(AFfilesetup setup)
{
	Tag type, formtype;
	uint32_t size;
	uint32_t index = 0;

	bool hasFormat = false;
	bool hasData = false;
	bool hasFrameCount = false;

	Track *track = allocateTrack();

	m_fh->seek(0, File::SeekFromBeginning);

	readTag(&type);
	readU32(&size);
	readTag(&formtype);

	assert(type == "RIFF");
	assert(formtype == "WAVE");

	/* Include the offset of the form type. */
	index += 4;

	while (index < size)
	{
		Tag chunkid;
		uint32_t chunksize = 0;
		status result;

		readTag(&chunkid);
		readU32(&chunksize);

		if (chunkid == "fmt ")
		{
			result = parseFormat(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasFormat = true;
		}
		else if (chunkid == "data")
		{
			/* The format chunk must precede the data chunk. */
			if (!hasFormat)
			{
				_af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
				return AF_FAIL;
			}

			result = parseData(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasData = true;
		}
		else if (chunkid == "inst")
		{
			result = parseInstrument(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkid == "fact")
		{
			hasFrameCount = true;
			result = parseFrameCount(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkid == "cue ")
		{
			result = parseCues(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkid == "LIST" || chunkid == "list")
		{
			result = parseList(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkid == "INST")
		{
			result = parseInstrument(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (chunkid == "plst")
		{
			result = parsePlayList(chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}

		index += chunksize + 8;

		/* All chunks must be aligned on an even number of bytes */
		if ((index % 2) != 0)
			index++;

		m_fh->seek(index + 8, File::SeekFromBeginning);
	}

	/* The format chunk and the data chunk are required. */
	if (!hasFormat || !hasData)
	{
		return AF_FAIL;
	}

	/*
		At this point we know that the file has a format chunk and a
		data chunk, so we can assume that track->f and track->data_size
		have been initialized.
	*/
	if (!hasFrameCount)
	{
		if (track->f.bytesPerPacket && track->f.framesPerPacket)
		{
			track->computeTotalFileFrames();
		}
		else
		{
			_af_error(AF_BAD_HEADER, "Frame count required but not found");
			return AF_FAIL;
		}
	}

	return AF_SUCCEED;
}

AFfilesetup WAVEFile::completeSetup(AFfilesetup setup)
{
	if (setup->trackSet && setup->trackCount != 1)
	{
		_af_error(AF_BAD_NUMTRACKS, "WAVE file must have 1 track");
		return AF_NULL_FILESETUP;
	}

	TrackSetup *track = setup->getTrack();
	if (!track)
		return AF_NULL_FILESETUP;

	if (track->f.isCompressed())
	{
		if (!track->sampleFormatSet)
			_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
		else
			_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
	}
	else if (track->sampleFormatSet)
	{
		switch (track->f.sampleFormat)
		{
			case AF_SAMPFMT_FLOAT:
				if (track->sampleWidthSet &&
					track->f.sampleWidth != 32)
				{
					_af_error(AF_BAD_WIDTH,
						"Warning: invalid sample width for floating-point WAVE file: %d (must be 32 bits)\n",
						track->f.sampleWidth);
					_af_set_sample_format(&track->f, AF_SAMPFMT_FLOAT, 32);
				}
				break;

			case AF_SAMPFMT_DOUBLE:
				if (track->sampleWidthSet &&
					track->f.sampleWidth != 64)
				{
					_af_error(AF_BAD_WIDTH,
						"Warning: invalid sample width for double-precision floating-point WAVE file: %d (must be 64 bits)\n",
						track->f.sampleWidth);
					_af_set_sample_format(&track->f, AF_SAMPFMT_DOUBLE, 64);
				}
				break;

			case AF_SAMPFMT_UNSIGNED:
				if (track->sampleWidthSet)
				{
					if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
					{
						_af_error(AF_BAD_WIDTH, "invalid sample width for WAVE file: %d (must be 1-32 bits)\n", track->f.sampleWidth);
						return AF_NULL_FILESETUP;
					}
					if (track->f.sampleWidth > 8)
					{
						_af_error(AF_BAD_SAMPFMT, "WAVE integer data of more than 8 bits must be two's complement signed");
						_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
					}
				}
				else
				/*
					If the sample width is not set but the user requests
					unsigned data, set the width to 8 bits.
				*/
					_af_set_sample_format(&track->f, track->f.sampleFormat, 8);
				break;

			case AF_SAMPFMT_TWOSCOMP:
				if (track->sampleWidthSet)
				{
					if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
					{
						_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
						return AF_NULL_FILESETUP;
					}
					else if (track->f.sampleWidth <= 8)
					{
						_af_error(AF_BAD_SAMPFMT, "Warning: WAVE format integer data of 1-8 bits must be unsigned; setting sample format to unsigned");
						_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, track->f.sampleWidth);
					}
				}
				else
				/*
					If no sample width was specified, we default to 16 bits
					for signed integer data.
				*/
					_af_set_sample_format(&track->f, track->f.sampleFormat, 16);
				break;
		}
	}
	/*
		Otherwise set the sample format depending on the sample
		width or set completely to default.
	*/
	else
	{
		if (!track->sampleWidthSet)
		{
			track->f.sampleWidth = 16;
			track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
		}
		else
		{
			if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
			{
				_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
				return AF_NULL_FILESETUP;
			}
			else if (track->f.sampleWidth > 8)
				/* Here track->f.sampleWidth is in {1..32}. */
				track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
			else
				/* Here track->f.sampleWidth is in {1..8}. */
				track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
		}
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
		track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
		track->f.compressionType != AF_COMPRESSION_IMA &&
		track->f.compressionType != AF_COMPRESSION_MS_ADPCM)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in WAVE format");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed() &&
		track->byteOrderSet &&
		track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
		track->f.isByteOrderSignificant())
	{
		_af_error(AF_BAD_BYTEORDER, "WAVE format only supports little-endian data");
		return AF_NULL_FILESETUP;
	}

	if (track->f.isUncompressed())
		track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;

	if (track->aesDataSet)
	{
		_af_error(AF_BAD_FILESETUP, "WAVE files cannot have AES data");
		return AF_NULL_FILESETUP;
	}

	if (setup->instrumentSet)
	{
		if (setup->instrumentCount > 1)
		{
			_af_error(AF_BAD_NUMINSTS, "WAVE files can have 0 or 1 instrument");
			return AF_NULL_FILESETUP;
		}
		else if (setup->instrumentCount == 1)
		{
			if (setup->instruments[0].loopSet &&
				setup->instruments[0].loopCount > 0 &&
				(!track->markersSet || track->markerCount == 0))
			{
				_af_error(AF_BAD_NUMMARKS, "WAVE files with loops must contain at least 1 marker");
				return AF_NULL_FILESETUP;
			}
		}
	}

	/* Make sure the miscellaneous data is of an acceptable type. */
	if (setup->miscellaneousSet)
	{
		for (int i=0; i<setup->miscellaneousCount; i++)
		{
			switch (setup->miscellaneous[i].type)
			{
				case AF_MISC_COPY:
				case AF_MISC_AUTH:
				case AF_MISC_NAME:
				case AF_MISC_ICRD:
				case AF_MISC_ISFT:
				case AF_MISC_ICMT:
					break;
				default:
					_af_error(AF_BAD_MISCTYPE, "illegal miscellaneous type [%d] for WAVE file", setup->miscellaneous[i].type);
					return AF_NULL_FILESETUP;
			}
		}
	}

	/*
		Allocate an AFfilesetup and make all the unset fields correct.
	*/
	AFfilesetup	newsetup = _af_filesetup_copy(setup, &waveDefaultFileSetup, false);

	/* Make sure we do not copy loops if they are not specified in setup. */
	if (setup->instrumentSet && setup->instrumentCount > 0 &&
		setup->instruments[0].loopSet)
	{
		free(newsetup->instruments[0].loops);
		newsetup->instruments[0].loopCount = 0;
	}

	return newsetup;
}

bool WAVEFile::isInstrumentParameterValid(AUpvlist list, int i)
{
	int param, type;

	AUpvgetparam(list, i, &param);
	AUpvgetvaltype(list, i, &type);
	if (type != AU_PVTYPE_LONG)
		return false;

	long lval;
	AUpvgetval(list, i, &lval);

	switch (param)
	{
		case AF_INST_MIDI_BASENOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_NUMCENTS_DETUNE:
			return ((lval >= -50) && (lval <= 50));

		case AF_INST_MIDI_LOVELOCITY:
			return ((lval >= 1) && (lval <= 127));

		case AF_INST_MIDI_HIVELOCITY:
			return ((lval >= 1) && (lval <= 127));

		case AF_INST_MIDI_LONOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_MIDI_HINOTE:
			return ((lval >= 0) && (lval <= 127));

		case AF_INST_NUMDBS_GAIN:
			return true;

		default:
			return false;
	}

	return true;
}

status WAVEFile::writeFormat()
{
	uint16_t	formatTag, channelCount;
	uint32_t	sampleRate, averageBytesPerSecond;
	uint16_t	blockAlign;
	uint32_t	chunkSize;
	uint16_t	bitsPerSample;

	Track *track = getTrack();

	m_fh->write("fmt ", 4);

	switch (track->f.compressionType)
	{
		case AF_COMPRESSION_NONE:
			chunkSize = 16;
			if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
				track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
			{
				formatTag = WAVE_FORMAT_IEEE_FLOAT;
			}
			else if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
				track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
			{
				formatTag = WAVE_FORMAT_PCM;
			}
			else
			{
				_af_error(AF_BAD_COMPTYPE, "bad sample format");
				return AF_FAIL;
			}

			blockAlign = _af_format_frame_size(&track->f, false);
			bitsPerSample = 8 * _af_format_sample_size(&track->f, false);
			break;

		/*
			G.711 compression uses eight bits per sample.
		*/
		case AF_COMPRESSION_G711_ULAW:
			chunkSize = 18;
			formatTag = IBM_FORMAT_MULAW;
			blockAlign = track->f.channelCount;
			bitsPerSample = 8;
			break;

		case AF_COMPRESSION_G711_ALAW:
			chunkSize = 18;
			formatTag = IBM_FORMAT_ALAW;
			blockAlign = track->f.channelCount;
			bitsPerSample = 8;
			break;

		case AF_COMPRESSION_IMA:
			chunkSize = 20;
			formatTag = WAVE_FORMAT_DVI_ADPCM;
			blockAlign = track->f.bytesPerPacket;
			bitsPerSample = 4;
			break;

		case AF_COMPRESSION_MS_ADPCM:
			chunkSize = 50;
			formatTag = WAVE_FORMAT_ADPCM;
			blockAlign = track->f.bytesPerPacket;
			bitsPerSample = 4;
			break;

		default:
			_af_error(AF_BAD_COMPTYPE, "bad compression type");
			return AF_FAIL;
	}

	writeU32(&chunkSize);
	writeU16(&formatTag);

	channelCount = track->f.channelCount;
	writeU16(&channelCount);

	sampleRate = track->f.sampleRate;
	writeU32(&sampleRate);

	averageBytesPerSecond =
		track->f.sampleRate * _af_format_frame_size(&track->f, false);
	if (track->f.compressionType == AF_COMPRESSION_IMA ||
		track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
		averageBytesPerSecond = track->f.sampleRate * track->f.bytesPerPacket /
			track->f.framesPerPacket;
	writeU32(&averageBytesPerSecond);

	writeU16(&blockAlign);

	writeU16(&bitsPerSample);

	if (track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
		track->f.compressionType == AF_COMPRESSION_G711_ALAW)
	{
		uint16_t zero = 0;
		writeU16(&zero);
	}
	else if (track->f.compressionType == AF_COMPRESSION_IMA)
	{
		uint16_t extraByteCount = 2;
		writeU16(&extraByteCount);
		uint16_t samplesPerBlock = track->f.framesPerPacket;
		writeU16(&samplesPerBlock);
	}
	else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
	{
		uint16_t extraByteCount = 2 + 2 + m_msadpcmNumCoefficients * 4;
		writeU16(&extraByteCount);
		uint16_t samplesPerBlock = track->f.framesPerPacket;
		writeU16(&samplesPerBlock);

		uint16_t numCoefficients = m_msadpcmNumCoefficients;
		writeU16(&numCoefficients);

		for (int i=0; i<m_msadpcmNumCoefficients; i++)
		{
			writeS16(&m_msadpcmCoefficients[i][0]);
			writeS16(&m_msadpcmCoefficients[i][1]);
		}
	}

	return AF_SUCCEED;
}

status WAVEFile::writeFrameCount()
{
	uint32_t factSize = 4;
	uint32_t totalFrameCount;

	Track *track = getTrack();

	/* Omit the fact chunk only for uncompressed integer audio formats. */
	if (track->f.compressionType == AF_COMPRESSION_NONE &&
		(track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
		track->f.sampleFormat == AF_SAMPFMT_UNSIGNED))
		return AF_SUCCEED;

	/*
		If the offset for the fact chunk hasn't been set yet,
		set it to the file's current position.
	*/
	if (m_factOffset == 0)
		m_factOffset = m_fh->tell();
	else
		m_fh->seek(m_factOffset, File::SeekFromBeginning);

	m_fh->write("fact", 4);
	writeU32(&factSize);

	totalFrameCount = track->totalfframes;
	writeU32(&totalFrameCount);

	return AF_SUCCEED;
}

status WAVEFile::writeData()
{
	Track *track = getTrack();

	m_fh->write("data", 4);
	m_dataSizeOffset = m_fh->tell();

	uint32_t chunkSize = track->data_size;

	writeU32(&chunkSize);
	track->fpos_first_frame = m_fh->tell();

	return AF_SUCCEED;
}

status WAVEFile::update()
{
	Track *track = getTrack();

	if (track->fpos_first_frame != 0)
	{
		uint32_t dataLength, fileLength;

		// Update the frame count chunk if present.
		writeFrameCount();

		// Update the length of the data chunk.
		m_fh->seek(m_dataSizeOffset, File::SeekFromBeginning);
		dataLength = (uint32_t) track->data_size;
		writeU32(&dataLength);

		// Update the length of the RIFF chunk.
		fileLength = (uint32_t) m_fh->length();
		fileLength -= 8;

		m_fh->seek(4, File::SeekFromBeginning);
		writeU32(&fileLength);
	}

	/*
		Write the actual data that was set after initializing
		the miscellaneous IDs.	The size of the data will be
		unchanged.
	*/
	writeMiscellaneous();

	// Write the new positions; the size of the data will be unchanged.
	writeCues();

	return AF_SUCCEED;
}

/* Convert an Audio File Library miscellaneous type to a WAVE type. */
static bool misc_type_to_wave (int misctype, Tag *miscid)
{
	if (misctype == AF_MISC_AUTH)
		*miscid = "IART";
	else if (misctype == AF_MISC_NAME)
		*miscid = "INAM";
	else if (misctype == AF_MISC_COPY)
		*miscid = "ICOP";
	else if (misctype == AF_MISC_ICMT)
		*miscid = "ICMT";
	else if (misctype == AF_MISC_ICRD)
		*miscid = "ICRD";
	else if (misctype == AF_MISC_ISFT)
		*miscid = "ISFT";
	else
		return false;

	return true;
}

status WAVEFile::writeMiscellaneous()
{
	if (m_miscellaneousCount != 0)
	{
		uint32_t	miscellaneousBytes;
		uint32_t 	chunkSize;

		/* Start at 12 to account for 'LIST', size, and 'INFO'. */
		miscellaneousBytes = 12;

		/* Then calculate the size of the whole INFO chunk. */
		for (int i=0; i<m_miscellaneousCount; i++)
		{
			Tag miscid;

			// Skip miscellaneous data of an unsupported type.
			if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
				continue;

			// Account for miscellaneous type and size.
			miscellaneousBytes += 8;
			miscellaneousBytes += m_miscellaneous[i].size;

			// Add a pad byte if necessary.
			if (m_miscellaneous[i].size % 2 != 0)
				miscellaneousBytes++;

			assert(miscellaneousBytes % 2 == 0);
		}

		if (m_miscellaneousOffset == 0)
			m_miscellaneousOffset = m_fh->tell();
		else
			m_fh->seek(m_miscellaneousOffset, File::SeekFromBeginning);

		/*
			Write the data.  On the first call to this
			function (from _af_wave_write_init), the
			data won't be available, fh->seek is used to
			reserve space until the data has been provided.
			On subseuent calls to this function (from
			_af_wave_update), the data will really be written.
		*/

		/* Write 'LIST'. */
		m_fh->write("LIST", 4);

		/* Write the size of the following chunk. */
		chunkSize = miscellaneousBytes-8;
		writeU32(&chunkSize);

		/* Write 'INFO'. */
		m_fh->write("INFO", 4);

		/* Write each miscellaneous chunk. */
		for (int i=0; i<m_miscellaneousCount; i++)
		{
			uint32_t miscsize = m_miscellaneous[i].size;
			Tag miscid;

			// Skip miscellaneous data of an unsupported type.
			if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
				continue;

			writeTag(&miscid);
			writeU32(&miscsize);
			if (m_miscellaneous[i].buffer != NULL)
			{
				uint8_t	zero = 0;

				m_fh->write(m_miscellaneous[i].buffer, m_miscellaneous[i].size);

				// Pad if necessary.
				if ((m_miscellaneous[i].size%2) != 0)
					writeU8(&zero);
			}
			else
			{
				int	size;
				size = m_miscellaneous[i].size;

				// Pad if necessary.
				if ((size % 2) != 0)
					size++;
				m_fh->seek(size, File::SeekFromCurrent);
			}
		}
	}

	return AF_SUCCEED;
}

status WAVEFile::writeCues()
{
	Track *track = getTrack();

	if (!track->markerCount)
		return AF_SUCCEED;

	if (m_markOffset == 0)
		m_markOffset = m_fh->tell();
	else
		m_fh->seek(m_markOffset, File::SeekFromBeginning);

	Tag cue("cue ");
	writeTag(&cue);

	/*
		The cue chunk consists of 4 bytes for the number of cue points
		followed by 24 bytes for each cue point record.
	*/
	uint32_t cueChunkSize = 4 + track->markerCount * 24;
	writeU32(&cueChunkSize);
	uint32_t numCues = track->markerCount;
	writeU32(&numCues);

	// Write each marker to the file.
	for (int i=0; i<track->markerCount; i++)
	{
		uint32_t identifier = track->markers[i].id;
		writeU32(&identifier);

		uint32_t position = i;
		writeU32(&position);

		Tag data("data");
		writeTag(&data);

		/*
			For an uncompressed WAVE file which contains only one data chunk,
			chunkStart and blockStart are zero.
		*/
		uint32_t chunkStart = 0;
		writeU32(&chunkStart);

		uint32_t blockStart = 0;
		writeU32(&blockStart);

		AFframecount markPosition = track->markers[i].position;
		uint32_t sampleOffset = markPosition;
		writeU32(&sampleOffset);
	}

	// Now write the cue names and comments within a master list chunk.
	uint32_t listChunkSize = 4;
	for (int i=0; i<track->markerCount; i++)
	{
		const char *name = track->markers[i].name;
		const char *comment = track->markers[i].comment;

		/*
			Each 'labl' or 'note' chunk consists of 4 bytes for the chunk ID,
			4 bytes for the chunk data size, 4 bytes for the cue point ID,
			and then the length of the label as a null-terminated string.

			In all, this is 12 bytes plus the length of the string, its null
			termination byte, and a trailing pad byte if the length of the
			chunk is otherwise odd.
		*/
		listChunkSize += 12 + zStringLength(name);
		listChunkSize += 12 + zStringLength(comment);
	}

	Tag list("LIST");
	writeTag(&list);
	writeU32(&listChunkSize);
	Tag adtl("adtl");
	writeTag(&adtl);

	for (int i=0; i<track->markerCount; i++)
	{
		uint32_t cuePointID = track->markers[i].id;

		const char *name = track->markers[i].name;
		uint32_t labelSize = 4 + zStringLength(name);
		Tag lablTag("labl");
		writeTag(&lablTag);
		writeU32(&labelSize);
		writeU32(&cuePointID);
		writeZString(name);

		const char *comment = track->markers[i].comment;
		uint32_t noteSize = 4 + zStringLength(comment);
		Tag noteTag("note");
		writeTag(&noteTag);
		writeU32(&noteSize);
		writeU32(&cuePointID);
		writeZString(comment);
	}

	return AF_SUCCEED;
}

bool WAVEFile::writeZString(const char *s)
{
	ssize_t lengthPlusNull = strlen(s) + 1;
	if (m_fh->write(s, lengthPlusNull) != lengthPlusNull)
		return false;
	if (lengthPlusNull & 1)
	{
		uint8_t zero = 0;
		if (!writeU8(&zero))
			return false;
	}
	return true;
}

size_t WAVEFile::zStringLength(const char *s)
{
	size_t lengthPlusNull = strlen(s) + 1;
	return lengthPlusNull + (lengthPlusNull & 1);
}

status WAVEFile::writeInit(AFfilesetup setup)
{
	if (initFromSetup(setup) == AF_FAIL)
		return AF_FAIL;

	initCompressionParams();

	uint32_t zero = 0;

	m_fh->seek(0, File::SeekFromBeginning);
	m_fh->write("RIFF", 4);
	m_fh->write(&zero, 4);
	m_fh->write("WAVE", 4);

	writeMiscellaneous();
	writeCues();
	writeFormat();
	writeFrameCount();
	writeData();

	return AF_SUCCEED;
}

bool WAVEFile::readUUID(UUID *u)
{
	return m_fh->read(u->data, 16) == 16;
}

bool WAVEFile::writeUUID(const UUID *u)
{
	return m_fh->write(u->data, 16) == 16;
}

void WAVEFile::initCompressionParams()
{
	Track *track = getTrack();
	if (track->f.compressionType == AF_COMPRESSION_IMA)
		initIMACompressionParams();
	else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
		initMSADPCMCompressionParams();
}

void WAVEFile::initIMACompressionParams()
{
	Track *track = getTrack();

	track->f.framesPerPacket = 505;
	track->f.bytesPerPacket = 256 * track->f.channelCount;

	AUpvlist pv = AUpvnew(1);
	AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = _AF_IMA_ADPCM_TYPE_WAVE;
	AUpvsetval(pv, 0, &l);

	track->f.compressionParams = pv;
}

void WAVEFile::initMSADPCMCompressionParams()
{
	const int16_t coefficients[7][2] =
	{
		{ 256, 0 },
		{ 512, -256 },
		{ 0, 0 },
		{ 192, 64 },
		{ 240, 0 },
		{ 460, -208 },
		{ 392, -232 }
	};
	memcpy(m_msadpcmCoefficients, coefficients, sizeof (int16_t) * 7 * 2);
	m_msadpcmNumCoefficients = 7;

	Track *track = getTrack();

	track->f.framesPerPacket = 500;
	track->f.bytesPerPacket = 256 * track->f.channelCount;

	AUpvlist pv = AUpvnew(2);
	AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
	AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
	long l = m_msadpcmNumCoefficients;
	AUpvsetval(pv, 0, &l);

	AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
	AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
	void *v = m_msadpcmCoefficients;
	AUpvsetval(pv, 1, &v);

	track->f.compressionParams = pv;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, 2003, 2010-2012, Michael Pruett <michael@68k.org>
	Copyright (C) 2002-2003, Davy Durham
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	WAVE.h

	This file contains structures and constants related to the RIFF
	WAVE sound file format.
*/

#ifndef WAVE_H
#define WAVE_H

#include "Compiler.h"
#include "FileHandle.h"
#include <stdint.h>

#define _AF_WAVE_NUM_INSTPARAMS 7
extern const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS];
#define _AF_WAVE_NUM_COMPTYPES 4
extern const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES];

struct UUID;

class WAVEFile : public _AFfilehandle
{
public:
	static bool recognize(File *fh);
	static AFfilesetup completeSetup(AFfilesetup);

	WAVEFile();

	status readInit(AFfilesetup) OVERRIDE;
	status writeInit(AFfilesetup) OVERRIDE;

	status update() OVERRIDE;

	bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;

private:
	AFfileoffset m_factOffset;	// start of fact (frame count) chunk
	AFfileoffset m_miscellaneousOffset;
	AFfileoffset m_markOffset;
	AFfileoffset m_dataSizeOffset;

	/*
		The index into the coefficient array is of type
		uint8_t, so we can safely limit msadpcmCoefficients to
		be 256 coefficient pairs.
	*/
	int m_msadpcmNumCoefficients;
	int16_t m_msadpcmCoefficients[256][2];

	status parseFrameCount(const Tag &type, uint32_t size);
	status parseFormat(const Tag &type, uint32_t size);
	status parseData(const Tag &type, uint32_t size);
	status parsePlayList(const Tag &type, uint32_t size);
	status parseCues(const Tag &type, uint32_t size);
	status parseADTLSubChunk(const Tag &type, uint32_t size);
	status parseINFOSubChunk(const Tag &type, uint32_t size);
	status parseList(const Tag &type, uint32_t size);
	status parseInstrument(const Tag &type, uint32_t size);

	status writeFormat();
	status writeFrameCount();
	status writeMiscellaneous();
	status writeCues();
	status writeData();

	bool readUUID(UUID *g);
	bool writeUUID(const UUID *g);

	bool writeZString(const char *);
	size_t zStringLength(const char *);

	void initCompressionParams();
	void initIMACompressionParams();
	void initMSADPCMCompressionParams();
};

#endif
/*
	Audio File Library
	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	aes.c

	This file contains routines for dealing with AES recording data.
*/

#include "config.h"

#include <string.h>
#include <assert.h>

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "util.h"

void afInitAESChannelData (AFfilesetup setup, int trackid)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	track->aesDataSet = true;
}

void afInitAESChannelDataTo (AFfilesetup setup, int trackid, int willBeData)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	track->aesDataSet = willBeData;
}

int afGetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (!track->hasAESData)
	{
		if (buf)
			memset(buf, 0, 24);
		return 0;
	}

	if (buf)
		memcpy(buf, track->aesData, 24);

	return 1;
}

void afSetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (!file->checkCanWrite())
		return;

	if (track->hasAESData)
	{
		memcpy(track->aesData, buf, 24);
	}
	else
	{
		_af_error(AF_BAD_NOAESDATA,
			"unable to store AES channel status data for track %d",
			trackid);
	}
}
/*
	Audio File Library
	Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	af_vfs.cpp

	Virtual file operations for the Audio File Library.
*/

#include "config.h"

#include "afinternal.h"
#include "af_vfs.h"

#include <stdlib.h>

AFvirtualfile *af_virtual_file_new()
{
	return (AFvirtualfile *) calloc(sizeof (AFvirtualfile), 1);
}

void af_virtual_file_destroy(AFvirtualfile *vfile)
{
	vfile->destroy(vfile);

	free(vfile);
}
/*
	Audio File Library
	Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	af_vfs.h

	Virtual file operations for the Audio File Library.
*/

#ifndef AUDIOFILE_VFS_H
#define AUDIOFILE_VFS_H

#include <audiofile.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif

struct _AFvirtualfile
{
	ssize_t (*read) (AFvirtualfile *vfile, void *data, size_t nbytes);
	AFfileoffset (*length) (AFvirtualfile *vfile);
	ssize_t (*write) (AFvirtualfile *vfile, const void *data, size_t nbytes);
	void (*destroy) (AFvirtualfile *vfile);
	AFfileoffset (*seek) (AFvirtualfile *vfile, AFfileoffset offset, int is_relative);
	AFfileoffset (*tell) (AFvirtualfile *vfile);

	void *closure;
};

AFAPI AFvirtualfile *af_virtual_file_new (void);
AFAPI void af_virtual_file_destroy (AFvirtualfile *vfile);

#undef AFAPI

#ifdef __cplusplus
}
#endif

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	afinternal.h

	This file defines the internal structures for the Audio File Library.
*/

#ifndef AFINTERNAL_H
#define AFINTERNAL_H

#include <sys/types.h>
#include "audiofile.h"
#include "error.h"

enum status
{
	AF_SUCCEED = 0,
	AF_FAIL = -1
};

union AFPVu
{
	long	l;
	double	d;
	void	*v;
};

struct InstParamInfo
{
	int id;
	int type;
	const char *name;
	AFPVu defaultValue;
};

struct Loop
{
	int	id;
	int	mode;	/* AF_LOOP_MODE_... */
	int	count;	/* how many times the loop is played */
	int	beginMarker, endMarker;
	int	trackid;
};

struct LoopSetup
{
	int	id;
};

struct Miscellaneous
{
	int id;
	int type;
	int size;

	void *buffer;

	int position;	// offset within the miscellaneous chunk
};

struct MiscellaneousSetup
{
	int	id;
	int	type;
	int	size;
};

struct TrackSetup;

class File;
struct Track;

enum
{
	_AF_VALID_FILEHANDLE = 38212,
	_AF_VALID_FILESETUP = 38213
};

enum
{
	_AF_READ_ACCESS = 1,
	_AF_WRITE_ACCESS = 2
};

// The following are tokens for compression parameters in PV lists.
enum
{
	_AF_MS_ADPCM_NUM_COEFFICIENTS = 800,	/* type: long */
	_AF_MS_ADPCM_COEFFICIENTS = 801,		/* type: array of int16_t[2] */
	_AF_IMA_ADPCM_TYPE = 810,
	_AF_IMA_ADPCM_TYPE_WAVE = 1,
	_AF_IMA_ADPCM_TYPE_QT = 2,
	_AF_CODEC_DATA = 900,		// type: pointer
	_AF_CODEC_DATA_SIZE = 901	// type: long
};

/* NeXT/Sun sampling rate */
#define _AF_SRATE_CODEC (8012.8210513)

#endif
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ALACAudioTypes.h
*/

#ifndef ALACAUDIOTYPES_H
#define ALACAUDIOTYPES_H

#if PRAGMA_ONCE
#pragma once
#endif

#include "config.h"

#ifdef __cplusplus
extern "C" {
#endif

#if PRAGMA_STRUCT_ALIGN
    #pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
    #pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
    #pragma pack(2)
#endif

#include <stdint.h>

#ifdef WORDS_BIGENDIAN
#define TARGET_RT_BIG_ENDIAN 1
#endif

#define kChannelAtomSize 12
    
enum 
{
    kALAC_UnimplementedError   = -4,
    kALAC_FileNotFoundError    = -43,
    kALAC_ParamError           = -50,
    kALAC_MemFullError         = -108
};

enum
{
    kALACFormatAppleLossless = 'alac',
    kALACFormatLinearPCM = 'lpcm'
};

enum
{
    kALACMaxChannels	= 8,
    kALACMaxEscapeHeaderBytes = 8,
    kALACMaxSearches	= 16,
    kALACMaxCoefs		= 16,
    kALACDefaultFramesPerPacket = 4096
};

typedef uint32_t ALACChannelLayoutTag;

enum
{
    kALACFormatFlagIsFloat                     = (1 << 0),     // 0x1
    kALACFormatFlagIsBigEndian                 = (1 << 1),     // 0x2
    kALACFormatFlagIsSignedInteger             = (1 << 2),     // 0x4
    kALACFormatFlagIsPacked                    = (1 << 3),     // 0x8
    kALACFormatFlagIsAlignedHigh               = (1 << 4),     // 0x10
};

enum
{
#if TARGET_RT_BIG_ENDIAN
    kALACFormatFlagsNativeEndian       = kALACFormatFlagIsBigEndian
#else
    kALACFormatFlagsNativeEndian       = 0
#endif
};

// this is required to be an IEEE 64bit float
typedef double alac_float64_t;

// These are the Channel Layout Tags used in the Channel Layout Info portion of the ALAC magic cookie
enum
{
    kALACChannelLayoutTag_Mono          = (100<<16) | 1,    // C
    kALACChannelLayoutTag_Stereo        = (101<<16) | 2,	// L R
    kALACChannelLayoutTag_MPEG_3_0_B    = (113<<16) | 3,	// C L R
    kALACChannelLayoutTag_MPEG_4_0_B    = (116<<16) | 4,	// C L R Cs
    kALACChannelLayoutTag_MPEG_5_0_D    = (120<<16) | 5,    // C L R Ls Rs
    kALACChannelLayoutTag_MPEG_5_1_D    = (124<<16) | 6,	// C L R Ls Rs LFE
    kALACChannelLayoutTag_AAC_6_1       = (142<<16) | 7,	// C L R Ls Rs Cs LFE
    kALACChannelLayoutTag_MPEG_7_1_B	= (127<<16) | 8     // C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
};

// ALAC currently only utilizes these channels layouts. There is a one for one correspondance between a
// given number of channels and one of these layout tags
static const ALACChannelLayoutTag	ALACChannelLayoutTags[kALACMaxChannels] =
{
    kALACChannelLayoutTag_Mono,         // C
    kALACChannelLayoutTag_Stereo,		// L R
    kALACChannelLayoutTag_MPEG_3_0_B,	// C L R
    kALACChannelLayoutTag_MPEG_4_0_B,	// C L R Cs
    kALACChannelLayoutTag_MPEG_5_0_D,	// C L R Ls Rs
    kALACChannelLayoutTag_MPEG_5_1_D,	// C L R Ls Rs LFE
    kALACChannelLayoutTag_AAC_6_1,		// C L R Ls Rs Cs LFE
    kALACChannelLayoutTag_MPEG_7_1_B	// C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
};

// AudioChannelLayout from CoreAudioTypes.h. We never need the AudioChannelDescription so we remove it
struct ALACAudioChannelLayout
{
    ALACChannelLayoutTag          mChannelLayoutTag;
    uint32_t                      mChannelBitmap;
    uint32_t                      mNumberChannelDescriptions;
};
typedef struct ALACAudioChannelLayout ALACAudioChannelLayout;

struct AudioFormatDescription
{
    alac_float64_t mSampleRate;
    uint32_t  mFormatID;
    uint32_t  mFormatFlags;
    uint32_t  mBytesPerPacket;
    uint32_t  mFramesPerPacket;
    uint32_t  mBytesPerFrame;
    uint32_t  mChannelsPerFrame;
    uint32_t  mBitsPerChannel;
    uint32_t  mReserved;
};
typedef struct AudioFormatDescription  AudioFormatDescription;

/* Lossless Definitions */

enum
{
	kALACCodecFormat		= 'alac',
	kALACVersion			= 0,
	kALACCompatibleVersion	= kALACVersion,
	kALACDefaultFrameSize	= 4096
};

// note: this struct is wrapped in an 'alac' atom in the sample description extension area
// note: in QT movies, it will be further wrapped in a 'wave' atom surrounded by 'frma' and 'term' atoms
typedef struct ALACSpecificConfig
{
	uint32_t				frameLength;
	uint8_t					compatibleVersion;
	uint8_t					bitDepth;							// max 32
	uint8_t					pb;									// 0 <= pb <= 255
	uint8_t					mb;
	uint8_t					kb;
	uint8_t					numChannels;
	uint16_t				maxRun;
	uint32_t				maxFrameBytes;
	uint32_t				avgBitRate;
	uint32_t				sampleRate;

} ALACSpecificConfig;


// The AudioChannelLayout atom type is not exposed yet so define it here
enum
{
	AudioChannelLayoutAID = 'chan'
};

#if PRAGMA_STRUCT_ALIGN
    #pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
    #pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
    #pragma pack()
#endif

#ifdef __cplusplus
}
#endif

#endif	/* ALACAUDIOTYPES_H */
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*=============================================================================
    File:		ALACBitUtilities.c

	$NoKeywords: $
=============================================================================*/

#include <stdio.h>
#include "ALACBitUtilities.h"

// BitBufferInit
//
void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
{
	bits->cur		= buffer;
	bits->end		= bits->cur + byteSize;
	bits->bitIndex	= 0;
	bits->byteSize	= byteSize;
}

// BitBufferRead
//
uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
{
	uint32_t		returnBits;
	
	//Assert( numBits <= 16 );

	returnBits = ((uint32_t)bits->cur[0] << 16) | ((uint32_t)bits->cur[1] << 8) | ((uint32_t)bits->cur[2]);
	returnBits = returnBits << bits->bitIndex;
	returnBits &= 0x00FFFFFF;
	
	bits->bitIndex += numBits;
	
	returnBits = returnBits >> (24 - numBits);
	
	bits->cur		+= (bits->bitIndex >> 3);
	bits->bitIndex	&= 7;
	
	//Assert( bits->cur <= bits->end );
	
	return returnBits;
}

// BitBufferReadSmall
//
// Reads up to 8 bits
uint8_t BitBufferReadSmall( BitBuffer * bits, uint8_t numBits )
{
	uint16_t		returnBits;
	
	//Assert( numBits <= 8 );
	
	returnBits = (bits->cur[0] << 8) | bits->cur[1];
	returnBits = returnBits << bits->bitIndex;
	
	bits->bitIndex += numBits;
	
	returnBits = returnBits >> (16 - numBits);
	
	bits->cur		+= (bits->bitIndex >> 3);
	bits->bitIndex	&= 7;
	
	//Assert( bits->cur <= bits->end );
	
	return (uint8_t)returnBits;
}

// BitBufferReadOne
//
// Reads one byte
uint8_t BitBufferReadOne( BitBuffer * bits )
{
	uint8_t		returnBits;

	returnBits = (bits->cur[0] >> (7 - bits->bitIndex)) & 1;

	bits->bitIndex++;
	
	bits->cur		+= (bits->bitIndex >> 3);
	bits->bitIndex	&= 7;
	
	//Assert( bits->cur <= bits->end );
	
	return returnBits;
}

// BitBufferPeek
//
uint32_t BitBufferPeek( BitBuffer * bits, uint8_t numBits )
{
	return ((((((uint32_t) bits->cur[0] << 16) | ((uint32_t) bits->cur[1] << 8) |
			((uint32_t) bits->cur[2])) << bits->bitIndex) & 0x00FFFFFF) >> (24 - numBits));
}

// BitBufferPeekOne
//
uint32_t BitBufferPeekOne( BitBuffer * bits )
{
	return ((bits->cur[0] >> (7 - bits->bitIndex)) & 1);
}

// BitBufferUnpackBERSize
//
uint32_t BitBufferUnpackBERSize( BitBuffer * bits )
{
	uint32_t		size;
	uint8_t		tmp;
	
	for ( size = 0, tmp = 0x80u; tmp &= 0x80u; size = (size << 7u) | (tmp & 0x7fu) )
		tmp = (uint8_t) BitBufferReadSmall( bits, 8 );
	
	return size;
}

// BitBufferGetPosition
//
uint32_t BitBufferGetPosition( BitBuffer * bits )
{
	uint8_t *		begin;
	
	begin = bits->end - bits->byteSize;
	
	return ((uint32_t)(bits->cur - begin) * 8) + bits->bitIndex;
}

// BitBufferByteAlign
//
void BitBufferByteAlign( BitBuffer * bits, int32_t addZeros )
{
	// align bit buffer to next byte boundary, writing zeros if requested
	if ( bits->bitIndex == 0 )
		return;

	if ( addZeros )
		BitBufferWrite( bits, 0, 8 - bits->bitIndex );
	else	
		BitBufferAdvance( bits, 8 - bits->bitIndex );	
}

// BitBufferAdvance
//
void BitBufferAdvance( BitBuffer * bits, uint32_t numBits )
{
	if ( numBits )
	{
		bits->bitIndex += numBits;
		bits->cur += (bits->bitIndex >> 3);
		bits->bitIndex &= 7;
	}
}

// BitBufferRewind
//
void BitBufferRewind( BitBuffer * bits, uint32_t numBits )
{
	uint32_t	numBytes;
	
	if ( numBits == 0 )
		return;
	
	if ( bits->bitIndex >= numBits )
	{
		bits->bitIndex -= numBits;
		return;
	}
	
	numBits -= bits->bitIndex;
	bits->bitIndex = 0;

	numBytes	= numBits / 8;
	numBits		= numBits % 8;
	
	bits->cur -= numBytes;
	
	if ( numBits > 0 )
	{
		bits->bitIndex = 8 - numBits;
		bits->cur--;
	}
	
	if ( bits->cur < (bits->end - bits->byteSize) )
	{
		//DebugCMsg("BitBufferRewind: Rewound too far.");

		bits->cur		= (bits->end - bits->byteSize);
		bits->bitIndex	= 0;
	}
}

// BitBufferWrite
//
void BitBufferWrite( BitBuffer * bits, uint32_t bitValues, uint32_t numBits )
{
	uint32_t				invBitIndex;
	
	RequireAction( bits != nil, return; );
	RequireActionSilent( numBits > 0, return; );

	invBitIndex = 8 - bits->bitIndex;

	while ( numBits > 0 )
	{
		uint32_t		tmp;
		uint8_t		shift;
		uint8_t		mask;
		uint32_t		curNum;

		curNum = MIN( invBitIndex, numBits );

		tmp = bitValues >> (numBits - curNum);

		shift  = (uint8_t)(invBitIndex - curNum);
		mask   = 0xffu >> (8 - curNum);		// must be done in two steps to avoid compiler sequencing ambiguity
		mask <<= shift;

		bits->cur[0] = (bits->cur[0] & ~mask) | (((uint8_t) tmp << shift)  & mask);
		numBits -= curNum;

		// increment to next byte if need be
		invBitIndex -= curNum;
		if ( invBitIndex == 0 )
		{
			invBitIndex = 8;
			bits->cur++;
		}
	}

	bits->bitIndex = 8 - invBitIndex;
}

void	BitBufferReset( BitBuffer * bits )
//void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
{
	bits->cur		= bits->end - bits->byteSize;
    bits->bitIndex	= 0;
}

#if PRAGMA_MARK
#pragma mark -
#endif
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*=============================================================================
    File:		ALACBitUtilities.h
	
	$NoKeywords: $
=============================================================================*/

#ifndef __ALACBITUTILITIES_H
#define __ALACBITUTILITIES_H

#include <stdint.h>

#ifndef MIN
#define MIN(x, y) 			( (x)<(y) ?(x) :(y) )
#endif //MIN
#ifndef MAX
#define MAX(x, y) 			( (x)>(y) ?(x): (y) )
#endif //MAX

#ifndef nil
#define nil NULL
#endif

#define RequireAction(condition, action)			if (!(condition)) { action }
#define RequireActionSilent(condition, action)			if (!(condition)) { action }
#define RequireNoErr(condition, action)			if ((condition)) { action }

#ifdef __cplusplus
extern "C" {
#endif

enum
{
    ALAC_noErr = 0
};
    

typedef enum
{
    
    ID_SCE = 0,						/* Single Channel Element   */
    ID_CPE = 1,						/* Channel Pair Element     */
    ID_CCE = 2,						/* Coupling Channel Element */
    ID_LFE = 3,						/* LFE Channel Element      */
    ID_DSE = 4,						/* not yet supported        */
    ID_PCE = 5,
    ID_FIL = 6,
    ID_END = 7
} ELEMENT_TYPE;

// types
typedef struct BitBuffer
{
	uint8_t *		cur;
	uint8_t *		end;
	uint32_t		bitIndex;
	uint32_t		byteSize;
	
} BitBuffer;

/*
	BitBuffer routines
	- these routines take a fixed size buffer and read/write to it
	- bounds checking must be done by the client
*/
void	BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize );
uint32_t	BitBufferRead( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
uint8_t	BitBufferReadSmall( BitBuffer * bits, uint8_t numBits );
uint8_t	BitBufferReadOne( BitBuffer * bits );
uint32_t	BitBufferPeek( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
uint32_t	BitBufferPeekOne( BitBuffer * bits );
uint32_t	BitBufferUnpackBERSize( BitBuffer * bits );
uint32_t	BitBufferGetPosition( BitBuffer * bits );
void	BitBufferByteAlign( BitBuffer * bits, int32_t addZeros );
void	BitBufferAdvance( BitBuffer * bits, uint32_t numBits );
void	BitBufferRewind( BitBuffer * bits, uint32_t numBits );
void	BitBufferWrite( BitBuffer * bits, uint32_t value, uint32_t numBits );
void	BitBufferReset( BitBuffer * bits);


#ifdef __cplusplus
}
#endif

#endif	/* __BITUTILITIES_H */
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ALACDecoder.cpp
*/

#include <stdlib.h>
#include <string.h>

#include "ALACDecoder.h"

#include "dplib.h"
#include "aglib.h"
#include "matrixlib.h"

#include "ALACBitUtilities.h"
#include "EndianPortable.h"

// constants/data
const uint32_t kMaxBitDepth = 32;			// max allowed bit depth is 32


// prototypes
static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride );
static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride );
static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride );

/*
	Constructor
*/
ALACDecoder::ALACDecoder() :
	mMixBufferU( nil ),
	mMixBufferV( nil ),
	mPredictor( nil ),
	mShiftBuffer( nil )
{
	memset( &mConfig, 0, sizeof(mConfig) );
}

/*
	Destructor
*/
ALACDecoder::~ALACDecoder()
{
	// delete the matrix mixing buffers
	if ( mMixBufferU )
    {
		free(mMixBufferU);
        mMixBufferU = NULL;
    }
	if ( mMixBufferV )
    {
		free(mMixBufferV);
        mMixBufferV = NULL;
    }
	
	// delete the dynamic predictor's "corrector" buffer
	// - note: mShiftBuffer shares memory with this buffer
	if ( mPredictor )
    {
		free(mPredictor);
        mPredictor = NULL;
    }
}

/*
	Init()
	- initialize the decoder with the given configuration
*/
int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize )
{
	int32_t		status = ALAC_noErr;
    ALACSpecificConfig theConfig;
    uint8_t * theActualCookie = (uint8_t *)inMagicCookie;
    uint32_t theCookieBytesRemaining = inMagicCookieSize;

    // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders.
    // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating 
    // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the
    // ALACSpecificConfig. 
    // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie'
    
    // skip format ('frma') atom if present
    if (theActualCookie[4] == 'f' && theActualCookie[5] == 'r' && theActualCookie[6] == 'm' && theActualCookie[7] == 'a')
    {
        theActualCookie += 12;
        theCookieBytesRemaining -= 12;
    }
    
    // skip 'alac' atom header if present
    if (theActualCookie[4] == 'a' && theActualCookie[5] == 'l' && theActualCookie[6] == 'a' && theActualCookie[7] == 'c')
    {
        theActualCookie += 12;
        theCookieBytesRemaining -= 12;
    }

    // read the ALACSpecificConfig
    if (theCookieBytesRemaining >= sizeof(ALACSpecificConfig))
    {
        memcpy(&theConfig, theActualCookie, sizeof(ALACSpecificConfig));

        theConfig.frameLength = Swap32BtoN(theConfig.frameLength);
        theConfig.maxRun = Swap16BtoN(theConfig.maxRun);
        theConfig.maxFrameBytes = Swap32BtoN(theConfig.maxFrameBytes);
        theConfig.avgBitRate = Swap32BtoN(theConfig.avgBitRate);
        theConfig.sampleRate = Swap32BtoN(theConfig.sampleRate);

        mConfig = theConfig;
        
        RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );

        // allocate mix buffers
        mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
        mMixBufferV = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );

        // allocate dynamic predictor buffer
        mPredictor = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );

        // "shift off" buffer shares memory with predictor buffer
        mShiftBuffer = (uint16_t *) mPredictor;
        
        RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && (mPredictor != nil),
                        status = kALAC_MemFullError; goto Exit; );
     }
    else
    {
        status = kALAC_ParamError;
    }

    // skip to Channel Layout Info
    // theActualCookie += sizeof(ALACSpecificConfig);
    
    // Currently, the Channel Layout Info portion of the magic cookie (as defined in the 
    // ALACMagicCookieDescription.txt document) is unused by the decoder. 
    
Exit:
	return status;
}

/*
	Decode()
	- the decoded samples are interleaved into the output buffer in the order they arrive in
	  the bitstream
*/
int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples )
{
	BitBuffer			shiftBits;
	uint32_t            bits1, bits2;
	uint8_t				tag;
	uint8_t				elementInstanceTag;
	AGParamRec			agParams;
	uint32_t				channelIndex;
	int16_t				coefsU[32];		// max possible size is 32 although NUMCOEPAIRS is the current limit
	int16_t				coefsV[32];
	uint8_t				numU, numV;
	uint8_t				mixBits;
	int8_t				mixRes;
	uint16_t			unusedHeader;
	uint8_t				escapeFlag;
	uint32_t			chanBits;
	uint8_t				bytesShifted;
	uint32_t			shift;
	uint8_t				modeU, modeV;
	uint32_t			denShiftU, denShiftV;
	uint16_t			pbFactorU, pbFactorV;
	uint16_t			pb;
	int16_t *			samples;
	int16_t *			out16;
	uint8_t *			out20;
	uint8_t *			out24;
	int32_t *			out32;
	uint8_t				headerByte;
	uint8_t				partialFrame;
	uint32_t			extraBits;
	int32_t				val;
	uint32_t			i, j;
	int32_t             status;
	
	RequireAction( (bits != nil) && (sampleBuffer != nil) && (outNumSamples != nil), return kALAC_ParamError; );
	RequireAction( numChannels > 0, return kALAC_ParamError; );

	mActiveElements = 0;
	channelIndex	= 0;
	
	samples = (int16_t *) sampleBuffer;

	status = ALAC_noErr;
	*outNumSamples = numSamples;

	while ( status == ALAC_noErr )
	{
		// bail if we ran off the end of the buffer
    	RequireAction( bits->cur < bits->end, status = kALAC_ParamError; goto Exit; );

		// copy global decode params for this element
		pb = mConfig.pb;

		// read element tag
		tag = BitBufferReadSmall( bits, 3 );
		switch ( tag )
		{
			case ID_SCE:
			case ID_LFE:
			{
				// mono/LFE channel
				elementInstanceTag = BitBufferReadSmall( bits, 4 );
				mActiveElements |= (1u << elementInstanceTag);

				// read the 12 unused header bits
				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );

				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
				headerByte = (uint8_t) BitBufferRead( bits, 4 );
				
				partialFrame = headerByte >> 3;
				
				bytesShifted = (headerByte >> 1) & 0x3u;
				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );

				shift = bytesShifted * 8;

				escapeFlag = headerByte & 0x1;

				chanBits = mConfig.bitDepth - (bytesShifted * 8);
				
				// check for partial frame to override requested numSamples
				if ( partialFrame != 0 )
				{
					numSamples  = BitBufferRead( bits, 16 ) << 16;
					numSamples |= BitBufferRead( bits, 16 );
				}

				if ( escapeFlag == 0 )
				{
					// compressed frame, read rest of parameters
					mixBits	= (uint8_t) BitBufferRead( bits, 8 );
					mixRes	= (int8_t) BitBufferRead( bits, 8 );
					//Assert( (mixBits == 0) && (mixRes == 0) );		// no mixing for mono

					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					modeU		= headerByte >> 4;
					denShiftU	= headerByte & 0xfu;
					
					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					pbFactorU	= headerByte >> 5;
					numU		= headerByte & 0x1fu;

					for ( i = 0; i < numU; i++ )
						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
					
					// if shift active, skip the the shift buffer but remember where it starts
					if ( bytesShifted != 0 )
					{
						shiftBits = *bits;
						BitBufferAdvance( bits, (bytesShifted * 8) * numSamples ); 
					}

					// decompress
					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
					RequireNoErr( status, goto Exit; );

					if ( modeU == 0 )
					{
						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
					}
					else
					{
						// the special "numActive == 31" mode can be done in-place
						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
					}
				}
				else
				{
					//Assert( bytesShifted == 0 );

					// uncompressed frame, copy data into the mix buffer to use common output code
					shift = 32 - chanBits;
					if ( chanBits <= 16 )
					{
						for ( i = 0; i < numSamples; i++ )
						{
							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
							val = (val << shift) >> shift;
							mMixBufferU[i] = val;
						}
					}
					else
					{
						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
						extraBits = chanBits - 16;
						for ( i = 0; i < numSamples; i++ )
						{
							val = (int32_t) BitBufferRead( bits, 16 );
							val = (val << 16) >> shift;
							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t) extraBits );
						}
					}

					mixBits = mixRes = 0;
					bits1 = chanBits * numSamples;
					bytesShifted = 0;
				}

				// now read the shifted values into the shift buffer
				if ( bytesShifted != 0 )
				{
					shift = bytesShifted * 8;
					//Assert( shift <= 16 );

					for ( i = 0; i < numSamples; i++ )
						mShiftBuffer[i] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
				}

				// convert 32-bit integers into output buffer
				switch ( mConfig.bitDepth )
				{
					case 16:
						out16 = &((int16_t *)sampleBuffer)[channelIndex];
						for ( i = 0, j = 0; i < numSamples; i++, j += numChannels )
							out16[j] = (int16_t) mMixBufferU[i];
						break;
					case 20:
						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
						copyPredictorTo20( mMixBufferU, out20, numChannels, numSamples );
						break;
					case 24:
						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
						if ( bytesShifted != 0 )
							copyPredictorTo24Shift( mMixBufferU, mShiftBuffer, out24, numChannels, numSamples, bytesShifted );
						else
							copyPredictorTo24( mMixBufferU, out24, numChannels, numSamples );							
						break;
					case 32:
						out32 = &((int32_t *)sampleBuffer)[channelIndex];
						if ( bytesShifted != 0 )
							copyPredictorTo32Shift( mMixBufferU, mShiftBuffer, out32, numChannels, numSamples, bytesShifted );
						else
							copyPredictorTo32( mMixBufferU, out32, numChannels, numSamples);
						break;
				}

				channelIndex += 1;
				*outNumSamples = numSamples;
				break;
			}

			case ID_CPE:
			{
				// if decoding this pair would take us over the max channels limit, bail
				if ( (channelIndex + 2) > numChannels )
					goto NoMoreChannels;

				// stereo channel pair
				elementInstanceTag = BitBufferReadSmall( bits, 4 );
				mActiveElements |= (1u << elementInstanceTag);

				// read the 12 unused header bits
				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );

				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
				headerByte = (uint8_t) BitBufferRead( bits, 4 );
				
				partialFrame = headerByte >> 3;
				
				bytesShifted = (headerByte >> 1) & 0x3u;
				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );

				shift = bytesShifted * 8;

				escapeFlag = headerByte & 0x1;

				chanBits = mConfig.bitDepth - (bytesShifted * 8) + 1;
				
				// check for partial frame length to override requested numSamples
				if ( partialFrame != 0 )
				{
					numSamples  = BitBufferRead( bits, 16 ) << 16;
					numSamples |= BitBufferRead( bits, 16 );
				}

				if ( escapeFlag == 0 )
				{
					// compressed frame, read rest of parameters
					mixBits		= (uint8_t) BitBufferRead( bits, 8 );
					mixRes		= (int8_t) BitBufferRead( bits, 8 );

					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					modeU		= headerByte >> 4;
					denShiftU	= headerByte & 0xfu;
					
					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					pbFactorU	= headerByte >> 5;
					numU		= headerByte & 0x1fu;
					for ( i = 0; i < numU; i++ )
						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );

					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					modeV		= headerByte >> 4;
					denShiftV	= headerByte & 0xfu;
					
					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
					pbFactorV	= headerByte >> 5;
					numV		= headerByte & 0x1fu;
					for ( i = 0; i < numV; i++ )
						coefsV[i] = (int16_t) BitBufferRead( bits, 16 );

					// if shift active, skip the interleaved shifted values but remember where they start
					if ( bytesShifted != 0 )
					{
						shiftBits = *bits;
						BitBufferAdvance( bits, (bytesShifted * 8) * 2 * numSamples );
					}

					// decompress and run predictor for "left" channel
					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
					RequireNoErr( status, goto Exit; );

					if ( modeU == 0 )
					{
						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
					}
					else
					{
						// the special "numActive == 31" mode can be done in-place
						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
					}

					// decompress and run predictor for "right" channel
					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorV) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits2 );
					RequireNoErr( status, goto Exit; );

					if ( modeV == 0 )
					{
						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
					}
					else
					{
						// the special "numActive == 31" mode can be done in-place
						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
					}
				}
				else
				{
					//Assert( bytesShifted == 0 );

					// uncompressed frame, copy data into the mix buffers to use common output code
					chanBits = mConfig.bitDepth;
					shift = 32 - chanBits;
					if ( chanBits <= 16 )
					{
						for ( i = 0; i < numSamples; i++ )
						{
							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
							val = (val << shift) >> shift;
							mMixBufferU[i] = val;

							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
							val = (val << shift) >> shift;
							mMixBufferV[i] = val;
						}
					}
					else
					{
						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
						extraBits = chanBits - 16;
						for ( i = 0; i < numSamples; i++ )
						{
							val = (int32_t) BitBufferRead( bits, 16 );
							val = (val << 16) >> shift;
							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t)extraBits );

							val = (int32_t) BitBufferRead( bits, 16 );
							val = (val << 16) >> shift;
							mMixBufferV[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
						}
					}

					bits1 = chanBits * numSamples;
					bits2 = chanBits * numSamples;
					mixBits = mixRes = 0;
					bytesShifted = 0;
				}

				// now read the shifted values into the shift buffer
				if ( bytesShifted != 0 )
				{
					shift = bytesShifted * 8;
					//Assert( shift <= 16 );

					for ( i = 0; i < (numSamples * 2); i += 2 )
					{
						mShiftBuffer[i + 0] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
						mShiftBuffer[i + 1] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
					}
				}

				// un-mix the data and convert to output format
				// - note that mixRes = 0 means just interleave so we use that path for uncompressed frames
				switch ( mConfig.bitDepth )
				{
					case 16:
						out16 = &((int16_t *)sampleBuffer)[channelIndex];
						unmix16( mMixBufferU, mMixBufferV, out16, numChannels, numSamples, mixBits, mixRes );
						break;
					case 20:
						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
						unmix20( mMixBufferU, mMixBufferV, out20, numChannels, numSamples, mixBits, mixRes );
						break;
					case 24:
						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
						unmix24( mMixBufferU, mMixBufferV, out24, numChannels, numSamples,
									mixBits, mixRes, mShiftBuffer, bytesShifted );
						break;
					case 32:
						out32 = &((int32_t *)sampleBuffer)[channelIndex];
						unmix32( mMixBufferU, mMixBufferV, out32, numChannels, numSamples,
									mixBits, mixRes, mShiftBuffer, bytesShifted );
						break;
				}

				channelIndex += 2;
				*outNumSamples = numSamples;
				break;
			}

			case ID_CCE:
			case ID_PCE:
			{
				// unsupported element, bail
				//AssertNoErr( tag );
				status = kALAC_ParamError;
				break;
			}

			case ID_DSE:
			{
				// data stream element -- parse but ignore
				status = this->DataStreamElement( bits );
				break;
			}
			
			case ID_FIL:
			{
				// fill element -- parse but ignore
				status = this->FillElement( bits );
				break;
			}

			case ID_END:
			{
				// frame end, all done so byte align the frame and check for overruns
				BitBufferByteAlign( bits, false );
				//Assert( bits->cur == bits->end );
				goto Exit;
			}
		}

#if ! DEBUG
		// if we've decoded all of our channels, bail (but not in debug b/c we want to know if we're seeing bad bits)
		// - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits
		if ( channelIndex >= numChannels )
			break;
#endif
	}

NoMoreChannels:

	// if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros
	for ( ; channelIndex < numChannels; channelIndex++ )
	{
		switch ( mConfig.bitDepth )
		{
			case 16:
			{
				int16_t *	fill16 = &((int16_t *)sampleBuffer)[channelIndex];
				Zero16( fill16, numSamples, numChannels );
				break;
			}
			case 24:
			{
				uint8_t *	fill24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
				Zero24( fill24, numSamples, numChannels );
				break;
			}
			case 32:
			{
				int32_t *	fill32 = &((int32_t *)sampleBuffer)[channelIndex];
				Zero32( fill32, numSamples, numChannels );
				break;
			}
		}
	}

Exit:
	return status;
}

#if PRAGMA_MARK
#pragma mark -
#endif

/*
	FillElement()
	- they're just filler so we don't need 'em
*/
int32_t ALACDecoder::FillElement( BitBuffer * bits )
{
	int16_t		count;
	
	// 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15
	// - plus this weird -1 thing I still don't fully understand
	count = BitBufferReadSmall( bits, 4 );
	if ( count == 15 )
		count += (int16_t) BitBufferReadSmall( bits, 8 ) - 1;

	BitBufferAdvance( bits, count * 8 );

	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );

	return ALAC_noErr;	
}

/*
	DataStreamElement()
	- we don't care about data stream elements so just skip them
*/
int32_t ALACDecoder::DataStreamElement( BitBuffer * bits )
{
	uint8_t		element_instance_tag;
	int32_t		data_byte_align_flag;
	uint16_t		count;
	
	// the tag associates this data stream element with a given audio element
	element_instance_tag = BitBufferReadSmall( bits, 4 );
	
	data_byte_align_flag = BitBufferReadOne( bits );

	// 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255
	count = BitBufferReadSmall( bits, 8 );
	if ( count == 255 )
		count += BitBufferReadSmall( bits, 8 );

	// the align flag means the bitstream should be byte-aligned before reading the following data bytes
	if ( data_byte_align_flag )
		BitBufferByteAlign( bits, false );

	// skip the data bytes
	BitBufferAdvance( bits, count * 8 );

	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );

	return ALAC_noErr;
}

/*
	ZeroN()
	- helper routines to clear out output channel buffers when decoding fewer channels than requested
*/
static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride )
{
	if ( stride == 1 )
	{
		memset( buffer, 0, numItems * sizeof(int16_t) );
	}
	else
	{
		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
			buffer[index] = 0;
	}
}

static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride )
{
	if ( stride == 1 )
	{
		memset( buffer, 0, numItems * 3 );
	}
	else
	{
		for ( uint32_t index = 0; index < (numItems * stride * 3); index += (stride * 3) )
		{
			buffer[index + 0] = 0;
			buffer[index + 1] = 0;
			buffer[index + 2] = 0;
		}
	}
}

static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride )
{
	if ( stride == 1 )
	{
		memset( buffer, 0, numItems * sizeof(int32_t) );
	}
	else
	{
		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
			buffer[index] = 0;
	}
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ALACDecoder.h
*/

#ifndef _ALACDECODER_H
#define _ALACDECODER_H

#if PRAGMA_ONCE
#pragma once
#endif

#include <stdint.h>

#include "ALACAudioTypes.h"

struct BitBuffer;

class ALACDecoder
{
	public:
		ALACDecoder();
		~ALACDecoder();

		int32_t	Init( void * inMagicCookie, uint32_t inMagicCookieSize );
		int32_t	Decode( struct BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples );

	public:
		// decoding parameters (public for use in the analyzer)
		ALACSpecificConfig		mConfig;

	protected:
		int32_t	FillElement( struct BitBuffer * bits );
		int32_t	DataStreamElement( struct BitBuffer * bits );

		uint16_t					mActiveElements;

		// decoding buffers
		int32_t *				mMixBufferU;
		int32_t *				mMixBufferV;
		int32_t *				mPredictor;
		uint16_t *				mShiftBuffer;	// note: this points to mPredictor's memory but different
												//		 variable for clarity and type difference
};

#endif	/* _ALACDECODER_H */
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ALACEncoder.cpp
*/

// build stuff
#define VERBOSE_DEBUG		0

// headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ALACEncoder.h"

#include "aglib.h"
#include "dplib.h"
#include "matrixlib.h"

#include "ALACBitUtilities.h"
#include "ALACAudioTypes.h"
#include "EndianPortable.h"

// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when
// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type
typedef int16_t (*SearchCoefs)[kALACMaxCoefs];

// defines/constants
const uint32_t kALACEncoderMagic	= 'dpge';
const uint32_t kMaxSampleSize		= 32;			// max allowed bit width is 32
const uint32_t kDefaultMixBits	= 2;
const uint32_t kDefaultMixRes		= 0;
const uint32_t kMaxRes			= 4;
const uint32_t kDefaultNumUV		= 8;
const uint32_t kMinUV				= 4;
const uint32_t kMaxUV				= 8;

// static functions
#if VERBOSE_DEBUG
static void AddFiller( BitBuffer * bits, int32_t numBytes );
#endif


/*
	Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed
				at the beginning of the frame for that channel.  Indicates whether SCE, CPE, or LFE.
				Each particular field is accessed via the current channel index.  Note that the channel
				index increments by two for channel pairs.
				
	For example:
	
			C L R 3-channel input		= (ID_CPE << 3) | (ID_SCE)
				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)

			C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
				index 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3)
				index 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3)
				index 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3)
*/
static const uint32_t	sChannelMaps[kALACMaxChannels] =
{
	ID_SCE,
	ID_CPE,
	(ID_CPE << 3) | (ID_SCE),
	(ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE),
	(ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
	(ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
	(ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
	(ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
};

static const uint32_t sSupportediPodSampleRates[] =
{
	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};

/*
	Constructor
*/
ALACEncoder::ALACEncoder() :
	mBitDepth( 0 ),
    mFastMode( 0 ),
	mMixBufferU( nil ),
	mMixBufferV( nil ),
	mPredictorU( nil ),
	mPredictorV( nil ),
	mShiftBufferUV( nil ),
	mWorkBuffer( nil ),


	mTotalBytesGenerated( 0 ),
	mAvgBitRate( 0 ),
	mMaxFrameBytes( 0 )
{
	// overrides
	mFrameSize = kALACDefaultFrameSize;
}

/*
	Destructor
*/
ALACEncoder::~ALACEncoder()
{
	// delete the matrix mixing buffers
	if ( mMixBufferU )
    {
		free(mMixBufferU);
        mMixBufferU = NULL;
    }
	if ( mMixBufferV )
    {
		free(mMixBufferV);
        mMixBufferV = NULL;
    }
	
	// delete the dynamic predictor's "corrector" buffers
	if ( mPredictorU )
    {
		free(mPredictorU);
        mPredictorU = NULL;
    }
	if ( mPredictorV )
    {
		free(mPredictorV);
        mPredictorV = NULL;
    }

	// delete the unused byte shift buffer
	if ( mShiftBufferUV )
    {
		free(mShiftBufferUV);
        mShiftBufferUV = NULL;
    }

	// delete the work buffer
	if ( mWorkBuffer )
    {
		free(mWorkBuffer);
        mWorkBuffer = NULL;
    }	
}

#if PRAGMA_MARK
#pragma mark -
#endif

/*
	HEADER SPECIFICATION  

        For every segment we adopt the following header:
        
			1 byte reserved			(always 0)
			1 byte flags			(see below)
			[4 byte frame length]	(optional, see below)
			     ---Next, the per-segment ALAC parameters---
			1 byte mixBits			(middle-side parameter)
			1 byte mixRes			(middle-side parameter, interpreted as signed char)

			1 byte shiftU			(4 bits modeU, 4 bits denShiftU)
			1 byte filterU			(3 bits pbFactorU, 5 bits numU)
			(numU) shorts			(signed DP coefficients for V channel)
			     ---Next, 2nd-channel ALAC parameters in case of stereo mode---
			1 byte shiftV			(4 bits modeV, 4 bits denShiftV)
			1 byte filterV			(3 bits pbFactorV, 5 bits numV)
			(numV) shorts			(signed DP coefficients for V channel)
			     ---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated---
			     ---Then comes the AG-compressor bitstream---


        FLAGS
        -----

		The presence of certain flag bits changes the header format such that the parameters might
		not even be sent.  The currently defined flags format is:

			0000psse
			
			where		0 	= reserved, must be 0
						p	= 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte
						ss	= 2-bit field indicating "number of shift-off bytes ignored by compression"
						e	= 1-bit field indicating "escape"

		The "partial frame" flag means that the following segment is not equal to the frame length specified
		in the out-of-band decoder configuration.  This allows the decoder to deal with end-of-file partial
		segments without incurring the 32-bit overhead for each segment.

		The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through
		uncompressed.  The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words
		quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the
		uncompressed size.  However, by shifting the input values down and running the remaining bits through
		the normal compression algorithm, a net win can be achieved.  If this field is non-zero, it means that
		the shifted-off bytes follow after the parameter section of the header and before the compressed
		bitstream.  Note that doing this also allows us to use matrixing on 32-bit inputs after one or more
		bytes are shifted off the bottom which helps the eventual compression ratio.  For stereo channels,
		the shifted off bytes are interleaved.

        The "escape" flag means that this segment was not compressed b/c the compressed size would be
        >= uncompressed size.  In that case, the audio data was passed through uncompressed after the header.
        The other header parameter bytes will not be sent.
        

		PARAMETERS
		----------

		If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by:

			4 + (2 + 2 * numU)                   (mono mode)
			4 + (2 + 2 * numV) + (2 + 2 * numV)  (stereo mode)

        where the ALAC filter-lengths numU, numV are bounded by a
        constant (in the current source, numU, numV <= NUMCOEPAIRS), and
        this forces an absolute upper bound on header size.

        Each segment-decode process loads up these bytes from the front of the
        local stream, in the above order, then follows with the entropy-encoded
        bits for the given segment.

        To generalize middle-side, there are various mixing modes including middle-side, each lossless,
        as embodied in the mix() and unmix() functions.  These functions exploit a generalized middle-side
        transformation:

        u := [(rL + (m-r)R)/m];
        v := L - R;

        where [ ] denotes integer floor.  The (lossless) inverse is

        L = u + v - [rV/m];
        R = L - v;

        In the segment header, m and r are encoded in mixBits and mixRes.
        Classical "middle-side" is obtained with m = 2, r = 1, but now
        we have more generalized mixes.

        NOTES
        -----
        The relevance of the ALAC coefficients is explained in detail
        in patent documents.
*/

/*
	EncodeStereo()
	- encode a channel pair
*/
int32_t ALACEncoder::EncodeStereo( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
{
	BitBuffer		workBits;
	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
	AGParamRec		agParams;
	uint32_t          bits1, bits2;
	uint32_t			dilate;
	int32_t			mixBits, mixRes, maxRes;
	uint32_t			minBits, minBits1, minBits2;
	uint32_t			numU, numV;
	uint32_t			mode;
	uint32_t			pbFactor;
	uint32_t			chanBits;
	uint32_t			denShift;
	uint8_t			bytesShifted;
	SearchCoefs		coefsU;
	SearchCoefs		coefsV;
	uint32_t			index;
	uint8_t			partialFrame;
	uint32_t			escapeBits;
	bool			doEscape;
	int32_t		status = ALAC_noErr;

	// make sure we handle this bit-depth before we get going
	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );

	// reload coefs pointers for this channel pair
	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
	//	 actually results in better overall compression
	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
	//	 different coefs for the different passes of "mixRes" results in even better compression
	coefsU = (SearchCoefs) mCoefsU[channelIndex];
	coefsV = (SearchCoefs) mCoefsV[channelIndex];

	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
	// so enable 16-bit "shift off" and encode in 17-bit mode
	// - in addition, 24-bit mode really improves with one byte shifted off
	if ( mBitDepth == 32 )
		bytesShifted = 2;
	else if ( mBitDepth >= 24 )
		bytesShifted = 1;
	else
		bytesShifted = 0;

	chanBits = mBitDepth - (bytesShifted * 8) + 1;
	
	// flag whether or not this is a partial frame
	partialFrame = (numSamples == mFrameSize) ? 0 : 1;

	// brute-force encode optimization loop
	// - run over variations of the encoding params to find the best choice
	mixBits		= kDefaultMixBits;
	maxRes		= kMaxRes;
	numU = numV = kDefaultNumUV;
	denShift	= DENSHIFT_DEFAULT;
	mode		= 0;
	pbFactor	= 4;
	dilate		= 8;

	minBits	= minBits1 = minBits2 = 1ul << 31;
	
    int32_t		bestRes = mLastMixRes[channelIndex];

    for ( mixRes = 0; mixRes <= maxRes; mixRes++ )
    {
        // mix the stereo inputs
        switch ( mBitDepth )
        {
            case 16:
                mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
                break;
            case 20:
                mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
                break;
            case 24:
                // includes extraction of shifted-off bytes
                mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
                break;
            case 32:
                // includes extraction of shifted-off bytes
                mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
                break;
        }

        BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
        
        // run the dynamic predictors
        pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
        pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );

        // run the lossless compressor on each channel
        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
        status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
        RequireNoErr( status, goto Exit; );

        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
        status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
        RequireNoErr( status, goto Exit; );

        // look for best match
        if ( (bits1 + bits2) < minBits1 )
        {
            minBits1 = bits1 + bits2;
            bestRes = mixRes;
        }
    }
    
    mLastMixRes[channelIndex] = (int16_t)bestRes;

	// mix the stereo inputs with the current best mixRes
	mixRes = mLastMixRes[channelIndex];
	switch ( mBitDepth )
	{
		case 16:
			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
			break;
		case 20:
			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
			break;
		case 24:
			// also extracts the shifted off bytes into the shift buffers
			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
					mixBits, mixRes, mShiftBufferUV, bytesShifted );
			break;
		case 32:
			// also extracts the shifted off bytes into the shift buffers
			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
					mixBits, mixRes, mShiftBufferUV, bytesShifted );
			break;
	}

	// now it's time for the predictor coefficient search loop
	numU = numV = kMinUV;
	minBits1 = minBits2 = 1ul << 31;

	for ( uint32_t numUV = kMinUV; numUV <= kMaxUV; numUV += 4 )
	{
		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );		

		dilate = 32;

		// run the predictor over the same data multiple times to help it converge
		for ( uint32_t converge = 0; converge < 8; converge++ )
		{
		    pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
		    pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
		}

		dilate = 8;

		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );

		if ( (bits1 * dilate + 16 * numUV) < minBits1 )
		{
			minBits1 = bits1 * dilate + 16 * numUV;
			numU = numUV;
		}

		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
		status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );

		if ( (bits2 * dilate + 16 * numUV) < minBits2 )
		{
			minBits2 = bits2 * dilate + 16 * numUV;
			numV = numUV;
		}
	}

	// test for escape hatch if best calculated compressed size turns out to be more than the input size
	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
	if ( bytesShifted != 0 )
		minBits += (numSamples * (bytesShifted * 8) * 2);

	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */

	doEscape = (minBits >= escapeBits) ? true : false;

	if ( doEscape == false )
	{
		// write bitstream header and coefs
		BitBufferWrite( bitstream, 0, 12 );
		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
		if ( partialFrame )
			BitBufferWrite( bitstream, numSamples, 32 );
		BitBufferWrite( bitstream, mixBits, 8 );
		BitBufferWrite( bitstream, mixRes, 8 );
		
		//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
		//Assert( (pbFactor < 8) && (numU < 32) );
		//Assert( (pbFactor < 8) && (numV < 32) );

		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
		for ( index = 0; index < numU; index++ )
			BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );

		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
		BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
		for ( index = 0; index < numV; index++ )
			BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );

		// if shift active, write the interleaved shift buffers
		if ( bytesShifted != 0 )
		{
			uint32_t		bitShift = bytesShifted * 8;

			//Assert( bitShift <= 16 );

			for ( index = 0; index < (numSamples * 2); index += 2 )
			{
				uint32_t			shiftedVal;
				
				shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
				BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
			}
		}

		// run the dynamic predictor and lossless compression for the "left" channel
		// - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead
		//		   of only using "U" buffers for the U-channel and "V" buffers for the V-channel
		if ( mode == 0 )
		{
			pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
		}
		else
		{
			pc_block( mMixBufferU, mPredictorV, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
			pc_block( mPredictorV, mPredictorU, numSamples, nil, 31, chanBits, 0 );
		}

		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
		RequireNoErr( status, goto Exit; );

		// run the dynamic predictor and lossless compression for the "right" channel
		if ( mode == 0 )
		{
			pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
		}
		else
		{
			pc_block( mMixBufferV, mPredictorU, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
			pc_block( mPredictorU, mPredictorV, numSamples, nil, 31, chanBits, 0 );
		}

		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
		status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
		RequireNoErr( status, goto Exit; );

		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
			chuck it and do an escape packet
		*/
		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
		if ( minBits >= escapeBits )
		{
			*bitstream = startBits;		// reset bitstream state
			doEscape = true;
		}
	}

	if ( doEscape == true )
	{
		/* escape */
		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );

#if VERBOSE_DEBUG		
		DebugMsg( "escape!: %lu vs %lu", minBits, escapeBits );
#endif
	}
	
Exit:
	return status;
}

/*
	EncodeStereoFast()
	- encode a channel pair without the search loop for maximum possible speed
*/
int32_t ALACEncoder::EncodeStereoFast( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
{
	BitBuffer		startBits = *bitstream;			// squirrel away current bit position in case we decide to use escape hatch
	AGParamRec		agParams;
	uint32_t	bits1, bits2;
	int32_t			mixBits, mixRes;
	uint32_t			minBits, minBits1, minBits2;
	uint32_t			numU, numV;
	uint32_t			mode;
	uint32_t			pbFactor;
	uint32_t			chanBits;
	uint32_t			denShift;
	uint8_t			bytesShifted;
	SearchCoefs		coefsU;
	SearchCoefs		coefsV;
	uint32_t			index;
	uint8_t			partialFrame;
	uint32_t			escapeBits;
	bool			doEscape;	
	int32_t		status;

	// make sure we handle this bit-depth before we get going
	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );

	// reload coefs pointers for this channel pair
	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
	//	 actually results in better overall compression
	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
	//	 different coefs for the different passes of "mixRes" results in even better compression
	coefsU = (SearchCoefs) mCoefsU[channelIndex];
	coefsV = (SearchCoefs) mCoefsV[channelIndex];

	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
	// so enable 16-bit "shift off" and encode in 17-bit mode
	// - in addition, 24-bit mode really improves with one byte shifted off
	if ( mBitDepth == 32 )
		bytesShifted = 2;
	else if ( mBitDepth >= 24 )
		bytesShifted = 1;
	else
		bytesShifted = 0;

	chanBits = mBitDepth - (bytesShifted * 8) + 1;
	
	// flag whether or not this is a partial frame
	partialFrame = (numSamples == mFrameSize) ? 0 : 1;

	// set up default encoding parameters for "fast" mode
	mixBits		= kDefaultMixBits;
	mixRes		= kDefaultMixRes;
	numU = numV = kDefaultNumUV;
	denShift	= DENSHIFT_DEFAULT;
	mode		= 0;
	pbFactor	= 4;

	minBits	= minBits1 = minBits2 = 1ul << 31;
	
	// mix the stereo inputs with default mixBits/mixRes
	switch ( mBitDepth )
	{
		case 16:
			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
			break;
		case 20:
			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
			break;
		case 24:
			// also extracts the shifted off bytes into the shift buffers
			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
					mixBits, mixRes, mShiftBufferUV, bytesShifted );
			break;
		case 32:
			// also extracts the shifted off bytes into the shift buffers
			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
					mixBits, mixRes, mShiftBufferUV, bytesShifted );
			break;
	}

	/* speculatively write the bitstream assuming the compressed version will be smaller */

	// write bitstream header and coefs
	BitBufferWrite( bitstream, 0, 12 );
	BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
	if ( partialFrame )
		BitBufferWrite( bitstream, numSamples, 32 );
	BitBufferWrite( bitstream, mixBits, 8 );
	BitBufferWrite( bitstream, mixRes, 8 );
	
	//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
	//Assert( (pbFactor < 8) && (numU < 32) );
	//Assert( (pbFactor < 8) && (numV < 32) );

	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
	BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
	for ( index = 0; index < numU; index++ )
		BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );

	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
	BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
	for ( index = 0; index < numV; index++ )
		BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );

	// if shift active, write the interleaved shift buffers
	if ( bytesShifted != 0 )
	{
		uint32_t		bitShift = bytesShifted * 8;

		//Assert( bitShift <= 16 );

		for ( index = 0; index < (numSamples * 2); index += 2 )
		{
			uint32_t			shiftedVal;
			
			shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
			BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
		}
	}

	// run the dynamic predictor and lossless compression for the "left" channel
	// - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0
	pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );

	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
	status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
	RequireNoErr( status, goto Exit; );

	// run the dynamic predictor and lossless compression for the "right" channel
	pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );

	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
	status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
	RequireNoErr( status, goto Exit; );

	// do bit requirement calculations
	minBits1 = bits1 + (numU * sizeof(int16_t) * 8);
	minBits2 = bits2 + (numV * sizeof(int16_t) * 8);

	// test for escape hatch if best calculated compressed size turns out to be more than the input size
	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
	if ( bytesShifted != 0 )
		minBits += (numSamples * (bytesShifted * 8) * 2);

	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */

	doEscape = (minBits >= escapeBits) ? true : false;

	if ( doEscape == false )
	{
		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
			chuck it and do an escape packet
		*/
		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
		if ( minBits >= escapeBits )
		{
			doEscape = true;
		}

	}

	if ( doEscape == true )
	{
		/* escape */

		// reset bitstream position since we speculatively wrote the compressed version
		*bitstream = startBits;

		// write escape frame
		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );

#if VERBOSE_DEBUG		
		DebugMsg( "escape!: %u vs %u", minBits, (numSamples * mBitDepth * 2) );
#endif
	}
	
Exit:
	return status;
}

/*
	EncodeStereoEscape()
	- encode stereo escape frame
*/
int32_t ALACEncoder::EncodeStereoEscape( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t numSamples )
{
	int16_t *		input16;
	int32_t *		input32;
	uint8_t			partialFrame;
	uint32_t			index;

	// flag whether or not this is a partial frame
	partialFrame = (numSamples == mFrameSize) ? 0 : 1;

	// write bitstream header
	BitBufferWrite( bitstream, 0, 12 );
	BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
	if ( partialFrame )
		BitBufferWrite( bitstream, numSamples, 32 );

	// just copy the input data to the output buffer
	switch ( mBitDepth )
	{
		case 16:
			input16 = (int16_t *) inputBuffer;
			
			for ( index = 0; index < (numSamples * stride); index += stride )
			{
				BitBufferWrite( bitstream, input16[index + 0], 16 );
				BitBufferWrite( bitstream, input16[index + 1], 16 );
			}
			break;
		case 20:
			// mix20() with mixres param = 0 means de-interleave so use it to simplify things
			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0 );
			for ( index = 0; index < numSamples; index++ )
			{
				BitBufferWrite( bitstream, mMixBufferU[index], 20 );
				BitBufferWrite( bitstream, mMixBufferV[index], 20 );
			}				
			break;
		case 24:
			// mix24() with mixres param = 0 means de-interleave so use it to simplify things
			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0, mShiftBufferUV, 0 );
			for ( index = 0; index < numSamples; index++ )
			{
				BitBufferWrite( bitstream, mMixBufferU[index], 24 );
				BitBufferWrite( bitstream, mMixBufferV[index], 24 );
			}				
			break;
		case 32:
			input32 = (int32_t *) inputBuffer;

			for ( index = 0; index < (numSamples * stride); index += stride )
			{
				BitBufferWrite( bitstream, input32[index + 0], 32 );
				BitBufferWrite( bitstream, input32[index + 1], 32 );
			}				
			break;
	}
	
	return ALAC_noErr;
}

/*
	EncodeMono()
	- encode a mono input buffer
*/
int32_t ALACEncoder::EncodeMono( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
{
	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
	AGParamRec		agParams;
	uint32_t	bits1;
	uint32_t			numU;
	SearchCoefs		coefsU;
	uint32_t			dilate;
	uint32_t			minBits, bestU;
	uint32_t			minU, maxU;
	uint32_t			index, index2;
	uint8_t			bytesShifted;
	uint32_t			shift;
	uint32_t			mask;
	uint32_t			chanBits;
	uint8_t			pbFactor;
	uint8_t			partialFrame;
	int16_t *		input16;
	int32_t *		input32;
	uint32_t			escapeBits;
	bool			doEscape;
	int32_t		status;

	// make sure we handle this bit-depth before we get going
	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );

	status = ALAC_noErr;
	
	// reload coefs array from previous frame
	coefsU = (SearchCoefs) mCoefsU[channelIndex];

	// pick bit depth for actual encoding
	// - we lop off the lower byte(s) for 24-/32-bit encodings
	if ( mBitDepth == 32 )
		bytesShifted = 2;
	else if ( mBitDepth >= 24 )
		bytesShifted = 1;
	else
		bytesShifted = 0;

	shift = bytesShifted * 8;
	mask = (1ul << shift) - 1;
	chanBits = mBitDepth - (bytesShifted * 8);

	// flag whether or not this is a partial frame
	partialFrame = (numSamples == mFrameSize) ? 0 : 1;

	// convert N-bit data to 32-bit for predictor
	switch ( mBitDepth )
	{
		case 16:
		{
			// convert 16-bit data to 32-bit for predictor
			input16 = (int16_t *) inputBuffer;
			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
				mMixBufferU[index] = (int32_t) input16[index2];
			break;
		}
		case 20:
			// convert 20-bit data to 32-bit for predictor
			copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
			break;
		case 24:
			// convert 24-bit data to 32-bit for the predictor and extract the shifted off byte(s)
			copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
			for ( index = 0; index < numSamples; index++ )
			{
				mShiftBufferUV[index] = (uint16_t)(mMixBufferU[index] & mask);
				mMixBufferU[index] >>= shift;
			}
			break;
		case 32:
		{
			// just copy the 32-bit input data for the predictor and extract the shifted off byte(s)
			input32 = (int32_t *) inputBuffer;

			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
			{
				int32_t			val = input32[index2];
				
				mShiftBufferUV[index] = (uint16_t)(val & mask);
				mMixBufferU[index] = val >> shift;
			}
			break;
		}
	}

	// brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool)
	// - run over variations of the encoding params to find the best choice
	minU		= 4;
	maxU		= 8;
	minBits		= 1ul << 31;
	pbFactor	= 4;
	
	minBits	= 1ul << 31;
	bestU	= minU;

	for ( numU = minU; numU <= maxU; numU += 4 )
	{
		BitBuffer		workBits;
		uint32_t			numBits;

		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
	
		dilate = 32;
		for ( uint32_t converge = 0; converge < 7; converge++ )	
			pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );

		dilate = 8;
		pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );

		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
		RequireNoErr( status, goto Exit; );

		numBits = (dilate * bits1) + (16 * numU);
		if ( numBits < minBits )
		{
			bestU	= numU;
			minBits = numBits;
		}
	}             

	// test for escape hatch if best calculated compressed size turns out to be more than the input size
	// - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU
	minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
	if ( bytesShifted != 0 )
		minBits += (numSamples * (bytesShifted * 8));

	escapeBits = (numSamples * mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */

	doEscape = (minBits >= escapeBits) ? true : false;

	if ( doEscape == false )
	{
		// write bitstream header
		BitBufferWrite( bitstream, 0, 12 );
		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
		if ( partialFrame )
			BitBufferWrite( bitstream, numSamples, 32 );
		BitBufferWrite( bitstream, 0, 16 );								// mixBits = mixRes = 0
		
		// write the params and predictor coefs
		numU = bestU;
		BitBufferWrite( bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8 );	// modeU = 0
		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
		for ( index = 0; index < numU; index++ )
			BitBufferWrite( bitstream, coefsU[numU-1][index], 16 );

		// if shift active, write the interleaved shift buffers
		if ( bytesShifted != 0 )
		{
			for ( index = 0; index < numSamples; index++ )
				BitBufferWrite( bitstream, mShiftBufferUV[index], shift );
		}

		// run the dynamic predictor with the best result
		pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );

		// do lossless compression
		set_standard_ag_params( &agParams, numSamples, numSamples );
		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
		//AssertNoErr( status );


		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
			chuck it and do an escape packet
		*/
		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
		if ( minBits >= escapeBits )
		{
			*bitstream = startBits;		// reset bitstream state
			doEscape = true;
		}
	}

	if ( doEscape == true )
	{
		// write bitstream header and coefs
		BitBufferWrite( bitstream, 0, 12 );
		BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
		if ( partialFrame )
			BitBufferWrite( bitstream, numSamples, 32 );

		// just copy the input data to the output buffer
		switch ( mBitDepth )
		{
			case 16:
				input16 = (int16_t *) inputBuffer;
				for ( index = 0; index < (numSamples * stride); index += stride )
					BitBufferWrite( bitstream, input16[index], 16 );
				break;
			case 20:
				// convert 20-bit data to 32-bit for simplicity
				copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
				for ( index = 0; index < numSamples; index++ )
					BitBufferWrite( bitstream, mMixBufferU[index], 20 );
				break;
			case 24:
				// convert 24-bit data to 32-bit for simplicity
				copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
				for ( index = 0; index < numSamples; index++ )
					BitBufferWrite( bitstream, mMixBufferU[index], 24 );
				break;
			case 32:
				input32 = (int32_t *) inputBuffer;
				for ( index = 0; index < (numSamples * stride); index += stride )
					BitBufferWrite( bitstream, input32[index], 32 );
				break;
		}
#if VERBOSE_DEBUG		
		DebugMsg( "escape!: %lu vs %lu", minBits, (numSamples * mBitDepth) );
#endif
	}

Exit:
	return status;
}

#if PRAGMA_MARK
#pragma mark -
#endif

/*
	Encode()
	- encode the next block of samples
*/
int32_t ALACEncoder::Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
                             unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes)
{
	uint32_t				numFrames;
	uint32_t				outputSize;
	BitBuffer			bitstream;
	int32_t			status;

	numFrames = *ioNumBytes/theInputFormat.mBytesPerPacket;

	// create a bit buffer structure pointing to our output buffer
	BitBufferInit( &bitstream, theWriteBuffer, mMaxOutputBytes );

	if ( theInputFormat.mChannelsPerFrame == 2 )
	{
		// add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0
		BitBufferWrite( &bitstream, ID_CPE, 3 );
		BitBufferWrite( &bitstream, 0, 4 );

		// encode stereo input buffer
		if ( mFastMode == false )
			status = this->EncodeStereo( &bitstream, theReadBuffer, 2, 0, numFrames );
		else
			status = this->EncodeStereoFast( &bitstream, theReadBuffer, 2, 0, numFrames );
		RequireNoErr( status, goto Exit; );
	}
	else if ( theInputFormat.mChannelsPerFrame == 1 )
	{
		// add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0
		BitBufferWrite( &bitstream, ID_SCE, 3 );
		BitBufferWrite( &bitstream, 0, 4 );

		// encode mono input buffer
		status = this->EncodeMono( &bitstream, theReadBuffer, 1, 0, numFrames );
		RequireNoErr( status, goto Exit; );
	}
	else
	{
		char *					inputBuffer;
		uint32_t				tag;
		uint32_t				channelIndex;
		uint32_t				inputIncrement;
		uint8_t				stereoElementTag;
		uint8_t				monoElementTag;
		uint8_t				lfeElementTag;
		
		inputBuffer		= (char *) theReadBuffer;
		inputIncrement	= ((mBitDepth + 7) / 8);
		
		stereoElementTag	= 0;
		monoElementTag		= 0;
		lfeElementTag		= 0;

		for ( channelIndex = 0; channelIndex < theInputFormat.mChannelsPerFrame; )
		{
			tag = (sChannelMaps[theInputFormat.mChannelsPerFrame - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3);
	
			BitBufferWrite( &bitstream, tag, 3 );
			switch ( tag )
			{
				case ID_SCE:
					// mono
					BitBufferWrite( &bitstream, monoElementTag, 4 );

					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
					
					inputBuffer += inputIncrement;
					channelIndex++;
					monoElementTag++;
					break;

				case ID_CPE:
					// stereo
					BitBufferWrite( &bitstream, stereoElementTag, 4 );

					status = this->EncodeStereo( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );

					inputBuffer += (inputIncrement * 2);
					channelIndex += 2;
					stereoElementTag++;
					break;

				case ID_LFE:
					// LFE channel (subwoofer)
					BitBufferWrite( &bitstream, lfeElementTag, 4 );

					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );

					inputBuffer += inputIncrement;
					channelIndex++;
					lfeElementTag++;
					break;

				default:
					status = kALAC_ParamError;
					goto Exit;
			}

			RequireNoErr( status, goto Exit; );
		}
	}

#if VERBOSE_DEBUG
{
	// if there is room left in the output buffer, add some random fill data to test decoder
	int32_t			bitsLeft;
	int32_t			bytesLeft;
	
	bitsLeft = BitBufferGetPosition( &bitstream ) - 3;	// - 3 for ID_END tag
	bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8);
	
	if ( (bytesLeft > 20) && ((bytesLeft & 0x4u) != 0) )
		AddFiller( &bitstream, bytesLeft );
}
#endif

	// add 3-bit frame end tag: ID_END
	BitBufferWrite( &bitstream, ID_END, 3 );

	// byte-align the output data
	BitBufferByteAlign( &bitstream, true );

	outputSize = BitBufferGetPosition( &bitstream ) / 8;
	//Assert( outputSize <= mMaxOutputBytes );


	// all good, let iTunes know what happened and remember the total number of input sample frames
	*ioNumBytes = outputSize;
	//mEncodedFrames		   	   += encodeMsg->numInputSamples;

	// gather encoding stats
	mTotalBytesGenerated += outputSize;
	mMaxFrameBytes = MAX( mMaxFrameBytes, outputSize );

	status = ALAC_noErr;

Exit:
	return status;
}

/*
	Finish()
	- drain out any leftover samples
*/

int32_t ALACEncoder::Finish()
{
/*	// finalize bit rate statistics
	if ( mSampleSize.numEntries != 0 )
		mAvgBitRate = (uint32_t)( (((float)mTotalBytesGenerated * 8.0f) / (float)mSampleSize.numEntries) * ((float)mSampleRate / (float)mFrameSize) );
	else
		mAvgBitRate = 0;
*/
	return ALAC_noErr;
}

#if PRAGMA_MARK
#pragma mark -
#endif

/*
	GetConfig()
*/
void ALACEncoder::GetConfig( ALACSpecificConfig & config )
{
	config.frameLength			= Swap32NtoB(mFrameSize);
	config.compatibleVersion	= (uint8_t) kALACCompatibleVersion;
	config.bitDepth				= (uint8_t) mBitDepth;
	config.pb					= (uint8_t) PB0;
	config.kb					= (uint8_t) KB0;
	config.mb					= (uint8_t) MB0;
	config.numChannels			= (uint8_t) mNumChannels;
	config.maxRun				= Swap16NtoB((uint16_t) MAX_RUN_DEFAULT);
	config.maxFrameBytes		= Swap32NtoB(mMaxFrameBytes);
	config.avgBitRate			= Swap32NtoB(mAvgBitRate);
	config.sampleRate			= Swap32NtoB(mOutputSampleRate);
}

uint32_t ALACEncoder::GetMagicCookieSize(uint32_t inNumChannels)
{
    if (inNumChannels > 2)
    {
        return sizeof(ALACSpecificConfig) + kChannelAtomSize + sizeof(ALACAudioChannelLayout);
    }
    else
    {
        return sizeof(ALACSpecificConfig);
    }
}

void ALACEncoder::GetMagicCookie(void * outCookie, uint32_t * ioSize)
{
    ALACSpecificConfig theConfig = {0};
    ALACAudioChannelLayout theChannelLayout = {0};
    uint8_t theChannelAtom[kChannelAtomSize] = {0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0};
    uint32_t theCookieSize = sizeof(ALACSpecificConfig);
    uint8_t * theCookiePointer = (uint8_t *)outCookie;
    
    GetConfig(theConfig);
    if (theConfig.numChannels > 2)
    {
        theChannelLayout.mChannelLayoutTag = Swap32NtoB(ALACChannelLayoutTags[theConfig.numChannels - 1]);
        theCookieSize += (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
    }
     if (*ioSize >= theCookieSize)
    {
        memcpy(theCookiePointer, &theConfig, sizeof(ALACSpecificConfig));
        theChannelAtom[3] = (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
        if (theConfig.numChannels > 2)
        {
            theCookiePointer += sizeof(ALACSpecificConfig);
            memcpy(theCookiePointer, theChannelAtom, kChannelAtomSize);
            theCookiePointer += kChannelAtomSize;
            memcpy(theCookiePointer, &theChannelLayout, sizeof(ALACAudioChannelLayout));
        }
        *ioSize = theCookieSize;
    }
    else
    {
        *ioSize = 0; // no incomplete cookies
    }
}

/*
	InitializeEncoder()
	- initialize the encoder component with the current config
*/
int32_t ALACEncoder::InitializeEncoder(AudioFormatDescription theOutputFormat)
{
	int32_t			status;
    
    mOutputSampleRate = theOutputFormat.mSampleRate;
    mNumChannels = theOutputFormat.mChannelsPerFrame;
    switch(theOutputFormat.mFormatFlags)
    {
        case 1:
            mBitDepth = 16;
            break;
        case 2:
            mBitDepth = 20;
            break;
        case 3:
            mBitDepth = 24;
            break;
        case 4:
            mBitDepth = 32;
            break;
        default:
            break;
    }

	// set up default encoding parameters and state
	// - note: mFrameSize is set in the constructor or via SetFrameSize() which must be called before this routine
	for ( uint32_t index = 0; index < kALACMaxChannels; index++ )
		mLastMixRes[index] = kDefaultMixRes;

	// the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1)
	// but note that this can be bigger than the input size!
	// - since we don't yet know what our input format will be, use our max allowed sample size in the calculation
	mMaxOutputBytes = mFrameSize * mNumChannels * ((10 + kMaxSampleSize) / 8)  + 1;

	// allocate mix buffers
	mMixBufferU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
	mMixBufferV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );

	// allocate dynamic predictor buffers
	mPredictorU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
	mPredictorV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
	
	// allocate combined shift buffer
	mShiftBufferUV = (uint16_t *) calloc( mFrameSize * 2 * sizeof(uint16_t),1 );
	
	// allocate work buffer for search loop
	mWorkBuffer = (uint8_t *) calloc( mMaxOutputBytes, 1 );

	RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) &&
					(mPredictorU != nil) && (mPredictorV != nil) &&
					(mShiftBufferUV != nil) && (mWorkBuffer != nil ),
					status = kALAC_MemFullError; goto Exit; );

	status = ALAC_noErr;


	// initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio
	for ( int32_t channel = 0; channel < (int32_t)mNumChannels; channel++ )
	{
		for ( int32_t search = 0; search < kALACMaxSearches; search++ )
		{
			init_coefs( mCoefsU[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
			init_coefs( mCoefsV[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
		}
	}

Exit:
	return status;
}

/*
	GetSourceFormat()
	- given the input format, return one of our supported formats
*/
void ALACEncoder::GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output )
{
	// default is 16-bit native endian
	// - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense
	//		   to encode to 16-bit since the source was lossy in the first place
	// - note: if not a supported bit depth, find the closest supported bit depth to the input one
	if ( (source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) ||
		( source->mBitsPerChannel <= 16 ) )
		mBitDepth = 16;
	else if ( source->mBitsPerChannel <= 20 )
		mBitDepth = 20;
	else if ( source->mBitsPerChannel <= 24 )
		mBitDepth = 24;
	else
		mBitDepth = 32;
		
	// we support 16/20/24/32-bit integer data at any sample rate and our target number of channels
	// and sample rate were specified when we were configured
	/*
    MakeUncompressedAudioFormat( mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output );
     */
}



#if VERBOSE_DEBUG

#if PRAGMA_MARK
#pragma mark -
#endif

/*
	AddFiller()
	- add fill and data stream elements to the bitstream to test the decoder
*/
static void AddFiller( BitBuffer * bits, int32_t numBytes )
{
	uint8_t		tag;
	uint32_t		index;

	// out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements
	numBytes -= 6;
	if ( numBytes <= 0 )
		return;
	
	// randomly pick Fill or Data Stream Element based on numBytes requested
	tag = (numBytes & 0x8) ? ID_FIL : ID_DSE;

	BitBufferWrite( bits, tag, 3 );
	if ( tag == ID_FIL )
	{
		// can't write more than 269 bytes in a fill element
		numBytes = (numBytes > 269) ? 269 : numBytes;

		// fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size
		if ( numBytes >= 15 )
		{
			uint16_t			extensionSize;

			BitBufferWrite( bits, 15, 4 );

			// 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax
			// - otherwise, there's no way to represent 15
			// - for example, to really mean 15 bytes you must encode extensionSize = 1
			// - why it's not like data stream elements I have no idea
			extensionSize = (numBytes - 15) + 1;
			Assert( extensionSize <= 255 );
			BitBufferWrite( bits, extensionSize, 8 );
		}
		else
			BitBufferWrite( bits, numBytes, 4 );

		BitBufferWrite( bits, 0x10, 8 );		// extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000
		for ( index = 0; index < (numBytes - 1); index++ )
			BitBufferWrite( bits, 0xa5, 8 );	// fill_byte = b10100101 = 0xa5
	}
	else
	{
		// can't write more than 510 bytes in a data stream element
		numBytes = (numBytes > 510) ? 510 : numBytes;

		BitBufferWrite( bits, 0, 4 );			// element instance tag
		BitBufferWrite( bits, 1, 1 );			// byte-align flag = true

		// data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size
		if ( numBytes >= 255 )
		{
			BitBufferWrite( bits, 255, 8 );
			BitBufferWrite( bits, numBytes - 255, 8 );
		}
		else
			BitBufferWrite( bits, numBytes, 8 );
		
		BitBufferByteAlign( bits, true );		// byte-align with zeros

		for ( index = 0; index < numBytes; index++ )
			BitBufferWrite( bits, 0x5a, 8 );
	}
}

#endif	/* VERBOSE_DEBUG */
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ALACEncoder.h
*/

#pragma once

#include <stdint.h>

#include "ALACAudioTypes.h"


struct BitBuffer;

class ALACEncoder
{
	public:
		ALACEncoder();
		virtual ~ALACEncoder();

		virtual int32_t	Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
                                   unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes);
		virtual int32_t	Finish( );

		void				SetFastMode( bool fast ) { mFastMode = fast; };

		// this must be called *before* InitializeEncoder()
		void				SetFrameSize( uint32_t frameSize ) { mFrameSize = frameSize; };

		void				GetConfig( ALACSpecificConfig & config );
        uint32_t            GetMagicCookieSize(uint32_t inNumChannels);
        void				GetMagicCookie( void * config, uint32_t * ioSize ); 

        virtual int32_t	InitializeEncoder(AudioFormatDescription theOutputFormat);

    protected:
		virtual void		GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output );
		
		int32_t			EncodeStereo( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
		int32_t			EncodeStereoFast( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
		int32_t			EncodeStereoEscape( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t numSamples );
		int32_t			EncodeMono( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );


		// ALAC encoder parameters
		int16_t					mBitDepth;
		bool					mFastMode;

		// encoding state
		int16_t					mLastMixRes[kALACMaxChannels];

		// encoding buffers
		int32_t *				mMixBufferU;
		int32_t *				mMixBufferV;
		int32_t *				mPredictorU;
		int32_t *				mPredictorV;
		uint16_t *				mShiftBufferUV;
		
		uint8_t *					mWorkBuffer;

		// per-channel coefficients buffers
		int16_t					mCoefsU[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];
		int16_t					mCoefsV[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];

		// encoding statistics
		uint32_t					mTotalBytesGenerated;
		uint32_t					mAvgBitRate;
		uint32_t					mMaxFrameBytes;
        uint32_t                  mFrameSize;
        uint32_t                  mMaxOutputBytes;
        uint32_t                  mNumChannels;
        uint32_t                  mOutputSampleRate;		
};
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

//
//  EndianPortable.c
//
//  Copyright 2011 Apple Inc. All rights reserved.
//

#include "config.h"
#include "EndianPortable.h"

#define BSWAP16(x) (((x << 8) | ((x >> 8) & 0x00ff)))
#define BSWAP32(x) (((x << 24) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff)))
#define BSWAP64(x) ((((int64_t)x << 56) | (((int64_t)x << 40) & 0x00ff000000000000LL) | \
                    (((int64_t)x << 24) & 0x0000ff0000000000LL) | (((int64_t)x << 8) & 0x000000ff00000000LL) | \
                    (((int64_t)x >> 8) & 0x00000000ff000000LL) | (((int64_t)x >> 24) & 0x0000000000ff0000LL) | \
                    (((int64_t)x >> 40) & 0x000000000000ff00LL) | (((int64_t)x >> 56) & 0x00000000000000ffLL)))

#ifndef WORDS_BIGENDIAN
#define TARGET_RT_LITTLE_ENDIAN 1
#endif

uint16_t Swap16NtoB(uint16_t inUInt16)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP16(inUInt16);
#else
    return inUInt16;
#endif
}

uint16_t Swap16BtoN(uint16_t inUInt16)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP16(inUInt16);
#else
    return inUInt16;
#endif
}

uint32_t Swap32NtoB(uint32_t inUInt32)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP32(inUInt32);
#else
    return inUInt32;
#endif
}

uint32_t Swap32BtoN(uint32_t inUInt32)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP32(inUInt32);
#else
    return inUInt32;
#endif
}

uint64_t Swap64BtoN(uint64_t inUInt64)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP64(inUInt64);
#else
    return inUInt64;
#endif
}

uint64_t Swap64NtoB(uint64_t inUInt64)
{
#if TARGET_RT_LITTLE_ENDIAN
    return BSWAP64(inUInt64);
#else
    return inUInt64;
#endif
}

float SwapFloat32BtoN(float in)
{
#if TARGET_RT_LITTLE_ENDIAN
	union {
		float f;
		int32_t i;
	} x;
	x.f = in;	
	x.i = BSWAP32(x.i);
	return x.f;
#else
	return in;
#endif
}

float SwapFloat32NtoB(float in)
{
#if TARGET_RT_LITTLE_ENDIAN
	union {
		float f;
		int32_t i;
	} x;
	x.f = in;	
	x.i = BSWAP32(x.i);
	return x.f;
#else
	return in;
#endif
}

double SwapFloat64BtoN(double in)
{
#if TARGET_RT_LITTLE_ENDIAN
	union {
		double f;
		int64_t i;
	} x;
	x.f = in;	
	x.i = BSWAP64(x.i);
	return x.f;
#else
	return in;
#endif
}

double SwapFloat64NtoB(double in)
{
#if TARGET_RT_LITTLE_ENDIAN
	union {
		double f;
		int64_t i;
	} x;
	x.f = in;	
	x.i = BSWAP64(x.i);
	return x.f;
#else
	return in;
#endif
}

void Swap16(uint16_t * inUInt16)
{
	*inUInt16 = BSWAP16(*inUInt16);
}

void Swap24(uint8_t * inUInt24)
{
	uint8_t tempVal = inUInt24[0];
	inUInt24[0] = inUInt24[2];
	inUInt24[2] = tempVal;
}

void Swap32(uint32_t * inUInt32)
{
	*inUInt32 = BSWAP32(*inUInt32);
}

/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

//
//  EndianPortable.h
//
//  Copyright 2011 Apple Inc. All rights reserved.
//

#ifndef _EndianPortable_h
#define _EndianPortable_h

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

uint16_t Swap16NtoB(uint16_t inUInt16);
uint16_t Swap16BtoN(uint16_t inUInt16);

uint32_t Swap32NtoB(uint32_t inUInt32);
uint32_t Swap32BtoN(uint32_t inUInt32);

uint64_t Swap64BtoN(uint64_t inUInt64);
uint64_t Swap64NtoB(uint64_t inUInt64);

float SwapFloat32BtoN(float in);
float SwapFloat32NtoB(float in);

double SwapFloat64BtoN(double in);
double SwapFloat64NtoB(double in);

void Swap16(uint16_t * inUInt16);
void Swap24(uint8_t * inUInt24);
void Swap32(uint32_t * inUInt32);

#ifdef __cplusplus
}
#endif

#endif
noinst_LTLIBRARIES = libalac.la

libalac_la_SOURCES = \
	ag_dec.c \
	ag_enc.c \
	aglib.h \
	ALACAudioTypes.h \
	ALACBitUtilities.c \
	ALACBitUtilities.h \
	ALACDecoder.cpp \
	ALACDecoder.h \
	ALACEncoder.cpp \
	ALACEncoder.h \
	dp_dec.c \
	dp_enc.c \
	dplib.h \
	EndianPortable.c \
	EndianPortable.h \
	matrix_dec.c \
	matrix_enc.c \
	matrixlib.h

AM_CFLAGS = \
	-DNDEBUG \
	-Wall \
	-Wno-multichar \
	$(COVERAGE_CFLAGS) \
	-fvisibility=hidden
AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden

CLEANFILES = *.gcda *.gcno
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ag_dec.c
	
	Contains:   Adaptive Golomb decode routines.

	Copyright:	(c) 2001-2011 Apple, Inc.
*/

#include "aglib.h"
#include "ALACBitUtilities.h"
#include "ALACAudioTypes.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

#define CODE_TO_LONG_MAXBITS	32
#define N_MAX_MEAN_CLAMP		0xffff
#define N_MEAN_CLAMP_VAL		0xffff
#define REPORT_VAL  40

#if __GNUC__
#define ALWAYS_INLINE		__attribute__((always_inline))
#else
#define ALWAYS_INLINE
#endif

/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
	if it is ugly but the performance gains are well worth it.
	- WSK 5/19/04
*/

void set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth)
{
	/* Use
		fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data,
		but use
		fullwidth = full image width, sectorwidth = sector (patch) width
		for such as image (2-dim.) data.
	*/
	set_ag_params( params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT );
}

void set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun)
{
	params->mb = params->mb0 = m;
	params->pb = p;
	params->kb = k;
	params->wb = (1u<<params->kb)-1;
	params->qb = QB-params->pb; 
	params->fw = f;
	params->sw = s;
	params->maxrun = maxrun;
}

#if PRAGMA_MARK
#pragma mark -
#endif


// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
static inline int32_t lead( int32_t m )
{
	long j;
	unsigned long c = (1ul << 31);

	for(j=0; j < 32; j++)
	{
		if((c & m) != 0)
			break;
		c >>= 1;
	}
	return (j);
}

#define arithmin(a, b) ((a) < (b) ? (a) : (b))

static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
{
    int32_t result;

    x += 3;
    result = lead(x);

    return 31 - result;
}

static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer )
{
	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
	uint32_t		value;
	
	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
	return value;

}

#if PRAGMA_MARK
#pragma mark -
#endif

#define get_next_fromlong(inlong, suff)		((inlong) >> (32 - (suff)))


static inline uint32_t ALWAYS_INLINE
getstreambits( uint8_t *in, int32_t bitoffset, int32_t numbits )
{
	uint32_t	load1, load2;
	uint32_t	byteoffset = bitoffset / 8;
	uint32_t	result;
	
	//Assert( numbits <= 32 );

	load1 = read32bit( in + byteoffset );

	if ( (numbits + (bitoffset & 0x7)) > 32)
	{
		int32_t load2shift;

		result = load1 << (bitoffset & 0x7);
		load2 = (uint32_t) in[byteoffset+4];
		load2shift = (8-(numbits + (bitoffset & 0x7)-32));
		load2 >>= load2shift;
		result >>= (32-numbits);
		result |= load2;		
	}
	else
	{
		result = load1 >> (32-numbits-(bitoffset & 7));
	}

	// a shift of >= "the number of bits in the type of the value being shifted" results in undefined
	// behavior so don't try to shift by 32
	if ( numbits != (sizeof(result) * 8) )
		result &= ~(0xfffffffful << numbits);
	
	return result;
}


static inline int32_t dyn_get(unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k)
{
    uint32_t	tempbits = *bitPos;
    uint32_t		result;
    uint32_t		pre = 0, v;
    uint32_t		streamlong;

	streamlong = read32bit( in + (tempbits >> 3) );
    streamlong <<= (tempbits & 7);

    /* find the number of bits in the prefix */ 
    {
        uint32_t	notI = ~streamlong;
    	pre = lead( notI);
    }

    if(pre >= MAX_PREFIX_16)
    {
        pre = MAX_PREFIX_16;
        tempbits += pre;
        streamlong <<= pre;
        result = get_next_fromlong(streamlong,MAX_DATATYPE_BITS_16);
        tempbits += MAX_DATATYPE_BITS_16;

    }
    else
    {
        // all of the bits must fit within the long we have loaded
        //Assert(pre+1+k <= 32);

        tempbits += pre;
        tempbits += 1;
        streamlong <<= pre+1;
        v = get_next_fromlong(streamlong, k);
        tempbits += k;
    
        result = pre*m + v-1;

        if(v<2) {
            result -= (v-1);
            tempbits -= 1;
        }
    }

    *bitPos = tempbits;
    return result;
}


static inline int32_t dyn_get_32bit( uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits )
{
	uint32_t	tempbits = *bitPos;
	uint32_t		v;
	uint32_t		streamlong;
	uint32_t		result;
	
	streamlong = read32bit( in + (tempbits >> 3) );
	streamlong <<= (tempbits & 7);

	/* find the number of bits in the prefix */ 
	{
		uint32_t notI = ~streamlong;
		result = lead( notI);
	}
	
	if(result >= MAX_PREFIX_32)
	{
		result = getstreambits(in, tempbits+MAX_PREFIX_32, maxbits);
		tempbits += MAX_PREFIX_32 + maxbits;
	}
	else
	{		
		/* all of the bits must fit within the long we have loaded*/
		//Assert(k<=14);
		//Assert(result<MAX_PREFIX_32);
		//Assert(result+1+k <= 32);
		
		tempbits += result;
		tempbits += 1;
		
		if (k != 1)
		{
			streamlong <<= result+1;
			v = get_next_fromlong(streamlong, k);
			tempbits += k;
			tempbits -= 1;
			result = result*m;
			
			if(v>=2)
			{
				result += (v-1);
				tempbits += 1;
			}
		}
	}

	*bitPos = tempbits;

	return result;
}

int32_t dyn_decomp( AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits )
{
    uint8_t 		*in;
    int32_t			*outPtr = pc;
    uint32_t 	bitPos, startPos, maxPos;
    uint32_t		j, m, k, n, c, mz;
    int32_t			del, zmode;
    uint32_t 	mb;
    uint32_t	pb_local = params->pb;
    uint32_t	kb_local = params->kb;
    uint32_t	wb_local = params->wb;
    int32_t				status;

	RequireAction( (bitstream != nil) && (pc != nil) && (outNumBits != nil), return kALAC_ParamError; );
	*outNumBits = 0;

	in = bitstream->cur;
	startPos = bitstream->bitIndex;
	maxPos = bitstream->byteSize * 8;
	bitPos = startPos;

    mb = params->mb0;
    zmode = 0;

    c = 0;
	status = ALAC_noErr;

    while (c < numSamples)
    {
		// bail if we've run off the end of the buffer
    	RequireAction( bitPos < maxPos, status = kALAC_ParamError; goto Exit; );

        m = (mb)>>QBSHIFT;
        k = lg3a(m);

        k = arithmin(k, kb_local);
        m = (1<<k)-1;
        
		n = dyn_get_32bit( in, &bitPos, m, k, maxSize );

        // least significant bit is sign bit
        {
        	uint32_t	ndecode = n + zmode;
            int32_t		multiplier = (- (ndecode&1));

            multiplier |= 1;
            del = ((ndecode+1) >> 1) * (multiplier);
        }

        *outPtr++ = del;

        c++;

        mb = pb_local*(n+zmode) + mb - ((pb_local*mb)>>QBSHIFT);

		// update mean tracking
		if (n > N_MAX_MEAN_CLAMP)
			mb = N_MEAN_CLAMP_VAL;

        zmode = 0;

        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
        {
            zmode = 1;
            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
            mz = ((1<<k)-1) & wb_local;

            n = dyn_get(in, &bitPos, mz, k);

            RequireAction(c+n <= numSamples, status = kALAC_ParamError; goto Exit; );

            for(j=0; j < n; j++)
            {
                *outPtr++ = 0;
                ++c;                    
            }

            if(n >= 65535)
            	zmode = 0;

            mb = 0;
        }
    }

Exit:
	*outNumBits = (bitPos - startPos);
	BitBufferAdvance( bitstream, *outNumBits );
	RequireAction( bitstream->cur <= bitstream->end, status = kALAC_ParamError; );

    return status;
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		ag_enc.c
	
	Contains:   Adaptive Golomb encode routines.

	Copyright:	(c) 2001-2011 Apple, Inc.
*/

#include "aglib.h"
#include "ALACBitUtilities.h"
#include "EndianPortable.h"
#include "ALACAudioTypes.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

#define CODE_TO_LONG_MAXBITS	32
#define N_MAX_MEAN_CLAMP		0xffff
#define N_MEAN_CLAMP_VAL		0xffff
#define REPORT_VAL  40

#if __GNUC__
#define ALWAYS_INLINE		__attribute__((always_inline))
#else
#define ALWAYS_INLINE
#endif


/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
	if it is ugly but the performance gains are well worth it.
	- WSK 5/19/04
*/

// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
static inline int32_t lead( int32_t m )
{
	long j;
	unsigned long c = (1ul << 31);

	for(j=0; j < 32; j++)
	{
		if((c & m) != 0)
			break;
		c >>= 1;
	}
	return (j);
}

#define arithmin(a, b) ((a) < (b) ? (a) : (b))

static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
{
    int32_t result;

    x += 3;
    result = lead(x);

    return 31 - result;
}

static inline int32_t ALWAYS_INLINE abs_func( int32_t a )
{
	// note: the CW PPC intrinsic __abs() turns into these instructions so no need to try and use it
	int32_t isneg  = a >> 31;
	int32_t xorval = a ^ isneg;
	int32_t result = xorval-isneg;
	
	return result;	
}

static inline uint32_t ALWAYS_INLINE unaligned_read32_be(const uint8_t *buffer)
{
	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
	uint32_t		value;
	
	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
	return value;
}

static inline void ALWAYS_INLINE unaligned_write32_be(uint8_t *buffer, uint32_t value)
{
	buffer[0] = value >> 24;
	buffer[1] = (value >> 16) & 0xff;
	buffer[2] = (value >> 8) & 0xff;
	buffer[3] = value & 0xff;
}

#if PRAGMA_MARK
#pragma mark -
#endif

static inline int32_t dyn_code(int32_t m, int32_t k, int32_t n, uint32_t *outNumBits)
{
	uint32_t 	div, mod, de;
	uint32_t	numBits;
	uint32_t	value;

	//Assert( n >= 0 );

	div = n/m;

	if(div >= MAX_PREFIX_16)
	{
		numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
		value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;
	}
	else
	{
		mod = n%m;
		de = (mod == 0);
		numBits = div + k + 1 - de;
		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;

		// if coding this way is bigger than doing escape, then do escape
		if (numBits > MAX_PREFIX_16 + MAX_DATATYPE_BITS_16)
		{
		    numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
		    value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;            
		}
	}
	
	*outNumBits = numBits;

	return (int32_t) value;
}


static inline int32_t dyn_code_32bit(int32_t maxbits, uint32_t m, uint32_t k, uint32_t n, uint32_t *outNumBits, uint32_t *outValue, uint32_t *overflow, uint32_t *overflowbits)
{
	uint32_t 	div, mod, de;
	uint32_t	numBits;
	uint32_t	value;
	int32_t			didOverflow = 0;

	div = n/m;

	if (div < MAX_PREFIX_32)
	{
		mod = n - (m * div);

		de = (mod == 0);
		numBits = div + k + 1 - de;
		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;		
		if (numBits > 25)
			goto codeasescape;
	}
	else
	{
codeasescape:
		numBits = MAX_PREFIX_32;
		value = (((1<<MAX_PREFIX_32)-1));
		*overflow = n;
		*overflowbits = maxbits;
		didOverflow = 1;
	}
	
	*outNumBits = numBits;
	*outValue = value;

	return didOverflow;
}


static inline void ALWAYS_INLINE dyn_jam_noDeref(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
{
	uint8_t		*i = out + (bitPos >> 3);
	uint32_t	mask;
	uint32_t	curr;
	uint32_t	shift;

	//Assert( numBits <= 32 );

	curr = unaligned_read32_be(i);

	shift = 32 - (bitPos & 7) - numBits;

	mask = ~0u >> (32 - numBits);		// mask must be created in two steps to avoid compiler sequencing ambiguity
	mask <<= shift;

	value  = (value << shift) & mask;
	value |= curr & ~mask;
	
	unaligned_write32_be(i, value);
}


static inline void ALWAYS_INLINE dyn_jam_noDeref_large(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
{
	uint8_t		*i = out + (bitPos>>3);
	uint32_t	w;
	uint32_t	curr;
	uint32_t	mask;
	int32_t			shiftvalue = (32 - (bitPos&7) - numBits);
	
	//Assert(numBits <= 32);

	curr = unaligned_read32_be(i);

	if (shiftvalue < 0)
	{
		uint8_t 	tailbyte;
		uint8_t 	*tailptr;

		w = value >> -shiftvalue;
		mask = ~0u >> -shiftvalue;
		w |= (curr & ~mask);

		tailptr = i + 4;
		tailbyte = (value << ((8+shiftvalue))) & 0xff;
		*tailptr = (uint8_t)tailbyte;
	}
	else
	{
		mask = ~0u >> (32 - numBits);
		mask <<= shiftvalue;			// mask must be created in two steps to avoid compiler sequencing ambiguity

		w  = (value << shiftvalue) & mask;
		w |= curr & ~mask;
	}
	
	unaligned_write32_be(i, w);
}


int32_t dyn_comp( AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits )
{
    unsigned char *		out;
    uint32_t		bitPos, startPos;
    uint32_t			m, k, n, c, mz, nz;
    uint32_t		numBits;
    uint32_t			value;
    int32_t				del, zmode;
	uint32_t		overflow, overflowbits;
    int32_t					status;

    // shadow the variables in params so there's not the dereferencing overhead
    uint32_t		mb, pb, kb, wb;
    int32_t					rowPos = 0;
    int32_t					rowSize = params->sw;
    int32_t					rowJump = (params->fw) - rowSize;
    int32_t *			inPtr = pc;

	*outNumBits = 0;
	RequireAction( (bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError; );

	out = bitstream->cur;
	startPos = bitstream->bitIndex;
    bitPos = startPos;

    mb = params->mb = params->mb0;
    pb = params->pb;
    kb = params->kb;
    wb = params->wb;
    zmode = 0;

    c=0;
	status = ALAC_noErr;

    while (c < numSamples)
    {
        m  = mb >> QBSHIFT;
        k = lg3a(m);
        if ( k > kb)
        {
        	k = kb;
        }
        m = (1<<k)-1;

        del = *inPtr++;
        rowPos++;

        n = (abs_func(del) << 1) - ((del >> 31) & 1) - zmode;
		//Assert( 32-lead(n) <= bitSize );

		if ( dyn_code_32bit(bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits) )
		{
			dyn_jam_noDeref(out, bitPos, numBits, value);
			bitPos += numBits;			
			dyn_jam_noDeref_large(out, bitPos, overflowbits, overflow);			
			bitPos += overflowbits;
		}
		else
		{
			dyn_jam_noDeref(out, bitPos, numBits, value);
			bitPos += numBits;
		}
      
        c++;
        if ( rowPos >= rowSize)
        {
        	rowPos = 0;
        	inPtr += rowJump;
        }

        mb = pb * (n + zmode) + mb - ((pb *mb)>>QBSHIFT);

		// update mean tracking if it's overflowed
		if (n > N_MAX_MEAN_CLAMP)
			mb = N_MEAN_CLAMP_VAL;

        zmode = 0;

        RequireAction(c <= numSamples, status = kALAC_ParamError; goto Exit; );

        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
        {
            zmode = 1;
            nz = 0;

            while(c<numSamples && *inPtr == 0)
            {
            	/* Take care of wrap-around globals. */
                ++inPtr;
                ++nz;
                ++c;
                if ( ++rowPos >= rowSize)
                {
                	rowPos = 0;
                	inPtr += rowJump;
                }

                if(nz >= 65535)
                {
                	zmode = 0;
                	break;
                }
            }

            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
            mz = ((1<<k)-1) & wb;

            value = dyn_code(mz, k, nz, &numBits);
            dyn_jam_noDeref(out, bitPos, numBits, value);
            bitPos += numBits;

            mb = 0;
        }
    }

    *outNumBits = (bitPos - startPos);
	BitBufferAdvance( bitstream, *outNumBits );

Exit:
	return status;
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		aglib.h
	
	Copyright:	(C) 2001-2011 Apple, Inc.
*/

#ifndef AGLIB_H
#define AGLIB_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define QBSHIFT 9
#define QB (1<<QBSHIFT)
#define PB0 40
#define MB0 10
#define KB0 14
#define MAX_RUN_DEFAULT 255

#define MMULSHIFT 2
#define MDENSHIFT (QBSHIFT - MMULSHIFT - 1)
#define MOFF ((1<<(MDENSHIFT-2)))

#define BITOFF 24

/* Max. prefix of 1's. */
#define MAX_PREFIX_16			9
#define MAX_PREFIX_TOLONG_16	15
#define MAX_PREFIX_32			9

/* Max. bits in 16-bit data type */
#define MAX_DATATYPE_BITS_16	16

typedef struct AGParamRec
{
    uint32_t mb, mb0, pb, kb, wb, qb;
    uint32_t fw, sw;

    uint32_t maxrun;

    // fw = 1, sw = 1;

} AGParamRec, *AGParamRecPtr;

struct BitBuffer;

void	set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth);
void	set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun);

int32_t		dyn_comp(AGParamRecPtr params, int32_t * pc, struct BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits);
int32_t		dyn_decomp(AGParamRecPtr params, struct BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits);


#ifdef __cplusplus
}
#endif

#endif //#ifndef AGLIB_H
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		dp_dec.c

	Contains:	Dynamic Predictor decode routines

	Copyright:	(c) 2001-2011 Apple, Inc.
*/


#include "dplib.h"
#include <string.h>

#if __GNUC__
#define ALWAYS_INLINE		__attribute__((always_inline))
#else
#define ALWAYS_INLINE
#endif

#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
// align loops to a 16 byte boundary to make the G5 happy
#pragma function_align 16
#define LOOP_ALIGN			asm { align 16 }
#else
#define LOOP_ALIGN
#endif

static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
{
    int32_t negishift;
	
    negishift = ((uint32_t)-i) >> 31;
    return negishift | (i >> 31);
}

void unpc_block( int32_t * pc1, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
{
	register int16_t	a0, a1, a2, a3;
	register int32_t	b0, b1, b2, b3;
	int32_t					j, k, lim;
	int32_t				sum1, sg, sgn, top, dd;
	int32_t *			pout;
	int32_t				del, del0;
	uint32_t			chanshift = 32 - chanbits;
	int32_t				denhalf = 1<<(denshift-1);

	out[0] = pc1[0];
	if ( numactive == 0 )
	{
		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
		if ( (num > 1)  && (pc1 != out) )
			memcpy( &out[1], &pc1[1], (num - 1) * sizeof(int32_t) );
		return;
	}
	if ( numactive == 31 )
	{
		// short-circuit if numactive == 31
		int32_t		prev;
		
		/*	this code is written such that the in/out buffers can be the same
			to conserve buffer space on embedded devices like the iPod
			
			(original code)
			for ( j = 1; j < num; j++ )
				del = pc1[j] + out[j-1];
				out[j] = (del << chanshift) >> chanshift;
		*/
		prev = out[0];
		for ( j = 1; j < num; j++ )
		{
			del = pc1[j] + prev;
			prev = (del << chanshift) >> chanshift;
			out[j] = prev;
		}
		return;
	}

	for ( j = 1; j <= numactive; j++ )
	{
		del = pc1[j] + out[j-1];
		out[j] = (del << chanshift) >> chanshift;
	}

	lim = numactive + 1;

	if ( numactive == 4 )
	{
		// optimization for numactive == 4
		register int16_t	a0, a1, a2, a3;
		register int32_t	b0, b1, b2, b3;

		a0 = coefs[0];
		a1 = coefs[1];
		a2 = coefs[2];
		a3 = coefs[3];

		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			top = out[j - lim];
			pout = out + j - 1;

			b0 = top - pout[0];
			b1 = top - pout[-1];
			b2 = top - pout[-2];
			b3 = top - pout[-3];

			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;

			del = pc1[j];
			del0 = del;
			sg = sign_of_int(del);
			del += top + sum1;

			out[j] = (del << chanshift) >> chanshift;

			if ( sg > 0 )
			{
				sgn = sign_of_int( b3 );
				a3 -= sgn;
				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b2 );
				a2 -= sgn;
				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b1 );
				a1 -= sgn;
				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
				if ( del0 <= 0 )
					continue;

				a0 -= sign_of_int( b0 );
			}
			else if ( sg < 0 )
			{
				// note: to avoid unnecessary negations, we flip the value of "sgn"
				sgn = -sign_of_int( b3 );
				a3 -= sgn;
				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b2 );
				a2 -= sgn;
				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b1 );
				a1 -= sgn;
				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
				if ( del0 >= 0 )
					continue;

				a0 += sign_of_int( b0 );
			}
		}

		coefs[0] = a0;
		coefs[1] = a1;
		coefs[2] = a2;
		coefs[3] = a3;
	}
	else if ( numactive == 8 )
	{
		register int16_t	a4, a5, a6, a7;
		register int32_t	b4, b5, b6, b7;

		// optimization for numactive == 8
		a0 = coefs[0];
		a1 = coefs[1];
		a2 = coefs[2];
		a3 = coefs[3];
		a4 = coefs[4];
		a5 = coefs[5];
		a6 = coefs[6];
		a7 = coefs[7];

		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			top = out[j - lim];
			pout = out + j - 1;

			b0 = top - (*pout--);
			b1 = top - (*pout--);
			b2 = top - (*pout--);
			b3 = top - (*pout--);
			b4 = top - (*pout--);
			b5 = top - (*pout--);
			b6 = top - (*pout--);
			b7 = top - (*pout);
			pout += 8;

			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;

			del = pc1[j];
			del0 = del;
			sg = sign_of_int(del);
			del += top + sum1;

			out[j] = (del << chanshift) >> chanshift;

			if ( sg > 0 )
			{
				sgn = sign_of_int( b7 );
				a7 -= sgn;
				del0 -= 1 * ((sgn * b7) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b6 );
				a6 -= sgn;
				del0 -= 2 * ((sgn * b6) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b5 );
				a5 -= sgn;
				del0 -= 3 * ((sgn * b5) >> denshift);
				if ( del0 <= 0 )
					continue;

				sgn = sign_of_int( b4 );
				a4 -= sgn;
				del0 -= 4 * ((sgn * b4) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b3 );
				a3 -= sgn;
				del0 -= 5 * ((sgn * b3) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b2 );
				a2 -= sgn;
				del0 -= 6 * ((sgn * b2) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b1 );
				a1 -= sgn;
				del0 -= 7 * ((sgn * b1) >> denshift);
				if ( del0 <= 0 )
					continue;

				a0 -= sign_of_int( b0 );
			}
			else if ( sg < 0 )
			{
				// note: to avoid unnecessary negations, we flip the value of "sgn"
				sgn = -sign_of_int( b7 );
				a7 -= sgn;
				del0 -= 1 * ((sgn * b7) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b6 );
				a6 -= sgn;
				del0 -= 2 * ((sgn * b6) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b5 );
				a5 -= sgn;
				del0 -= 3 * ((sgn * b5) >> denshift);
				if ( del0 >= 0 )
					continue;

				sgn = -sign_of_int( b4 );
				a4 -= sgn;
				del0 -= 4 * ((sgn * b4) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b3 );
				a3 -= sgn;
				del0 -= 5 * ((sgn * b3) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b2 );
				a2 -= sgn;
				del0 -= 6 * ((sgn * b2) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b1 );
				a1 -= sgn;
				del0 -= 7 * ((sgn * b1) >> denshift);
				if ( del0 >= 0 )
					continue;

				a0 += sign_of_int( b0 );
			}
		}

		coefs[0] = a0;
		coefs[1] = a1;
		coefs[2] = a2;
		coefs[3] = a3;
		coefs[4] = a4;
		coefs[5] = a5;
		coefs[6] = a6;
		coefs[7] = a7;
	}
	else
	{
		// general case
		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			sum1 = 0;
			pout = out + j - 1;
			top = out[j-lim];

			for ( k = 0; k < numactive; k++ )
				sum1 += coefs[k] * (pout[-k] - top);

			del = pc1[j];
			del0 = del;
			sg = sign_of_int( del );
			del += top + ((sum1 + denhalf) >> denshift);
			out[j] = (del << chanshift) >> chanshift;

			if ( sg > 0 )
			{
				for ( k = (numactive - 1); k >= 0; k-- )
				{
					dd = top - pout[-k];
					sgn = sign_of_int( dd );
					coefs[k] -= sgn;
					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
					if ( del0 <= 0 )
						break;
				}
			}
			else if ( sg < 0 )
			{
				for ( k = (numactive - 1); k >= 0; k-- )
				{
					dd = top - pout[-k];
					sgn = sign_of_int( dd );
					coefs[k] += sgn;
					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
					if ( del0 >= 0 )
						break;
				}
			}
		}
	}
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		dp_enc.c

	Contains:	Dynamic Predictor encode routines

	Copyright:	(c) 2001-2011 Apple, Inc.
*/

#include "dplib.h"
#include <string.h>

#if __GNUC__
#define ALWAYS_INLINE		__attribute__((always_inline))
#else
#define ALWAYS_INLINE
#endif

#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
// align loops to a 16 byte boundary to make the G5 happy
#pragma function_align 16
#define LOOP_ALIGN			asm { align 16 }
#else
#define LOOP_ALIGN
#endif

void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs )
{
	int32_t		k;
	int32_t		den = 1 << denshift;

	coefs[0] = (AINIT * den) >> 4;
	coefs[1] = (BINIT * den) >> 4;
	coefs[2] = (CINIT * den) >> 4;
	for ( k = 3; k < numPairs; k++ )
		coefs[k]  = 0;
}

void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs )
{
	int32_t k;

	for ( k = 0; k < numPairs; k++ )
		dstCoefs[k] = srcCoefs[k];
}

static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
{
    int32_t negishift;
	
    negishift = ((uint32_t)-i) >> 31;
    return negishift | (i >> 31);
}

void pc_block( int32_t * in, int32_t * pc1, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
{
	register int16_t	a0, a1, a2, a3;
	register int32_t	b0, b1, b2, b3;
	int32_t					j, k, lim;
	int32_t *			pin;
	int32_t				sum1, dd;
	int32_t				sg, sgn;
	int32_t				top;
	int32_t				del, del0;
	uint32_t			chanshift = 32 - chanbits;
	int32_t				denhalf = 1 << (denshift - 1);

	pc1[0] = in[0];
	if ( numactive == 0 )
	{
		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
		if ( (num > 1) && (in != pc1) )
			memcpy( &pc1[1], &in[1], (num - 1) * sizeof(int32_t) );
		return;
	}
	if ( numactive == 31 )
	{
		// short-circuit if numactive == 31
		for( j = 1; j < num; j++ )
		{
			del = in[j] - in[j-1];
			pc1[j] = (del << chanshift) >> chanshift;
		}
		return;
	}
	
	for ( j = 1; j <= numactive; j++ )
	{
		del = in[j] - in[j-1];
		pc1[j] = (del << chanshift) >> chanshift;
	}

	lim = numactive + 1;

	if ( numactive == 4 )
	{
		// optimization for numactive == 4
		a0 = coefs[0];
		a1 = coefs[1];
		a2 = coefs[2];
		a3 = coefs[3];

		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			top = in[j - lim];
			pin = in + j - 1;

			b0 = top - pin[0];
			b1 = top - pin[-1];
			b2 = top - pin[-2];
			b3 = top - pin[-3];

			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;

			del = in[j] - top - sum1;
			del = (del << chanshift) >> chanshift;
			pc1[j] = del;	     
			del0 = del;

			sg = sign_of_int(del);
			if ( sg > 0 )
			{
				sgn = sign_of_int( b3 );
				a3 -= sgn;
				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b2 );
				a2 -= sgn;
				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b1 );
				a1 -= sgn;
				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
				if ( del0 <= 0 )
					continue;

				a0 -= sign_of_int( b0 );
			}
			else if ( sg < 0 )
			{
				// note: to avoid unnecessary negations, we flip the value of "sgn"
				sgn = -sign_of_int( b3 );
				a3 -= sgn;
				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b2 );
				a2 -= sgn;
				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b1 );
				a1 -= sgn;
				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
				if ( del0 >= 0 )
					continue;

				a0 += sign_of_int( b0 );
			}
		}

		coefs[0] = a0;
		coefs[1] = a1;
		coefs[2] = a2;
		coefs[3] = a3;
	}
	else if ( numactive == 8 )
	{
		// optimization for numactive == 8
		register int16_t	a4, a5, a6, a7;
		register int32_t	b4, b5, b6, b7;

		a0 = coefs[0];
		a1 = coefs[1];
		a2 = coefs[2];
		a3 = coefs[3];
		a4 = coefs[4];
		a5 = coefs[5];
		a6 = coefs[6];
		a7 = coefs[7];

		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			top = in[j - lim];
			pin = in + j - 1;

			b0 = top - (*pin--);
			b1 = top - (*pin--);
			b2 = top - (*pin--);
			b3 = top - (*pin--);
			b4 = top - (*pin--);
			b5 = top - (*pin--);
			b6 = top - (*pin--);
			b7 = top - (*pin);
			pin += 8;

			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;

			del = in[j] - top - sum1;
			del = (del << chanshift) >> chanshift;
			pc1[j] = del;	     
			del0 = del;

			sg = sign_of_int(del);
			if ( sg > 0 )
			{
				sgn = sign_of_int( b7 );
				a7 -= sgn;
				del0 -= 1 * ((sgn * b7) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b6 );
				a6 -= sgn;
				del0 -= 2 * ((sgn * b6) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b5 );
				a5 -= sgn;
				del0 -= 3 * ((sgn * b5) >> denshift);
				if ( del0 <= 0 )
					continue;

				sgn = sign_of_int( b4 );
				a4 -= sgn;
				del0 -= 4 * ((sgn * b4) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b3 );
				a3 -= sgn;
				del0 -= 5 * ((sgn * b3) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b2 );
				a2 -= sgn;
				del0 -= 6 * ((sgn * b2) >> denshift);
				if ( del0 <= 0 )
					continue;
				
				sgn = sign_of_int( b1 );
				a1 -= sgn;
				del0 -= 7 * ((sgn * b1) >> denshift);
				if ( del0 <= 0 )
					continue;

				a0 -= sign_of_int( b0 );
			}
			else if ( sg < 0 )
			{
				// note: to avoid unnecessary negations, we flip the value of "sgn"
				sgn = -sign_of_int( b7 );
				a7 -= sgn;
				del0 -= 1 * ((sgn * b7) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b6 );
				a6 -= sgn;
				del0 -= 2 * ((sgn * b6) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b5 );
				a5 -= sgn;
				del0 -= 3 * ((sgn * b5) >> denshift);
				if ( del0 >= 0 )
					continue;

				sgn = -sign_of_int( b4 );
				a4 -= sgn;
				del0 -= 4 * ((sgn * b4) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b3 );
				a3 -= sgn;
				del0 -= 5 * ((sgn * b3) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b2 );
				a2 -= sgn;
				del0 -= 6 * ((sgn * b2) >> denshift);
				if ( del0 >= 0 )
					continue;
				
				sgn = -sign_of_int( b1 );
				a1 -= sgn;
				del0 -= 7 * ((sgn * b1) >> denshift);
				if ( del0 >= 0 )
					continue;

				a0 += sign_of_int( b0 );
			}
		}

		coefs[0] = a0;
		coefs[1] = a1;
		coefs[2] = a2;
		coefs[3] = a3;
		coefs[4] = a4;
		coefs[5] = a5;
		coefs[6] = a6;
		coefs[7] = a7;
	}
	else
	{
//pc_block_general:
		// general case
		for ( j = lim; j < num; j++ )
		{
			LOOP_ALIGN

			top = in[j - lim];
			pin = in + j - 1;

			sum1 = 0;
			for ( k = 0; k < numactive; k++ )
				sum1 -= coefs[k] * (top - pin[-k]);
		
			del = in[j] - top - ((sum1 + denhalf) >> denshift);
			del = (del << chanshift) >> chanshift;
			pc1[j] = del;
			del0 = del;

			sg = sign_of_int( del );
			if ( sg > 0 )
			{
				for ( k = (numactive - 1); k >= 0; k-- )
				{
					dd = top - pin[-k];
					sgn = sign_of_int( dd );
					coefs[k] -= sgn;
					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
					if ( del0 <= 0 )
						break;
				}
			}
			else if ( sg < 0 )
			{
				for ( k = (numactive - 1); k >= 0; k-- )
				{
					dd = top - pin[-k];
					sgn = sign_of_int( dd );
					coefs[k] += sgn;
					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
					if ( del0 >= 0 )
						break;
				}
			}
		}
	}
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		dplib.h
	
	Contains:	Dynamic Predictor routines

	Copyright:	Copyright (C) 2001-2011 Apple, Inc.
*/

#ifndef __DPLIB_H__
#define __DPLIB_H__

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// defines

#define DENSHIFT_MAX  15
#define DENSHIFT_DEFAULT 9
#define AINIT 38
#define BINIT (-29)
#define CINIT (-2)
#define NUMCOEPAIRS 16

// prototypes

void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs );
void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs );

// NOTE: these routines read at least "numactive" samples so the i/o buffers must be at least that big

void pc_block( int32_t * in, int32_t * pc, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );
void unpc_block( int32_t * pc, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );

#ifdef __cplusplus
}
#endif

#endif	/* __DPLIB_H__ */
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		matrix_dec.c
	
	Contains:	ALAC mixing/matrixing decode routines.

	Copyright:	(c) 2004-2011 Apple, Inc.
*/

#include "matrixlib.h"
#include "ALACAudioTypes.h"

// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
#if TARGET_RT_BIG_ENDIAN
	#define LBYTE	2
	#define MBYTE	1
	#define HBYTE	0
#else
	#define LBYTE	0
	#define MBYTE	1
	#define HBYTE	2
#endif

/*
    There is no plain middle-side option; instead there are various mixing
    modes including middle-side, each lossless, as embodied in the mix()
    and unmix() functions.  These functions exploit a generalized middle-side
    transformation:
    
    u := [(rL + (m-r)R)/m];
    v := L - R;
    
    where [ ] denotes integer floor.  The (lossless) inverse is
    
    L = u + v - [rV/m];
    R = L - v;
*/

// 16-bit routines

void unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
{
	int16_t *	op = out;
	int32_t 		j;

	if ( mixres != 0 )
	{
		/* matrixed stereo */
		for ( j = 0; j < numSamples; j++ )
		{
			int32_t		l, r;

			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
			r = l - v[j];

			op[0] = (int16_t) l;
			op[1] = (int16_t) r;
			op += stride;
		} 
	}
	else
	{
		/* Conventional separated stereo. */
		for ( j = 0; j < numSamples; j++ )
		{
			op[0] = (int16_t) u[j];
			op[1] = (int16_t) v[j];
			op += stride;
		}
	}
}

// 20-bit routines
// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers

void unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
{
	uint8_t *	op = out;
	int32_t 		j;

	if ( mixres != 0 )
	{
		/* matrixed stereo */
		for ( j = 0; j < numSamples; j++ )
		{
			int32_t		l, r;

			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
			r = l - v[j];

			l <<= 4;
			r <<= 4;

			op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
			op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
			op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
			op += 3;

			op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
			op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
			op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);

			op += (stride - 1) * 3;
		}
	}
	else 
	{
		/* Conventional separated stereo. */
		for ( j = 0; j < numSamples; j++ )
		{
			int32_t		val;

			val = u[j] << 4;
			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
			op += 3;

			val = v[j] << 4;
			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);

			op += (stride - 1) * 3;
		}
	}
}

// 24-bit routines
// - the 24 bits of data are right-justified in the input/output predictor buffers

void unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
{
	uint8_t *	op = out;
	int32_t			shift = bytesShifted * 8;
	int32_t		l, r;
	int32_t 		j, k;

	if ( mixres != 0 )
	{
		/* matrixed stereo */
		if ( bytesShifted != 0 )
		{
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
				r = l - v[j];

				l = (l << shift) | (uint32_t) shiftUV[k + 0];
				r = (r << shift) | (uint32_t) shiftUV[k + 1];

				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
				op += 3;

				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);

				op += (stride - 1) * 3;
			}
		}
		else
		{
			for ( j = 0; j < numSamples; j++ )
			{
				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
				r = l - v[j];

				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
				op += 3;

				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);

				op += (stride - 1) * 3;
			}
		}
	}
	else 
	{
		/* Conventional separated stereo. */
		if ( bytesShifted != 0 )
		{
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				l = u[j];
				r = v[j];

				l = (l << shift) | (uint32_t) shiftUV[k + 0];
				r = (r << shift) | (uint32_t) shiftUV[k + 1];

				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
				op += 3;

				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);

				op += (stride - 1) * 3;
			}
		}
		else
		{
			for ( j = 0; j < numSamples; j++ )
			{
				int32_t		val;

				val = u[j];
				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
				op += 3;

				val = v[j];
				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);

				op += (stride - 1) * 3;
			}
		}
	}
}

// 32-bit routines
// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
// - otherwise, the calculations might overflow into the 33rd bit and be lost
// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers

void unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
{
	int32_t *	op = out;
	int32_t			shift = bytesShifted * 8;
	int32_t		l, r;
	int32_t 		j, k;

	if ( mixres != 0 )
	{
		//Assert( bytesShifted != 0 );

		/* matrixed stereo with shift */
		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
		{
			int32_t		lt, rt;

			lt = u[j];
			rt = v[j];
			
			l = lt + rt - ((mixres * rt) >> mixbits);
			r = l - rt;

			op[0] = (l << shift) | (uint32_t) shiftUV[k + 0];
			op[1] = (r << shift) | (uint32_t) shiftUV[k + 1];
			op += stride;
		} 
	}
	else
	{
		if ( bytesShifted == 0 )
		{
			/* interleaving w/o shift */
			for ( j = 0; j < numSamples; j++ )
			{
				op[0] = u[j];
				op[1] = v[j];
				op += stride;
			}
		}
		else
		{
			/* interleaving with shift */
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				op[0] = (u[j] << shift) | (uint32_t) shiftUV[k + 0];
				op[1] = (v[j] << shift) | (uint32_t) shiftUV[k + 1];
				op += stride;
			}
		}
	}
}

// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)

void copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
{
	uint8_t *	op = out;
	int32_t			j;

	for ( j = 0; j < numSamples; j++ )
	{
		int32_t		val = in[j];

		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
		op += (stride * 3);
	}
}

void copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
{
	uint8_t *	op = out;
	int32_t			shiftVal = bytesShifted * 8;
	int32_t			j;

	//Assert( bytesShifted != 0 );

	for ( j = 0; j < numSamples; j++ )
	{
		int32_t		val = in[j];

		val = (val << shiftVal) | (uint32_t) shift[j];

		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
		op += (stride * 3);
	}
}

void copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
{
	uint8_t *	op = out;
	int32_t			j;

	// 32-bit predictor values are right-aligned but 20-bit output values should be left-aligned
	// in the 24-bit output buffer
	for ( j = 0; j < numSamples; j++ )
	{
		int32_t		val = in[j];

		op[HBYTE] = (uint8_t)((val >> 12) & 0xffu);
		op[MBYTE] = (uint8_t)((val >>  4) & 0xffu);
		op[LBYTE] = (uint8_t)((val <<  4) & 0xffu);
		op += (stride * 3);
	}
}

void copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples )
{
	int32_t			i, j;

	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
	for ( i = 0, j = 0; i < numSamples; i++, j += stride )
		out[j] = in[i];
}

void copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
{
	int32_t *		op = out;
	uint32_t		shiftVal = bytesShifted * 8;
	int32_t				j;

	//Assert( bytesShifted != 0 );

	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
	for ( j = 0; j < numSamples; j++ )
	{
		op[0] = (in[j] << shiftVal) | (uint32_t) shift[j];
		op += stride;
	}
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		matrix_enc.c
	
	Contains:	ALAC mixing/matrixing encode routines.

	Copyright:	(c) 2004-2011 Apple, Inc.
*/

#include "matrixlib.h"
#include "ALACAudioTypes.h"

// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
#if TARGET_RT_BIG_ENDIAN
	#define LBYTE	2
	#define MBYTE	1
	#define HBYTE	0
#else
	#define LBYTE	0
	#define MBYTE	1
	#define HBYTE	2
#endif

/*
    There is no plain middle-side option; instead there are various mixing
    modes including middle-side, each lossless, as embodied in the mix()
    and unmix() functions.  These functions exploit a generalized middle-side
    transformation:
    
    u := [(rL + (m-r)R)/m];
    v := L - R;
    
    where [ ] denotes integer floor.  The (lossless) inverse is
    
    L = u + v - [rV/m];
    R = L - v;
*/

// 16-bit routines

void mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
{
	int16_t	*	ip = in;
	int32_t			j;

	if ( mixres != 0 )
	{
		int32_t		mod = 1 << mixbits;
		int32_t		m2;

		/* matrixed stereo */
		m2 = mod - mixres;
		for ( j = 0; j < numSamples; j++ )
		{
			int32_t		l, r;

			l = (int32_t) ip[0];
			r = (int32_t) ip[1];
			ip += stride;
			u[j] = (mixres * l + m2 * r) >> mixbits;
			v[j] = l - r;
		}
	}
	else
	{
		/* Conventional separated stereo. */
		for ( j = 0; j < numSamples; j++ )
		{
			u[j] = (int32_t) ip[0];
			v[j] = (int32_t) ip[1];
			ip += stride;
		}
	}
}

// 20-bit routines
// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers

void mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
{
	int32_t		l, r;
	uint8_t *	ip = in;
	int32_t			j;

	if ( mixres != 0 )
	{
		/* matrixed stereo */
		int32_t		mod = 1 << mixbits;
		int32_t		m2 = mod - mixres;

		for ( j = 0; j < numSamples; j++ )
		{
			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
			l = (l << 8) >> 12;
			ip += 3;

			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
			r = (r << 8) >> 12;
			ip += (stride - 1) * 3;

			u[j] = (mixres * l + m2 * r) >> mixbits;
			v[j] = l - r;
		} 
	}
	else
	{
		/* Conventional separated stereo. */
		for ( j = 0; j < numSamples; j++ )
		{
			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
			u[j] = (l << 8) >> 12;
			ip += 3;

			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
			v[j] = (r << 8) >> 12;
			ip += (stride - 1) * 3;
		}
	}
}

// 24-bit routines
// - the 24 bits of data are right-justified in the input/output predictor buffers

void mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
{	
	int32_t		l, r;
	uint8_t *	ip = in;
	int32_t			shift = bytesShifted * 8;
	uint32_t	mask  = (1ul << shift) - 1;
	int32_t			j, k;

	if ( mixres != 0 )
	{
		/* matrixed stereo */
		int32_t		mod = 1 << mixbits;
		int32_t		m2 = mod - mixres;

		if ( bytesShifted != 0 )
		{
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				l = (l << 8) >> 8;
				ip += 3;

				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				r = (r << 8) >> 8;
				ip += (stride - 1) * 3;

				shiftUV[k + 0] = (uint16_t)(l & mask);
				shiftUV[k + 1] = (uint16_t)(r & mask);
				
				l >>= shift;
				r >>= shift;

				u[j] = (mixres * l + m2 * r) >> mixbits;
				v[j] = l - r;
			}
		}
		else
		{
			for ( j = 0; j < numSamples; j++ )
			{
				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				l = (l << 8) >> 8;
				ip += 3;

				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				r = (r << 8) >> 8;
				ip += (stride - 1) * 3;

				u[j] = (mixres * l + m2 * r) >> mixbits;
				v[j] = l - r;
			}
		}
	}
	else
	{
		/* Conventional separated stereo. */
		if ( bytesShifted != 0 )
		{
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				l = (l << 8) >> 8;
				ip += 3;

				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				r = (r << 8) >> 8;
				ip += (stride - 1) * 3;

				shiftUV[k + 0] = (uint16_t)(l & mask);
				shiftUV[k + 1] = (uint16_t)(r & mask);
				
				l >>= shift;
				r >>= shift;

				u[j] = l;
				v[j] = r;
			}
		}
		else
		{
			for ( j = 0; j < numSamples; j++ )
			{
				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				u[j] = (l << 8) >> 8;
				ip += 3;

				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
				v[j] = (r << 8) >> 8;
				ip += (stride - 1) * 3;
			}
		}
	}
}

// 32-bit routines
// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
// - otherwise, the calculations might overflow into the 33rd bit and be lost
// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers

void mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
{
	int32_t	*	ip = in;
	int32_t			shift = bytesShifted * 8;
	uint32_t	mask  = (1ul << shift) - 1;
	int32_t		l, r;
	int32_t			j, k;

	if ( mixres != 0 )
	{
		int32_t		mod = 1 << mixbits;
		int32_t		m2;

		//Assert( bytesShifted != 0 );

		/* matrixed stereo with shift */
		m2 = mod - mixres;
		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
		{
			l = ip[0];
			r = ip[1];
			ip += stride;

			shiftUV[k + 0] = (uint16_t)(l & mask);
			shiftUV[k + 1] = (uint16_t)(r & mask);
			
			l >>= shift;
			r >>= shift;

			u[j] = (mixres * l + m2 * r) >> mixbits;
			v[j] = l - r;
		}
	}
	else
	{
		if ( bytesShifted == 0 )
		{
			/* de-interleaving w/o shift */
			for ( j = 0; j < numSamples; j++ )
			{
				u[j] = ip[0];
				v[j] = ip[1];
				ip += stride;
			}
		}
		else
		{
			/* de-interleaving with shift */
			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
			{
				l = ip[0];
				r = ip[1];
				ip += stride;

				shiftUV[k + 0] = (uint16_t)(l & mask);
				shiftUV[k + 1] = (uint16_t)(r & mask);
				
				l >>= shift;
				r >>= shift;

				u[j] = l;
				v[j] = r;
			}
		}
	}
}

// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)

void copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
{
	uint8_t *	ip = in;
	int32_t			j;

	for ( j = 0; j < numSamples; j++ )
	{
		int32_t			val;

		// 20-bit values are left-aligned in the 24-bit input buffer but right-aligned in the 32-bit output buffer
		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
		out[j] = (val << 8) >> 12;
		ip += stride * 3;
	}
}

void copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
{
	uint8_t *	ip = in;
	int32_t			j;

	for ( j = 0; j < numSamples; j++ )
	{
		int32_t			val;

		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
		out[j] = (val << 8) >> 8;
		ip += stride * 3;
	}
}
/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

/*
	File:		matrixlib.h
	
	Contains:	ALAC mixing/matrixing routines to/from 32-bit predictor buffers.

	Copyright:	Copyright (C) 2004 to 2011 Apple, Inc.
*/

#ifndef __MATRIXLIB_H
#define __MATRIXLIB_H

#pragma once

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// 16-bit routines
void	mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
void	unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );

// 20-bit routines
void	mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
void	unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );

// 24-bit routines
// - 24-bit data sometimes compresses better by shifting off the bottom byte so these routines deal with
//	 the specified "unused lower bytes" in the combined "shift" buffer
void	mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
void	unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );

// 32-bit routines
// - note that these really expect the internal data width to be < 32-bit but the arrays are 32-bit
// - otherwise, the calculations might overflow into the 33rd bit and be lost
// - therefore, these routines deal with the specified "unused lower" bytes in the combined "shift" buffer
void	mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
void	unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );

// 20/24/32-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
void	copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );
void	copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );

void	copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );
void	copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );
void	copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );

void	copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples );
void	copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );

#ifdef __cplusplus
}
#endif

#endif	/* __MATRIXLIB_H */
AUpvfree
AUpvgetmaxitems
AUpvgetparam
AUpvgetval
AUpvgetvaltype
AUpvnew
AUpvsetparam
AUpvsetval
AUpvsetvaltype
afCloseFile
afFreeFileSetup
afGetAESChannelData
afGetByteOrder
afGetChannels
afGetCompression
afGetDataOffset
afGetFileFormat
afGetFrameCount
afGetFrameSize
afGetInstIDs
afGetInstParamLong
afGetInstParams
afGetLoopCount
afGetLoopEnd
afGetLoopEndFrame
afGetLoopIDs
afGetLoopMode
afGetLoopStart
afGetLoopStartFrame
afGetLoopTrack
afGetMarkComment
afGetMarkIDs
afGetMarkName
afGetMarkPosition
afGetMiscIDs
afGetMiscSize
afGetMiscType
afGetPCMMapping
afGetRate
afGetSampleFormat
afGetTrackBytes
afGetTrackIDs
afGetVirtualByteOrder
afGetVirtualChannels
afGetVirtualFrameSize
afGetVirtualPCMMapping
afGetVirtualSampleFormat
afIdentifyFD
afIdentifyNamedFD
afInitAESChannelData
afInitAESChannelDataTo
afInitByteOrder
afInitChannels
afInitCompression
afInitDataOffset
afInitFileFormat
afInitFrameCount
afInitInstIDs
afInitLoopIDs
afInitMarkComment
afInitMarkIDs
afInitMarkName
afInitMiscIDs
afInitMiscSize
afInitMiscType
afInitPCMMapping
afInitRate
afInitSampleFormat
afInitTrackIDs
afNewFileSetup
afOpenFD
afOpenFile
afOpenNamedFD
afOpenVirtualFile
afQuery
afQueryDouble
afQueryLong
afQueryPointer
afReadFrames
afReadMisc
afSeekFrame
afSeekMisc
afSetAESChannelData
afSetChannelMatrix
afSetErrorHandler
afSetInstParamLong
afSetInstParams
afSetLoopCount
afSetLoopEnd
afSetLoopEndFrame
afSetLoopMode
afSetLoopStart
afSetLoopStartFrame
afSetLoopTrack
afSetMarkPosition
afSetTrackPCMMapping
afSetVirtualByteOrder
afSetVirtualChannels
afSetVirtualPCMMapping
afSetVirtualSampleFormat
afSyncFile
afTellFrame
afWriteFrames
afWriteMisc
af_virtual_file_destroy
af_virtual_file_new
/*
	Audio File Library
	Copyright (C) 1998-2000, 2010-2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	audiofile.h

	This file contains the public interfaces to the Audio File Library.
*/

#ifndef AUDIOFILE_H
#define AUDIOFILE_H

#include <aupvlist.h>
#include <stdint.h>
#include <sys/types.h>

#define LIBAUDIOFILE_MAJOR_VERSION 0
#define LIBAUDIOFILE_MINOR_VERSION 3
#define LIBAUDIOFILE_MICRO_VERSION 6

#ifdef __cplusplus
extern "C" {
#endif

#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif

typedef struct _AFvirtualfile AFvirtualfile;

typedef struct _AFfilesetup *AFfilesetup;
typedef struct _AFfilehandle *AFfilehandle;
typedef void (*AFerrfunc)(long, const char *);

// Define AFframecount and AFfileoffset as 64-bit signed integers.
#if defined(__FreeBSD__) || \
	defined(__DragonFly__) || \
	defined(__NetBSD__) || \
	defined(__OpenBSD__) || \
	defined(__APPLE__) || \
	defined(__sgi) || \
	(defined(__linux__) && defined(__LP64__))
// BSD and IRIX systems define off_t as a 64-bit signed integer.
// Linux defines off_t as a 64-bit signed integer in LP64 mode.
typedef off_t AFframecount;
typedef off_t AFfileoffset;
#else
// For all other systems, use int64_t.
typedef int64_t AFframecount;
typedef int64_t AFfileoffset;
#endif

#define AF_NULL_FILESETUP	((struct _AFfilesetup *) 0)
#define AF_NULL_FILEHANDLE	((struct _AFfilehandle *) 0)

#define AF_ERR_BASE 3000

enum
{
	AF_DEFAULT_TRACK = 1001
};

enum
{
	AF_DEFAULT_INST = 2001
};

enum
{
	AF_NUM_UNLIMITED = 99999
};

enum
{
	AF_BYTEORDER_BIGENDIAN = 501,
	AF_BYTEORDER_LITTLEENDIAN = 502
};

enum
{
	AF_FILE_UNKNOWN = -1,
	AF_FILE_RAWDATA = 0,
	AF_FILE_AIFFC = 1,
	AF_FILE_AIFF = 2,
	AF_FILE_NEXTSND = 3,
	AF_FILE_WAVE = 4,
	AF_FILE_BICSF = 5,
	AF_FILE_IRCAM = AF_FILE_BICSF,
	AF_FILE_MPEG1BITSTREAM = 6,	/* not implemented */
	AF_FILE_SOUNDDESIGNER1 = 7,	/* not implemented */
	AF_FILE_SOUNDDESIGNER2 = 8,	/* not implemented */
	AF_FILE_AVR = 9,
	AF_FILE_IFF_8SVX = 10,
	AF_FILE_SAMPLEVISION = 11,
	AF_FILE_VOC = 12,
	AF_FILE_NIST_SPHERE = 13,
	AF_FILE_SOUNDFONT2 = 14,	/* not implemented */
	AF_FILE_CAF = 15,
	AF_FILE_FLAC = 16
};

enum
{
	AF_LOOP_MODE_NOLOOP = 0,
	AF_LOOP_MODE_FORW = 1,
	AF_LOOP_MODE_FORWBAKW = 2
};

enum
{
	AF_SAMPFMT_TWOSCOMP = 401, /* linear two's complement */
	AF_SAMPFMT_UNSIGNED = 402, /* unsigned integer */
	AF_SAMPFMT_FLOAT = 403, /* 32-bit IEEE floating-point */
	AF_SAMPFMT_DOUBLE = 404 /* 64-bit IEEE double-precision floating-point */
};

enum
{
	AF_INST_LOOP_OFF = 0,			/* no looping */
	AF_INST_LOOP_CONTINUOUS = 1,	/* loop continuously through decay */
	AF_INST_LOOP_SUSTAIN = 3		/* loop during sustain, then continue */
};

enum
{
	AF_INST_MIDI_BASENOTE = 301,
	AF_INST_NUMCENTS_DETUNE = 302,
	AF_INST_MIDI_LONOTE = 303,
	AF_INST_MIDI_HINOTE = 304,
	AF_INST_MIDI_LOVELOCITY = 305,
	AF_INST_MIDI_HIVELOCITY = 306,
	AF_INST_NUMDBS_GAIN = 307,
	AF_INST_SUSLOOPID = 308,		/* loop id for AIFF sustain loop */
	AF_INST_RELLOOPID = 309,		/* loop id for AIFF release loop */
	AF_INST_SAMP_STARTFRAME = 310,	/* start sample for this inst */
	AF_INST_SAMP_ENDFRAME = 311,	/* end sample for this inst */
	AF_INST_SAMP_MODE = 312,		/* looping mode for this inst */
	AF_INST_TRACKID = 313,
	AF_INST_NAME = 314,				/* name of this inst */
	AF_INST_SAMP_RATE = 315,		/* sample rate of this inst's sample */
	AF_INST_PRESETID = 316,			/* ID of preset containing this inst */
	AF_INST_PRESET_NAME = 317		/* name of preset containing this inst */
};

enum
{
	AF_MISC_UNRECOGNIZED = 0,	/* unrecognized data chunk */
	AF_MISC_COPY = 201,	/* copyright string */
	AF_MISC_AUTH = 202,	/* author string */
	AF_MISC_NAME = 203,	/* name string */
	AF_MISC_ANNO = 204,	/* annotation string */
	AF_MISC_APPL = 205,	/* application-specific data */
	AF_MISC_MIDI = 206,	/* MIDI exclusive data */
	AF_MISC_PCMMAP = 207,	/* PCM mapping information (future use) */
	AF_MISC_NeXT = 208,	/* misc binary data appended to NeXT header */
	AF_MISC_IRCAM_PEAKAMP = 209,	/* peak amplitude information */
	AF_MISC_IRCAM_COMMENT = 210,	/* BICSF text comment */
	AF_MISC_COMMENT = 210,	/* general text comment */

	AF_MISC_ICMT = AF_MISC_COMMENT,	/* comments chunk (WAVE format) */
	AF_MISC_ICRD = 211,  /* creation date (WAVE format) */
	AF_MISC_ISFT = 212  /* software name (WAVE format) */
};

enum
{
	/* supported compression schemes */
	AF_COMPRESSION_UNKNOWN = -1,
	AF_COMPRESSION_NONE = 0,
	AF_COMPRESSION_G722 = 501,
	AF_COMPRESSION_G711_ULAW = 502,
	AF_COMPRESSION_G711_ALAW = 503,

	/* Apple proprietary AIFF-C compression schemes (not supported) */
	AF_COMPRESSION_APPLE_ACE2 = 504,
	AF_COMPRESSION_APPLE_ACE8 = 505,
	AF_COMPRESSION_APPLE_MAC3 = 506,
	AF_COMPRESSION_APPLE_MAC6 = 507,

	AF_COMPRESSION_G726 = 517,
	AF_COMPRESSION_G728 = 518,
	AF_COMPRESSION_DVI_AUDIO = 519,
	AF_COMPRESSION_IMA = AF_COMPRESSION_DVI_AUDIO,
	AF_COMPRESSION_GSM = 520,
	AF_COMPRESSION_FS1016 = 521,
	AF_COMPRESSION_DV = 522,
	AF_COMPRESSION_MS_ADPCM = 523,

	AF_COMPRESSION_FLAC = 530,
	AF_COMPRESSION_ALAC = 540
};

/* tokens for afQuery() -- see the man page for instructions */
/* level 1 selectors */
enum
{
	AF_QUERYTYPE_INSTPARAM = 500,
	AF_QUERYTYPE_FILEFMT = 501,
	AF_QUERYTYPE_COMPRESSION = 502,
	AF_QUERYTYPE_COMPRESSIONPARAM = 503,
	AF_QUERYTYPE_MISC = 504,
	AF_QUERYTYPE_INST = 505,
	AF_QUERYTYPE_MARK = 506,
	AF_QUERYTYPE_LOOP = 507
};

/* level 2 selectors */
enum
{
	AF_QUERY_NAME = 600,	/* get name (1-3 words) */
	AF_QUERY_DESC = 601,	/* get description */
	AF_QUERY_LABEL = 602,	/* get 4- or 5-char label */
	AF_QUERY_TYPE = 603,	/* get type token */
	AF_QUERY_DEFAULT = 604,	/* dflt. value for param */
	AF_QUERY_ID_COUNT = 605,	/* get number of ids avail. */
	AF_QUERY_IDS = 606,	/* get array of id tokens */
	AF_QUERY_IMPLEMENTED = 613,	/* boolean */
	AF_QUERY_TYPE_COUNT = 607,	/* get number of types av. */
	AF_QUERY_TYPES = 608,	/* get array of types */
	AF_QUERY_NATIVE_SAMPFMT = 609,	/* for compression */
	AF_QUERY_NATIVE_SAMPWIDTH = 610,
	AF_QUERY_SQUISHFAC = 611,	/* 1.0 means variable */
	AF_QUERY_MAX_NUMBER = 612,	/* max allowed in file */
	AF_QUERY_SUPPORTED = 613	/* insts, loops, etc., supported? */
};

/* level 2 selectors which have sub-selectors */
enum
{
	AF_QUERY_TRACKS = 620,
	AF_QUERY_CHANNELS = 621,
	AF_QUERY_SAMPLE_SIZES = 622,
	AF_QUERY_SAMPLE_FORMATS = 623,
	AF_QUERY_COMPRESSION_TYPES = 624
};

/* level 3 sub-selectors */
enum
{
	AF_QUERY_VALUE_COUNT = 650,	/* number of values of the above */
	AF_QUERY_VALUES = 651	/* array of those values */
};


/*
	Old Audio File Library error codes. These are still returned by the
	AFerrorhandler calls, but are not used by the new digital media library
	error reporting routines. See the bottom of this file for the new error
	tokens.
*/

enum
{
	AF_BAD_NOT_IMPLEMENTED = 0,	/* not implemented yet */
	AF_BAD_FILEHANDLE = 1,	/* tried to use invalid filehandle */
	AF_BAD_OPEN = 3,	/* unix open failed */
	AF_BAD_CLOSE = 4,	/* unix close failed */
	AF_BAD_READ = 5,	/* unix read failed */
	AF_BAD_WRITE = 6,	/* unix write failed */
	AF_BAD_LSEEK = 7,	/* unix lseek failed */
	AF_BAD_NO_FILEHANDLE = 8,	/* failed to allocate a filehandle struct */
	AF_BAD_ACCMODE = 10,	/* unrecognized audio file access mode */
	AF_BAD_NOWRITEACC = 11,	/* file not open for writing */
	AF_BAD_NOREADACC = 12,	/* file not open for reading */
	AF_BAD_FILEFMT = 13,	/* unrecognized audio file format */
	AF_BAD_RATE = 14,	/* invalid sample rate */
	AF_BAD_CHANNELS = 15,	/* invalid number of channels*/
	AF_BAD_SAMPCNT = 16,	/* invalid sample count */
	AF_BAD_WIDTH = 17,	/* invalid sample width */
	AF_BAD_SEEKMODE = 18,	/* invalid seek mode */
	AF_BAD_NO_LOOPDATA = 19,	/* failed to allocate loop struct */
	AF_BAD_MALLOC = 20,	/* malloc failed somewhere */
	AF_BAD_LOOPID = 21,
	AF_BAD_SAMPFMT = 22,	/* bad sample format */
	AF_BAD_FILESETUP = 23,	/* bad file setup structure*/
	AF_BAD_TRACKID = 24,	/* no track corresponding to id */
	AF_BAD_NUMTRACKS = 25,	/* wrong number of tracks for file format */
	AF_BAD_NO_FILESETUP = 26,	/* failed to allocate a filesetup struct*/
	AF_BAD_LOOPMODE = 27,	/* unrecognized loop mode value */
	AF_BAD_INSTID = 28,	/* invalid instrument id */
	AF_BAD_NUMLOOPS = 29,	/* bad number of loops */
	AF_BAD_NUMMARKS = 30,	/* bad number of markers */
	AF_BAD_MARKID = 31,	/* bad marker id */
	AF_BAD_MARKPOS = 32,	/* invalid marker position value */
	AF_BAD_NUMINSTS = 33,	/* invalid number of instruments */
	AF_BAD_NOAESDATA = 34,
	AF_BAD_MISCID = 35,
	AF_BAD_NUMMISC = 36,
	AF_BAD_MISCSIZE = 37,
	AF_BAD_MISCTYPE = 38,
	AF_BAD_MISCSEEK = 39,
	AF_BAD_STRLEN = 40,	/* invalid string length */
	AF_BAD_RATECONV = 45,
	AF_BAD_SYNCFILE = 46,
	AF_BAD_CODEC_CONFIG = 47,	/* improperly configured codec */
	AF_BAD_CODEC_STATE = 48,	/* invalid codec state: can't recover */
	AF_BAD_CODEC_LICENSE = 49,	/* no license available for codec */
	AF_BAD_CODEC_TYPE = 50,	/* unsupported codec type */
	AF_BAD_COMPRESSION = AF_BAD_CODEC_CONFIG,	/* for back compat */
	AF_BAD_COMPTYPE = AF_BAD_CODEC_TYPE,	/* for back compat */

	AF_BAD_INSTPTYPE = 51,	/* invalid instrument parameter type */
	AF_BAD_INSTPID = 52,	/* invalid instrument parameter id */
	AF_BAD_BYTEORDER = 53,
	AF_BAD_FILEFMT_PARAM = 54,	/* unrecognized file format parameter */
	AF_BAD_COMP_PARAM = 55,	/* unrecognized compression parameter */
	AF_BAD_DATAOFFSET = 56,	/* bad data offset */
	AF_BAD_FRAMECNT = 57,	/* bad frame count */
	AF_BAD_QUERYTYPE = 58,	/* bad query type */
	AF_BAD_QUERY = 59,	/* bad argument to afQuery() */
	AF_WARNING_CODEC_RATE = 60,	/* using 8k instead of codec rate 8012 */
	AF_WARNING_RATECVT = 61,	/* warning about rate conversion used */

	AF_BAD_HEADER = 62,	/* failed to parse header */
	AF_BAD_FRAME = 63,	/* bad frame number */
	AF_BAD_LOOPCOUNT = 64,	/* bad loop count */
	AF_BAD_DMEDIA_CALL = 65,	/* error in dmedia subsystem call */

	/* AIFF/AIFF-C specific errors when parsing file header */
	AF_BAD_AIFF_HEADER = 108,	/* failed to parse chunk header */
	AF_BAD_AIFF_FORM = 109,	/* failed to parse FORM chunk */
	AF_BAD_AIFF_SSND = 110,	/* failed to parse SSND chunk */
	AF_BAD_AIFF_CHUNKID = 111,	/* unrecognized AIFF/AIFF-C chunk id */
	AF_BAD_AIFF_COMM = 112,	/* failed to parse COMM chunk */
	AF_BAD_AIFF_INST = 113,	/* failed to parse INST chunk */
	AF_BAD_AIFF_MARK = 114,	/* failed to parse MARK chunk */
	AF_BAD_AIFF_SKIP = 115,	/* failed to skip unsupported chunk */
	AF_BAD_AIFF_LOOPMODE = 116	/* unrecognized loop mode (forw, etc)*/
};

/* new error codes which may be retrieved via dmGetError() */
/* The old error tokens continue to be retrievable via the AFerrorhandler */
/* AF_ERR_BASE is #defined in dmedia/dmedia.h */

enum
{
	AF_ERR_NOT_IMPLEMENTED = 0+AF_ERR_BASE,	/* not implemented yet */
	AF_ERR_BAD_FILEHANDLE = 1+AF_ERR_BASE,	/* invalid filehandle */
	AF_ERR_BAD_READ = 5+AF_ERR_BASE,	/* unix read failed */
	AF_ERR_BAD_WRITE = 6+AF_ERR_BASE,	/* unix write failed */
	AF_ERR_BAD_LSEEK = 7+AF_ERR_BASE,	/* unix lseek failed */
	AF_ERR_BAD_ACCMODE = 10+AF_ERR_BASE,	/* unrecognized audio file access mode */
	AF_ERR_NO_WRITEACC = 11+AF_ERR_BASE,	/* file not open for writing */
	AF_ERR_NO_READACC = 12+AF_ERR_BASE,	/* file not open for reading */
	AF_ERR_BAD_FILEFMT = 13+AF_ERR_BASE,	/* unrecognized audio file format */
	AF_ERR_BAD_RATE = 14+AF_ERR_BASE,	/* invalid sample rate */
	AF_ERR_BAD_CHANNELS = 15+AF_ERR_BASE,	/* invalid # channels*/
	AF_ERR_BAD_SAMPCNT = 16+AF_ERR_BASE,	/* invalid sample count */
	AF_ERR_BAD_WIDTH = 17+AF_ERR_BASE,	/* invalid sample width */
	AF_ERR_BAD_SEEKMODE = 18+AF_ERR_BASE,	/* invalid seek mode */
	AF_ERR_BAD_LOOPID = 21+AF_ERR_BASE,	/* invalid loop id */
	AF_ERR_BAD_SAMPFMT = 22+AF_ERR_BASE,	/* bad sample format */
	AF_ERR_BAD_FILESETUP = 23+AF_ERR_BASE,	/* bad file setup structure*/
	AF_ERR_BAD_TRACKID = 24+AF_ERR_BASE,	/* no track corresponding to id */
	AF_ERR_BAD_NUMTRACKS = 25+AF_ERR_BASE,	/* wrong number of tracks for file format */
	AF_ERR_BAD_LOOPMODE = 27+AF_ERR_BASE,	/* unrecognized loop mode symbol */
	AF_ERR_BAD_INSTID = 28+AF_ERR_BASE,	/* invalid instrument id */
	AF_ERR_BAD_NUMLOOPS = 29+AF_ERR_BASE,	/* bad number of loops */
	AF_ERR_BAD_NUMMARKS = 30+AF_ERR_BASE,	/* bad number of markers */
	AF_ERR_BAD_MARKID = 31+AF_ERR_BASE,	/* bad marker id */
	AF_ERR_BAD_MARKPOS = 32+AF_ERR_BASE,	/* invalid marker position value */
	AF_ERR_BAD_NUMINSTS = 33+AF_ERR_BASE,	/* invalid number of instruments */
	AF_ERR_BAD_NOAESDATA = 34+AF_ERR_BASE,
	AF_ERR_BAD_MISCID = 35+AF_ERR_BASE,
	AF_ERR_BAD_NUMMISC = 36+AF_ERR_BASE,
	AF_ERR_BAD_MISCSIZE = 37+AF_ERR_BASE,
	AF_ERR_BAD_MISCTYPE = 38+AF_ERR_BASE,
	AF_ERR_BAD_MISCSEEK = 39+AF_ERR_BASE,
	AF_ERR_BAD_STRLEN = 40+AF_ERR_BASE,	/* invalid string length */
	AF_ERR_BAD_RATECONV = 45+AF_ERR_BASE,
	AF_ERR_BAD_SYNCFILE = 46+AF_ERR_BASE,
	AF_ERR_BAD_CODEC_CONFIG = 47+AF_ERR_BASE,	/* improperly configured codec */
	AF_ERR_BAD_CODEC_TYPE = 50+AF_ERR_BASE,	/* unsupported codec type */
	AF_ERR_BAD_INSTPTYPE = 51+AF_ERR_BASE,	/* invalid instrument parameter type */
	AF_ERR_BAD_INSTPID = 52+AF_ERR_BASE,	/* invalid instrument parameter id */

	AF_ERR_BAD_BYTEORDER = 53+AF_ERR_BASE,
	AF_ERR_BAD_FILEFMT_PARAM = 54+AF_ERR_BASE,	/* unrecognized file format parameter */
	AF_ERR_BAD_COMP_PARAM = 55+AF_ERR_BASE,	/* unrecognized compression parameter */
	AF_ERR_BAD_DATAOFFSET = 56+AF_ERR_BASE,	/* bad data offset */
	AF_ERR_BAD_FRAMECNT = 57+AF_ERR_BASE,	/* bad frame count */

	AF_ERR_BAD_QUERYTYPE = 58+AF_ERR_BASE,	/* bad query type */
	AF_ERR_BAD_QUERY = 59+AF_ERR_BASE,	/* bad argument to afQuery() */
	AF_ERR_BAD_HEADER = 62+AF_ERR_BASE,	/* failed to parse header */
	AF_ERR_BAD_FRAME = 63+AF_ERR_BASE,	/* bad frame number */
	AF_ERR_BAD_LOOPCOUNT = 64+AF_ERR_BASE,	/* bad loop count */

	/* AIFF/AIFF-C specific errors when parsing file header */

	AF_ERR_BAD_AIFF_HEADER = 66+AF_ERR_BASE,	/* failed to parse chunk header */
	AF_ERR_BAD_AIFF_FORM = 67+AF_ERR_BASE,	/* failed to parse FORM chunk */
	AF_ERR_BAD_AIFF_SSND = 68+AF_ERR_BASE,	/* failed to parse SSND chunk */
	AF_ERR_BAD_AIFF_CHUNKID = 69+AF_ERR_BASE,	/* unrecognized AIFF/AIFF-C chunk id */
	AF_ERR_BAD_AIFF_COMM = 70+AF_ERR_BASE,	/* failed to parse COMM chunk */
	AF_ERR_BAD_AIFF_INST = 71+AF_ERR_BASE,	/* failed to parse INST chunk */
	AF_ERR_BAD_AIFF_MARK = 72+AF_ERR_BASE,	/* failed to parse MARK chunk */
	AF_ERR_BAD_AIFF_SKIP = 73+AF_ERR_BASE,	/* failed to skip unsupported chunk */
	AF_ERR_BAD_AIFF_LOOPMODE = 74+AF_ERR_BASE	/* unrecognized loop mode (forw, etc) */
};


/* global routines */
AFAPI AFerrfunc afSetErrorHandler (AFerrfunc efunc);

/* query routines */
AFAPI AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4);

/* basic operations on file handles and file setups */
AFAPI AFfilesetup afNewFileSetup (void);
AFAPI void afFreeFileSetup (AFfilesetup);
AFAPI int afIdentifyFD (int);
AFAPI int afIdentifyNamedFD (int, const char *filename, int *implemented);

AFAPI AFfilehandle afOpenFile (const char *filename, const char *mode,
	AFfilesetup setup);
AFAPI AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
	AFfilesetup setup);
AFAPI AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup);
AFAPI AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
	const char *filename);

AFAPI void afSaveFilePosition (AFfilehandle file);
AFAPI void afRestoreFilePosition (AFfilehandle file);
AFAPI int afSyncFile (AFfilehandle file);
AFAPI int afCloseFile (AFfilehandle file);

AFAPI void afInitFileFormat (AFfilesetup, int format);
AFAPI int afGetFileFormat (AFfilehandle, int *version);

/* track */
AFAPI void afInitTrackIDs (AFfilesetup, const int *trackids, int trackCount);
AFAPI int afGetTrackIDs (AFfilehandle, int *trackids);

/* track data: reading, writng, seeking, sizing frames */
AFAPI int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount);
AFAPI int afWriteFrames (AFfilehandle, int track, const void *buffer, int frameCount);
AFAPI AFframecount afSeekFrame (AFfilehandle, int track, AFframecount frameoffset);
AFAPI AFframecount afTellFrame (AFfilehandle, int track);
AFAPI AFfileoffset afGetTrackBytes (AFfilehandle, int track);
AFAPI float afGetFrameSize (AFfilehandle, int track, int expand3to4);
AFAPI float afGetVirtualFrameSize (AFfilehandle, int track, int expand3to4);

/* track data: AES data */
/* afInitAESChannelData is obsolete -- use afInitAESChannelDataTo() */
AFAPI void afInitAESChannelData (AFfilesetup, int track); /* obsolete */
AFAPI void afInitAESChannelDataTo (AFfilesetup, int track, int willBeData);
AFAPI int afGetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
AFAPI void afSetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);

/* track data: byte order */
AFAPI void afInitByteOrder (AFfilesetup, int track, int byteOrder);
AFAPI int afGetByteOrder (AFfilehandle, int track);
AFAPI int afSetVirtualByteOrder (AFfilehandle, int track, int byteOrder);
AFAPI int afGetVirtualByteOrder (AFfilehandle, int track);

/* track data: number of channels */
AFAPI void afInitChannels (AFfilesetup, int track, int nchannels);
AFAPI int afGetChannels (AFfilehandle, int track);
AFAPI int afSetVirtualChannels (AFfilehandle, int track, int channelCount);
AFAPI int afGetVirtualChannels (AFfilehandle, int track);
AFAPI void afSetChannelMatrix (AFfilehandle, int track, double *matrix);

/* track data: sample format and sample width */
AFAPI void afInitSampleFormat (AFfilesetup, int track, int sampleFormat,
	int sampleWidth);
AFAPI void afGetSampleFormat (AFfilehandle file, int track, int *sampleFormat,
	int *sampleWidth);
AFAPI int afSetVirtualSampleFormat (AFfilehandle, int track,
	int sampleFormat, int sampleWidth);
AFAPI void afGetVirtualSampleFormat (AFfilehandle, int track,
	int *sampleFormat, int *sampleWidth);

/* track data: sampling rate */
AFAPI void afInitRate (AFfilesetup, int track, double rate);
AFAPI double afGetRate (AFfilehandle, int track);

#if 0
int afSetVirtualRate (AFfilehandle, int track, double rate);
double afGetVirtualRate (AFfilehandle, int track);
#endif

/* track data: compression */
AFAPI void afInitCompression (AFfilesetup, int track, int compression);
#if 0
void afInitCompressionParams (AFfilesetup, int track, int compression
	AUpvlist params, int parameterCount);
#endif

AFAPI int afGetCompression (AFfilehandle, int track);
#if 0
void afGetCompressionParams (AFfilehandle, int track, int *compression,
	AUpvlist params, int parameterCount);

int afSetVirtualCompression (AFfilesetup, int track, int compression);
void afSetVirtualCompressionParams (AFfilehandle, int track, int compression,
	AUpvlist params, int parameterCount);

int afGetVirtualCompression (AFfilesetup, int track, int compression);
void afGetVirtualCompressionParams (AFfilehandle, int track, int *compression,
	AUpvlist params, int parameterCount);
#endif

/* track data: pcm mapping */
AFAPI void afInitPCMMapping (AFfilesetup filesetup, int track,
	double slope, double intercept, double minClip, double maxClip);
AFAPI void afGetPCMMapping (AFfilehandle file, int track,
	double *slope, double *intercept, double *minClip, double *maxClip);
/* NOTE: afSetTrackPCMMapping() is special--it does not set the virtual  */
/* format; it changes what the AF thinks the track format is! Be careful. */
AFAPI int afSetTrackPCMMapping (AFfilehandle file, int track,
	double slope, double intercept, double minClip, double maxClip);
/* NOTE: afSetVirtualPCMMapping() is different from afSetTrackPCMMapping(): */
/* see comment for afSetTrackPCMMapping(). */
AFAPI int afSetVirtualPCMMapping (AFfilehandle file, int track,
	double slope, double intercept, double minClip, double maxClip);
AFAPI void afGetVirtualPCMMapping (AFfilehandle file, int track,
	double *slope, double *intercept, double *minClip, double *maxClip);

/* track data: data offset within the file */
/* initialize for raw reading only */
AFAPI void afInitDataOffset(AFfilesetup, int track, AFfileoffset offset);
AFAPI AFfileoffset afGetDataOffset (AFfilehandle, int track);

/* track data: count of frames in file */
AFAPI void afInitFrameCount (AFfilesetup, int track, AFframecount frameCount);
AFAPI AFframecount afGetFrameCount (AFfilehandle file, int track);

/* loop operations */
AFAPI void afInitLoopIDs (AFfilesetup, int instid, const int *ids, int nids);
AFAPI int afGetLoopIDs (AFfilehandle, int instid, int loopids[]);
AFAPI void afSetLoopMode (AFfilehandle, int instid, int loop, int mode);
AFAPI int afGetLoopMode (AFfilehandle, int instid, int loopid);
AFAPI int afSetLoopCount (AFfilehandle, int instid, int loop, int count);
AFAPI int afGetLoopCount (AFfilehandle, int instid, int loopid);
AFAPI void afSetLoopStart (AFfilehandle, int instid, int loopid, int markerid);
AFAPI int afGetLoopStart (AFfilehandle, int instid, int loopid);
AFAPI void afSetLoopEnd (AFfilehandle, int instid, int loopid, int markerid);
AFAPI int afGetLoopEnd (AFfilehandle, int instid, int loopid);

AFAPI int afSetLoopStartFrame (AFfilehandle, int instid, int loop,
	AFframecount startFrame);
AFAPI AFframecount afGetLoopStartFrame (AFfilehandle, int instid, int loop);
AFAPI int afSetLoopEndFrame (AFfilehandle, int instid, int loop,
	AFframecount startFrame);
AFAPI AFframecount afGetLoopEndFrame (AFfilehandle, int instid, int loop);

AFAPI void afSetLoopTrack (AFfilehandle, int instid, int loopid, int trackid);
AFAPI int afGetLoopTrack (AFfilehandle, int instid, int loopid);

/* marker operations */
AFAPI void afInitMarkIDs (AFfilesetup, int trackid, const int *ids, int nids);
AFAPI int afGetMarkIDs (AFfilehandle file, int trackid, int markids[]);
AFAPI void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
	AFframecount markpos);
AFAPI AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid);
AFAPI void afInitMarkName (AFfilesetup, int trackid, int marker, const char *name);
AFAPI void afInitMarkComment (AFfilesetup, int trackid, int marker,
	const char *comment);
AFAPI char *afGetMarkName (AFfilehandle file, int trackid, int markid);
AFAPI char *afGetMarkComment (AFfilehandle file, int trackid, int markid);

/* instrument operations */
AFAPI void afInitInstIDs (AFfilesetup, const int *ids, int nids);
AFAPI int afGetInstIDs (AFfilehandle file, int *instids);
AFAPI void afGetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
	int nparams);
AFAPI void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
	int nparams);
AFAPI long afGetInstParamLong (AFfilehandle file, int instid, int param);
AFAPI void afSetInstParamLong (AFfilehandle file, int instid, int param, long value);

/* miscellaneous data operations */
AFAPI void afInitMiscIDs (AFfilesetup, const int *ids, int nids);
AFAPI int afGetMiscIDs (AFfilehandle, int *ids);
AFAPI void afInitMiscType (AFfilesetup, int miscellaneousid, int type);
AFAPI int afGetMiscType (AFfilehandle, int miscellaneousid);
AFAPI void afInitMiscSize (AFfilesetup, int miscellaneousid, int size);
AFAPI int afGetMiscSize (AFfilehandle, int miscellaneousid);
AFAPI int afWriteMisc (AFfilehandle, int miscellaneousid, const void *buf, int bytes);
AFAPI int afReadMisc (AFfilehandle, int miscellaneousid, void *buf, int bytes);
AFAPI int afSeekMisc (AFfilehandle, int miscellaneousid, int offset);

#undef AFAPI

#ifdef __cplusplus
}
#endif

#endif /* AUDIOFILE_H */
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	aupv.c

	This file contains an implementation of SGI's Audio Library parameter
	value list functions.
*/

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "aupvinternal.h"
#include "aupvlist.h"

AUpvlist AUpvnew (int maxitems)
{
	AUpvlist	aupvlist;
	int		i;

	if (maxitems <= 0)
		return AU_NULL_PVLIST;

	aupvlist = (AUpvlist) malloc(sizeof (struct _AUpvlist));
	assert(aupvlist);
	if (aupvlist == NULL)
		return AU_NULL_PVLIST;

	aupvlist->items = calloc(maxitems, sizeof (struct _AUpvitem));

	assert(aupvlist->items);
	if (aupvlist->items == NULL)
	{
		free(aupvlist);
		return AU_NULL_PVLIST;
	}

	/* Initialize the items in the list. */
	for (i=0; i<maxitems; i++)
	{
		aupvlist->items[i].valid = _AU_VALID_PVITEM;
		aupvlist->items[i].type = AU_PVTYPE_LONG;
		aupvlist->items[i].parameter = 0;
		memset(&aupvlist->items[i].value, 0, sizeof (aupvlist->items[i].value));
	}

	aupvlist->valid = _AU_VALID_PVLIST;
	aupvlist->count = maxitems;

	return aupvlist;
}

int AUpvgetmaxitems (AUpvlist list)
{
	assert(list);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;

	return list->count;
}

int AUpvfree (AUpvlist list)
{
	assert(list);
	assert(list->items);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;

	if ((list->items != _AU_NULL_PVITEM) &&
		(list->items[0].valid == _AU_VALID_PVITEM))
	{
		free(list->items);
	}

	free(list);

	return _AU_SUCCESS;
}

int AUpvsetparam (AUpvlist list, int item, int param)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	list->items[item].parameter = param;
	return _AU_SUCCESS;
}

int AUpvsetvaltype (AUpvlist list, int item, int type)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	list->items[item].type = type;
	return _AU_SUCCESS;
}

int AUpvsetval (AUpvlist list, int item, void *val)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	switch (list->items[item].type)
	{
		case AU_PVTYPE_LONG:
			list->items[item].value.l = *((long *) val);
			break;
		case AU_PVTYPE_DOUBLE:
			list->items[item].value.d = *((double *) val);
			break;
		case AU_PVTYPE_PTR:
			list->items[item].value.v = *((void **) val);
			break;
		default:
			assert(0);
			return AU_BAD_PVLIST;
	}

	return _AU_SUCCESS;
}

int AUpvgetparam (AUpvlist list, int item, int *param)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	*param = list->items[item].parameter;
	return _AU_SUCCESS;
}

int AUpvgetvaltype (AUpvlist list, int item, int *type)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	*type = list->items[item].type;
	return _AU_SUCCESS;
}

int AUpvgetval (AUpvlist list, int item, void *val)
{
	assert(list);
	assert(list->items);
	assert(item >= 0);
	assert(item < list->count);

	if (list == AU_NULL_PVLIST)
		return AU_BAD_PVLIST;
	if (list->valid != _AU_VALID_PVLIST)
		return AU_BAD_PVLIST;
	if ((item < 0) || (item > list->count - 1))
		return AU_BAD_PVITEM;
	if (list->items[item].valid != _AU_VALID_PVITEM)
		return AU_BAD_PVLIST;

	switch (list->items[item].type)
	{
		case AU_PVTYPE_LONG:
			*((long *) val) = list->items[item].value.l;
			break;
		case AU_PVTYPE_DOUBLE:
			*((double *) val) = list->items[item].value.d;
			break;
		case AU_PVTYPE_PTR:
			*((void **) val) = list->items[item].value.v;
			break;
	}

	return _AU_SUCCESS;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	aupvinternal.h

	This file contains the private data structures for the parameter
	value list data types.
*/

#ifndef AUPVINTERNAL_H
#define AUPVINTERNAL_H

struct _AUpvitem
{
	int	valid;
	int	type;
	int	parameter;

	union
	{
		long	l;
		double	d;
		void	*v;
	}
	value;
};

struct _AUpvlist
{
	int			valid;
	size_t			count;
	struct _AUpvitem	*items;
};

enum
{
	_AU_VALID_PVLIST = 30932,
	_AU_VALID_PVITEM = 30933
};

enum
{
	AU_BAD_PVLIST = -5,
	AU_BAD_PVITEM = -6,
	AU_BAD_PVTYPE = -7,
	AU_BAD_ALLOC = -8
};

enum
{
	_AU_FAIL = -1,
	_AU_SUCCESS = 0
};

#define _AU_NULL_PVITEM ((struct _AUpvitem *) NULL)

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	aupvlist.h

	This file contains the interface to the parameter value list data
	structures and routines.
*/

#ifndef AUPVLIST_H
#define AUPVLIST_H

#ifdef __cplusplus
extern "C" {
#endif

#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif

enum
{
	AU_PVTYPE_LONG = 1,
	AU_PVTYPE_DOUBLE = 2,
	AU_PVTYPE_PTR = 3
};

typedef struct _AUpvlist *AUpvlist;

#define AU_NULL_PVLIST ((struct _AUpvlist *) 0)

AFAPI AUpvlist AUpvnew (int maxItems);
AFAPI int AUpvgetmaxitems (AUpvlist);
AFAPI int AUpvfree (AUpvlist);
AFAPI int AUpvsetparam (AUpvlist, int item, int param);
AFAPI int AUpvsetvaltype (AUpvlist, int item, int type);
AFAPI int AUpvsetval (AUpvlist, int item, void *val);
AFAPI int AUpvgetparam (AUpvlist, int item, int *param);
AFAPI int AUpvgetvaltype (AUpvlist, int item, int *type);
AFAPI int AUpvgetval (AUpvlist, int item, void *val);

#undef AFAPI

#ifdef __cplusplus
}
#endif

#endif /* AUPVLIST_H */
/*
	Audio File Library
	Copyright (C) 1998-1999, 2010-2011, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef BYTEORDER_H
#define BYTEORDER_H

#include "config.h"

#include <stdint.h>

#if WORDS_BIGENDIAN
	#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_BIGENDIAN)
#else
	#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_LITTLEENDIAN)
#endif

inline uint16_t _af_byteswap_int16 (uint16_t x)
{
	return (x >> 8) | (x << 8);
}

inline uint32_t _af_byteswap_int32 (uint32_t x)
{
	return ((x & 0x000000ffU) << 24) |
		((x & 0x0000ff00U) << 8) |
		((x & 0x00ff0000U) >> 8) |
		((x & 0xff000000U) >> 24);
}

inline uint64_t _af_byteswap_int64 (uint64_t x)
{
	return ((x & 0x00000000000000ffULL) << 56) |
		((x & 0x000000000000ff00ULL) << 40) |
		((x & 0x0000000000ff0000ULL) << 24) |
		((x & 0x00000000ff000000ULL) << 8) |
		((x & 0x000000ff00000000ULL) >> 8) |
		((x & 0x0000ff0000000000ULL) >> 24) |
		((x & 0x00ff000000000000ULL) >> 40) |
		((x & 0xff00000000000000ULL) >> 56);
}

inline float _af_byteswap_float32 (float x)
{
	union
	{
		uint32_t i;
		float f;
	} u;
	u.f = x;
	u.i = _af_byteswap_int32(u.i);
	return u.f;
}

inline double _af_byteswap_float64 (double x)
{
	union
	{
		uint64_t i;
		double f;
	} u;
	u.f = x;
	u.i = _af_byteswap_int64(u.i);
	return u.f;
}

inline uint64_t byteswap(uint64_t value) { return _af_byteswap_int64(value); }
inline int64_t byteswap(int64_t value) { return _af_byteswap_int64(value); }
inline uint32_t byteswap(uint32_t value) { return _af_byteswap_int32(value); }
inline int32_t byteswap(int32_t value) { return _af_byteswap_int32(value); }
inline uint16_t byteswap(uint16_t value) { return _af_byteswap_int16(value); }
inline int16_t byteswap(int16_t value) { return _af_byteswap_int16(value); }

inline double byteswap(double value) { return _af_byteswap_float64(value); }
inline float byteswap(float value) { return _af_byteswap_float32(value); }

template <typename T>
T bigToHost(T value)
{
	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
}

template <typename T>
T littleToHost(T value)
{
	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
}

template <typename T>
T hostToBig(T value)
{
	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
}

template <typename T>
T hostToLittle(T value)
{
	return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
}

#endif
/*
	Audio File Library
	Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	compression.cpp

	This file contains routines for configuring compressed audio.
*/

#include "config.h"

#include <assert.h>

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "audiofile.h"
#include "aupvlist.h"
#include "units.h"
#include "util.h"

const CompressionUnit *_af_compression_unit_from_id (int compressionid)
{
	for (int i=0; i<_AF_NUM_COMPRESSION; i++)
		if (_af_compression[i].compressionID == compressionid)
			return &_af_compression[i];

	_af_error(AF_BAD_COMPTYPE, "compression type %d not available", compressionid);
	return NULL;
}

int afGetCompression (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->f.compressionType;
}

void afInitCompression (AFfilesetup setup, int trackid, int compression)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	if (!_af_compression_unit_from_id(compression))
		return;

	track->compressionSet = true;
	track->f.compressionType = compression;
}

#if 0
int afGetCompressionParams (AFfilehandle file, int trackid,
	int *compression, AUpvlist pvlist, int numitems)
{
	assert(file);
	assert(trackid == AF_DEFAULT_TRACK);
}

void afInitCompressionParams (AFfilesetup setup, int trackid,
	int compression, AUpvlist pvlist, int numitems)
{
	assert(setup);
	assert(trackid == AF_DEFAULT_TRACK);
}
#endif
/*
	Audio File Library
	Copyright (C) 1999, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	compression.h
*/

#ifndef COMPRESSION_H
#define COMPRESSION_H

struct CompressionUnit;

const CompressionUnit *_af_compression_unit_from_id (int compressionid);

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	data.cpp
*/

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "File.h"
#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "modules/Module.h"
#include "modules/ModuleState.h"
#include "util.h"

int afWriteFrames (AFfilehandle file, int trackid, const void *samples,
	int nvframes2write)
{
	SharedPtr<Module> firstmod;
	SharedPtr<Chunk> userc;
	int bytes_per_vframe;
	AFframecount vframe;

	if (!_af_filehandle_ok(file))
		return -1;

	if (!file->checkCanWrite())
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
		return -1;

	if (!track->ms->fileModuleHandlesSeeking() &&
		file->m_seekok &&
		file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
			track->fpos_next_frame)
	{
		_af_error(AF_BAD_LSEEK, "unable to position write pointer at next frame");
		return -1;
	}

	bytes_per_vframe = _af_format_frame_size(&track->v, true);

	firstmod = track->ms->modules().front();
	userc = track->ms->chunks().front();

	track->filemodhappy = true;

	vframe = 0;
#ifdef UNLIMITED_CHUNK_NVFRAMES
	/*
		OPTIMIZATION: see the comment at the very end of
		arrangemodules() in modules.c for an explanation of this:
	*/
	if (!trk->ms->mustUseAtomicNVFrames())
	{
		userc->buffer = (char *) samples;
		userc->frameCount = nvframes2write;

		firstmod->runPush();

		/* Count this chunk if there was no i/o error. */
		if (trk->filemodhappy)
			vframe += userc->frameCount;
	}
	else
#else
	/* Optimization must be off. */
	assert(track->ms->mustUseAtomicNVFrames());
#endif
	{
		while (vframe < nvframes2write)
		{
			userc->buffer = (char *) samples + bytes_per_vframe * vframe;
			if (vframe <= nvframes2write - _AF_ATOMIC_NVFRAMES)
				userc->frameCount = _AF_ATOMIC_NVFRAMES;
			else
				userc->frameCount = nvframes2write - vframe;

			firstmod->runPush();

			if (!track->filemodhappy)
				break;

			vframe += userc->frameCount;
		}
	}

	track->nextvframe += vframe;
	track->totalvframes += vframe;

	return vframe;
}

int afReadFrames (AFfilehandle file, int trackid, void *samples,
	int nvframeswanted)
{
	SharedPtr<Module> firstmod;
	SharedPtr<Chunk> userc;
	AFframecount	nvframesleft, nvframes2read;
	int		bytes_per_vframe;
	AFframecount	vframe;

	if (!_af_filehandle_ok(file))
		return -1;

	if (!file->checkCanRead())
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
		return -1;

	if (!track->ms->fileModuleHandlesSeeking() &&
		file->m_seekok &&
		file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
			track->fpos_next_frame)
	{
		_af_error(AF_BAD_LSEEK, "unable to position read pointer at next frame");
		return -1;
	}

	if (track->totalvframes == -1)
		nvframes2read = nvframeswanted;
	else
	{
		nvframesleft = track->totalvframes - track->nextvframe;
		nvframes2read = (nvframeswanted > nvframesleft) ?
			nvframesleft : nvframeswanted;
	}
	bytes_per_vframe = _af_format_frame_size(&track->v, true);

	firstmod = track->ms->modules().back();
	userc = track->ms->chunks().back();

	track->filemodhappy = true;

	vframe = 0;

	if (!track->ms->mustUseAtomicNVFrames())
	{
		assert(track->frames2ignore == 0);
		userc->buffer = samples;
		userc->frameCount = nvframes2read;

		firstmod->runPull();
		if (track->filemodhappy)
			vframe += userc->frameCount;
	}
	else
	{
		bool	eof = false;

		if (track->frames2ignore != 0)
		{
			userc->frameCount = track->frames2ignore;
			userc->allocate(track->frames2ignore * bytes_per_vframe);
			if (!userc->buffer)
				return 0;

			firstmod->runPull();

			/* Have we hit EOF? */
			if (static_cast<ssize_t>(userc->frameCount) < track->frames2ignore)
				eof = true;

			track->frames2ignore = 0;

			userc->deallocate();
		}

		/*
			Now start reading useful frames, until EOF or
			premature EOF.
		*/

		while (track->filemodhappy && !eof && vframe < nvframes2read)
		{
			AFframecount	nvframes2pull;
			userc->buffer = (char *) samples + bytes_per_vframe * vframe;

			if (vframe <= nvframes2read - _AF_ATOMIC_NVFRAMES)
				nvframes2pull = _AF_ATOMIC_NVFRAMES;
			else
				nvframes2pull = nvframes2read - vframe;

			userc->frameCount = nvframes2pull;

			firstmod->runPull();

			if (track->filemodhappy)
			{
				vframe += userc->frameCount;
				if (static_cast<ssize_t>(userc->frameCount) < nvframes2pull)
					eof = true;
			}
		}
	}

	track->nextvframe += vframe;

	return vframe;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	debug.cpp

	This file contains debugging routines for the Audio File
	Library.
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>

#include "audiofile.h"
#include "aupvlist.h"

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "aupvinternal.h"
#include "byteorder.h"
#include "compression.h"
#include "debug.h"
#include "units.h"
#include "util.h"

void _af_print_pvlist (AUpvlist list)
{
	assert(list);

	printf("list.valid: %d\n", list->valid);
	printf("list.count: %zu\n", list->count);

	for (unsigned i=0; i<list->count; i++)
	{
		printf("item %u valid %d, should be %d\n",
			i, list->items[i].valid, _AU_VALID_PVITEM);

		switch (list->items[i].type)
		{
			case AU_PVTYPE_LONG:
				printf("item #%u, parameter %d, long: %ld\n",
					i, list->items[i].parameter,
					list->items[i].value.l);
				break;
			case AU_PVTYPE_DOUBLE:
				printf("item #%u, parameter %d, double: %f\n",
					i, list->items[i].parameter,
					list->items[i].value.d);
				break;
			case AU_PVTYPE_PTR:
				printf("item #%u, parameter %d, pointer: %p\n",
					i, list->items[i].parameter,
					list->items[i].value.v);
				break;

			default:
				printf("item #%u, invalid type %d\n", i,
					list->items[i].type);
				assert(false);
				break;
		}
	}
}

void _af_print_audioformat (AudioFormat *fmt)
{
	/* sampleRate, channelCount */
	printf("{ %7.2f Hz %d ch ", fmt->sampleRate, fmt->channelCount);

	/* sampleFormat, sampleWidth */
	switch (fmt->sampleFormat)
	{
		case AF_SAMPFMT_TWOSCOMP:
			printf("%db 2 ", fmt->sampleWidth);
			break;
		case AF_SAMPFMT_UNSIGNED:
			printf("%db u ", fmt->sampleWidth);
			break;
		case AF_SAMPFMT_FLOAT:
			printf("flt ");
			break;
		case AF_SAMPFMT_DOUBLE:
			printf("dbl ");
			break;
		default:
			printf("%dsampfmt? ", fmt->sampleFormat);
	}

	/* pcm */
	printf("(%.30g+-%.30g [%.30g,%.30g]) ",
		fmt->pcm.intercept, fmt->pcm.slope,
		fmt->pcm.minClip, fmt->pcm.maxClip);

	/* byteOrder */
	switch (fmt->byteOrder)
	{
		case AF_BYTEORDER_BIGENDIAN:
			printf("big ");
			break;
		case AF_BYTEORDER_LITTLEENDIAN:
			printf("little ");
			break;
		default:
			printf("%dbyteorder? ", fmt->byteOrder);
			break;
	}

	/* compression */
	{
		const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
		if (!unit)
			printf("%dcompression?", fmt->compressionType);
		else if (fmt->compressionType == AF_COMPRESSION_NONE)
			printf("pcm");
		else
			printf("%s", unit->label);
	}

	printf(" }");
}

void _af_print_tracks (AFfilehandle filehandle)
{
	for (int i=0; i<filehandle->m_trackCount; i++)
	{
		Track *track = &filehandle->m_tracks[i];
		printf("track %d\n", i);
		printf(" id %d\n", track->id);
		printf(" sample format\n");
		_af_print_audioformat(&track->f);
		printf(" virtual format\n");
		_af_print_audioformat(&track->v);
		printf(" total file frames: %jd\n",
			(intmax_t) track->totalfframes);
		printf(" total virtual frames: %jd\n",
			(intmax_t) track->totalvframes);
		printf(" next file frame: %jd\n",
			(intmax_t) track->nextfframe);
		printf(" next virtual frame: %jd\n",
			(intmax_t) track->nextvframe);
		printf(" frames to ignore: %jd\n",
			(intmax_t) track->frames2ignore);

		printf(" data_size: %jd\n",
			(intmax_t) track->data_size);
		printf(" fpos_first_frame: %jd\n",
			(intmax_t) track->fpos_first_frame);
		printf(" fpos_next_frame: %jd\n",
			(intmax_t) track->fpos_next_frame);
		printf(" fpos_after_data: %jd\n",
			(intmax_t) track->fpos_after_data);

		printf(" channel matrix:");
		_af_print_channel_matrix(track->channelMatrix,
			track->f.channelCount, track->v.channelCount);
		printf("\n");

		printf(" marker count: %d\n", track->markerCount);
	}
}

void _af_print_filehandle (AFfilehandle filehandle)
{
	printf("file handle: 0x%p\n", filehandle);

	if (filehandle->m_valid == _AF_VALID_FILEHANDLE)
		printf("valid\n");
	else
		printf("invalid!\n");

	printf(" access: ");
	if (filehandle->m_access == _AF_READ_ACCESS)
		putchar('r');
	else
		putchar('w');

	printf(" fileFormat: %d\n", filehandle->m_fileFormat);

	printf(" instrument count: %d\n", filehandle->m_instrumentCount);
	printf(" instruments: 0x%p\n", filehandle->m_instruments);

	printf(" miscellaneous count: %d\n", filehandle->m_miscellaneousCount);
	printf(" miscellaneous: 0x%p\n", filehandle->m_miscellaneous);

	printf(" trackCount: %d\n", filehandle->m_trackCount);
	printf(" tracks: 0x%p\n", filehandle->m_tracks);
	_af_print_tracks(filehandle);
}

void _af_print_channel_matrix (double *matrix, int fchans, int vchans)
{
	int v, f;

	if (!matrix)
	{
		printf("NULL");
		return;
	}

	printf("{");
	for (v=0; v < vchans; v++)
	{
		if (v) printf(" ");
		printf("{");
		for (f=0; f < fchans; f++)
		{
			if (f) printf(" ");
			printf("%5.2f", *(matrix + v*fchans + f));
		}
		printf("}");
	}
	printf("}");
}

void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
	char *formatstring, int numberwidth,
	double slope, double intercept, double minclip, double maxclip)
{
	char linebuf[81];
	int wavewidth = 78 - numberwidth*nchannels - 6;
	int c;

	memset(linebuf, ' ', 80);
	linebuf[0] = '|';
	linebuf[wavewidth-1] = '|';
	linebuf[wavewidth] = 0;

	printf("%05jd ", (intmax_t) frameno);

	for (c=0; c < nchannels; c++)
	{
		double pcm = frame[c];
		printf(formatstring, pcm);
	}
	for (c=0; c < nchannels; c++)
	{
		double pcm = frame[c], volts;
		if (maxclip > minclip)
		{
			if (pcm < minclip) pcm = minclip;
			if (pcm > maxclip) pcm = maxclip;
		}
		volts = (pcm - intercept) / slope;
		linebuf[(int)((volts/2 + 0.5)*(wavewidth-3)) + 1] = '0' + c;
	}
	printf("%s\n", linebuf);
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	debug.h

	This header file declares debugging functions for the Audio
	File Library.
*/

#ifndef DEBUG_H
#define DEBUG_H

#include <stdint.h>
#include "audiofile.h"
#include "afinternal.h"

void _af_print_filehandle (AFfilehandle filehandle);
void _af_print_tracks (AFfilehandle filehandle);
void _af_print_channel_matrix (double *matrix, int fchans, int vchans);
void _af_print_pvlist (AUpvlist list);

void _af_print_audioformat (AudioFormat *format);
void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
	char *formatstring, int numberwidth,
	double slope, double intercept, double minclip, double maxclip);

#endif
/*
	Audio File Library
	Copyright (C) 1998, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	error.c

	This file contains the routines used in the Audio File Library's
	error handling.
*/

#include "config.h"

#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include "audiofile.h"

static void defaultErrorFunction (long error, const char *str);

static AFerrfunc errorFunction = defaultErrorFunction;

AFerrfunc afSetErrorHandler (AFerrfunc efunc)
{
	AFerrfunc	old;

	old = errorFunction;
	errorFunction = efunc;

	return old;
}

static void defaultErrorFunction (long error, const char *str)
{
	fprintf(stderr, "Audio File Library: ");
	fprintf(stderr, "%s", str);
	fprintf(stderr, " [error %ld]\n", error);
}

void _af_error (int errorCode, const char *fmt, ...)
{
	char	buf[1024];
	va_list	ap;

	va_start(ap, fmt);

	vsnprintf(buf, 1024, fmt, ap);

	va_end(ap);

	if (errorFunction != NULL)
		errorFunction(errorCode, buf);
}
/*
	Audio File Library
	Copyright (C) 1998, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef ERROR_H
#define ERROR_H

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(__GNUC__) && !defined(__clang__) && !defined(__attribute__)
#define __attribute__(x)
#endif

void _af_error (int errorCode, const char *fmt, ...)
	__attribute__((format(printf, 2, 3)));

#ifdef __cplusplus
}
#endif

#endif
/* Copyright (C) 1989-1991 Apple Computer, Inc.
 *
 * All rights reserved.
 *
 * Warranty Information
 *  Even though Apple has reviewed this software, Apple makes no warranty
 *  or representation, either express or implied, with respect to this
 *  software, its quality, accuracy, merchantability, or fitness for a
 *  particular purpose.  As a result, this software is provided "as is,"
 *  and you, its user, are assuming the entire risk as to its quality
 *  and accuracy.
 *
 * This code may be used and freely distributed as long as it includes
 * this copyright notice and the above warranty information.
 *
 * Machine-independent I/O routines for IEEE floating-point numbers.
 *
 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
 * happens to be infinity on IEEE machines.  Unfortunately, it is
 * impossible to preserve NaN's in a machine-independent way.
 * Infinities are, however, preserved on IEEE machines.
 *
 * These routines have been tested on the following machines:
 *	Apple Macintosh, MPW 3.1 C compiler
 *	Apple Macintosh, THINK C compiler
 *	Silicon Graphics IRIS, MIPS compiler
 *	Cray X/MP and Y/MP
 *	Digital Equipment VAX
 *	Sequent Balance (Multiprocesor 386)
 *	NeXT
 *
 *
 * Implemented by Malcolm Slaney and Ken Turkowski.
 *
 * Malcolm Slaney contributions during 1988-1990 include big- and little-
 * endian file I/O, conversion to and from Motorola's extended 80-bit
 * floating-point format, and conversions to and from IEEE single-
 * precision floating-point format.
 *
 * In 1991, Ken Turkowski implemented the conversions to and from
 * IEEE double-precision format, added more precision to the extended
 * conversions, and accommodated conversions involving +/- infinity,
 * NaN's, and denormalized numbers.
 */

/****************************************************************
 * Extended precision IEEE floating-point conversion routines.
 * Extended is an 80-bit number as defined by Motorola,
 * with a sign bit, 15 bits of exponent (offset 16383?),
 * and a 64-bit mantissa, with no hidden bit.
 ****************************************************************/

#include "extended.h"

#include <math.h>

#ifndef HUGE_VAL
#define HUGE_VAL HUGE
#endif

#define FloatToUnsigned(f) ((unsigned long) (((long) (f - 2147483648.0)) + 2147483647L) + 1)

void _af_convert_to_ieee_extended (double num, unsigned char *bytes)
{
	int				sign;
	int				expon;
	double			fMant, fsMant;
	unsigned long	hiMant, loMant;

	if (num < 0) {
		sign = 0x8000;
		num *= -1;
	} else {
		sign = 0;
	}

	if (num == 0) {
		expon = 0; hiMant = 0; loMant = 0;
	}
	else {
		fMant = frexp(num, &expon);
		if ((expon > 16384) || !(fMant < 1)) {	  /* Infinity or NaN */
			expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
		}
		else {	  /* Finite */
			expon += 16382;
			if (expon < 0) {	/* denormalized */
				fMant = ldexp(fMant, expon);
				expon = 0;
			}
			expon |= sign;
			fMant = ldexp(fMant, 32);
			fsMant = floor(fMant);
			hiMant = FloatToUnsigned(fsMant);
			fMant = ldexp(fMant - fsMant, 32);
			fsMant = floor(fMant);
			loMant = FloatToUnsigned(fsMant);
		}
	}

	bytes[0] = expon >> 8;
	bytes[1] = expon;
	bytes[2] = hiMant >> 24;
	bytes[3] = hiMant >> 16;
	bytes[4] = hiMant >> 8;
	bytes[5] = hiMant;
	bytes[6] = loMant >> 24;
	bytes[7] = loMant >> 16;
	bytes[8] = loMant >> 8;
	bytes[9] = loMant;
}

#define UnsignedToFloat(u) (((double) ((long) (u - 2147483647L - 1))) + 2147483648.0)

double _af_convert_from_ieee_extended (const unsigned char *bytes)
{
	double			f;
	int				expon;
	unsigned long	hiMant, loMant;

	expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
	hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
		| ((unsigned long) (bytes[3] & 0xFF) << 16)
		| ((unsigned long) (bytes[4] & 0xFF) << 8)
		| ((unsigned long) (bytes[5] & 0xFF));
	loMant = ((unsigned long) (bytes[6] & 0xFF) << 24)
		| ((unsigned long) (bytes[7] & 0xFF) << 16)
		| ((unsigned long) (bytes[8] & 0xFF) << 8)
		| ((unsigned long) (bytes[9] & 0xFF));

	if (expon == 0 && hiMant == 0 && loMant == 0) {
		f = 0;
	}
	else {
		if (expon == 0x7FFF) {	  /* Infinity or NaN */
			f = HUGE_VAL;
		}
		else {
			expon -= 16383;
			f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
			f += ldexp(UnsignedToFloat(loMant), expon-=32);
		}
	}

	if (bytes[0] & 0x80)
		return -f;
	else
		return f;
}
/*
	Audio File Library
	Copyright (C) 1998, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	extended.h

	This file defines interfaces to Apple's extended floating-point
	conversion routines.
*/

#ifndef EXTENDED_H
#define EXTENDED_H

#ifdef __cplusplus
extern "C" {
#endif

void _af_convert_to_ieee_extended (double num, unsigned char *bytes);
double _af_convert_from_ieee_extended (const unsigned char *bytes);

#ifdef __cplusplus
}
#endif

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	audiofile.c

	This file implements many of the main interface routines of the
	Audio File Library.
*/

#include "config.h"

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "modules/Module.h"
#include "modules/ModuleState.h"
#include "units.h"
#include "util.h"

AFfileoffset afGetDataOffset (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->fpos_first_frame;
}

AFfileoffset afGetTrackBytes (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->data_size;
}

/*
	afGetFrameSize returns the size (in bytes) of a sample frame from
	the specified track of an audio file.

	stretch3to4 == true: size which user sees
	stretch3to4 == false: size used in file
*/
float afGetFrameSize (AFfilehandle file, int trackid, int stretch3to4)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return _af_format_frame_size(&track->f, stretch3to4);
}

float afGetVirtualFrameSize (AFfilehandle file, int trackid, int stretch3to4)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return _af_format_frame_size(&track->v, stretch3to4);
}

AFframecount afSeekFrame (AFfilehandle file, int trackid, AFframecount frame)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (!file->checkCanRead())
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
		return -1;

	if (frame < 0)
		return track->nextvframe;

	/* Optimize the case of seeking to the current position. */
	if (frame == track->nextvframe)
		return track->nextvframe;

	/* Limit request to the number of frames in the file. */
	if (track->totalvframes != -1)
		if (frame > track->totalvframes)
			frame = track->totalvframes - 1;

	/*
		Now that the modules are not dirty and frame
		represents a valid virtual frame, we call
		_AFsetupmodules again after setting track->nextvframe.

		_AFsetupmodules will look at track->nextvframe and
		compute track->nextfframe in clever and mysterious
		ways.
	*/
	track->nextvframe = frame;

	if (track->ms->setup(file, track) == AF_FAIL)
		return -1;

	return track->nextvframe;
}

AFfileoffset afTellFrame (AFfilehandle file, int trackid)
{
	return afSeekFrame(file, trackid, -1);
}

int afSetVirtualByteOrder (AFfilehandle file, int trackid, int byteorder)
{
	if (!_af_filehandle_ok(file))
		return AF_FAIL;

	Track *track = file->getTrack(trackid);
	if (!track)
		return AF_FAIL;

	if (byteorder != AF_BYTEORDER_BIGENDIAN &&
		byteorder != AF_BYTEORDER_LITTLEENDIAN)
	{
		_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
		return AF_FAIL;
	}

	track->v.byteOrder = byteorder;
	track->ms->setDirty();

	return AF_SUCCEED;
}

int afGetByteOrder (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->f.byteOrder;
}

int afGetVirtualByteOrder (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->v.byteOrder;
}

AFframecount afGetFrameCount (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
		return -1;

	return track->totalvframes;
}

double afGetRate (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->f.sampleRate;
}

int afGetChannels (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->f.channelCount;
}

void afGetSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (sampleFormat)
		*sampleFormat = track->f.sampleFormat;

	if (sampleWidth)
		*sampleWidth = track->f.sampleWidth;
}

void afGetVirtualSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (sampleFormat)
		*sampleFormat = track->v.sampleFormat;

	if (sampleWidth)
		*sampleWidth = track->v.sampleWidth;
}

int afSetVirtualSampleFormat (AFfilehandle file, int trackid,
	int sampleFormat, int sampleWidth)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (_af_set_sample_format(&track->v, sampleFormat, sampleWidth) == AF_FAIL)
		return -1;

	track->ms->setDirty();

	return 0;
}

/* XXXmpruett fix the version */
int afGetFileFormat (AFfilehandle file, int *version)
{
	if (!_af_filehandle_ok(file))
		return -1;

	if (version != NULL)
		*version = file->getVersion();

	return file->m_fileFormat;
}

int afSetVirtualChannels (AFfilehandle file, int trackid, int channelCount)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	track->v.channelCount = channelCount;
	track->ms->setDirty();

	if (track->channelMatrix)
		free(track->channelMatrix);
	track->channelMatrix = NULL;

	return 0;
}

double afGetVirtualRate (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->v.sampleRate;
}

int afSetVirtualRate (AFfilehandle file, int trackid, double rate)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	if (rate < 0)
	{
		_af_error(AF_BAD_RATE, "invalid sampling rate %.30g", rate);
		return -1;
	}

	track->v.sampleRate = rate;
	track->ms->setDirty();

	return 0;
}

void afSetChannelMatrix (AFfilehandle file, int trackid, double* matrix)
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (track->channelMatrix != NULL)
		free(track->channelMatrix);
	track->channelMatrix = NULL;

	if (matrix != NULL)
	{
		int	i, size;

		size = track->v.channelCount * track->f.channelCount;

		track->channelMatrix = (double *) malloc(size * sizeof (double));

		for (i = 0; i < size; i++)
			track->channelMatrix[i] = matrix[i];
	}
}

int afGetVirtualChannels (AFfilehandle file, int trackid)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	return track->v.channelCount;
}
/*
 * This source code is a product of Sun Microsystems, Inc. and is provided
 * for unrestricted use.  Users may copy or modify this source code without
 * charge.
 *
 * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
 * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * Sun source code is provided with no support and without any obligation on
 * the part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 *
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
 * OR ANY PART THEREOF.
 *
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 *
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#define SUPERCEDED

/*
 * g711.c
 *
 * u-law, A-law and linear PCM conversions.
 */
#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
#define	NSEGS		(8)		/* Number of A-law segments. */
#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
#define	SEG_MASK	(0x70)		/* Segment field mask. */

/* see libst.h */
#ifdef	SUPERCEDED

static const short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
			    0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};

static int search(int val, const short *table, int size)
{
	int		i;

	for (i = 0; i < size; i++) {
		if (val <= *table++)
			return (i);
	}
	return (size);
}

/*
 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
 *
 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
 *
 *		Linear Input Code	Compressed Code
 *	------------------------	---------------
 *	0000000wxyza			000wxyz
 *	0000001wxyza			001wxyz
 *	000001wxyzab			010wxyz
 *	00001wxyzabc			011wxyz
 *	0001wxyzabcd			100wxyz
 *	001wxyzabcde			101wxyz
 *	01wxyzabcdef			110wxyz
 *	1wxyzabcdefg			111wxyz
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */
unsigned char
_af_linear2alaw(pcm_val)
	int		pcm_val;	/* 2's complement (16-bit range) */
{
	int		mask;
	int		seg;
	unsigned char	aval;

	if (pcm_val >= 0) {
		mask = 0xD5;		/* sign (7th) bit = 1 */
	} else {
		mask = 0x55;		/* sign bit = 0 */
		pcm_val = -pcm_val - 8;
	}

	/* Convert the scaled magnitude to segment number. */
	seg = search(pcm_val, seg_end, 8);

	/* Combine the sign, segment, and quantization bits. */

	if (seg >= 8)		/* out of range, return maximum value. */
		return (0x7F ^ mask);
	else {
		aval = seg << SEG_SHIFT;
		if (seg < 2)
			aval |= (pcm_val >> 4) & QUANT_MASK;
		else
			aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
		return (aval ^ mask);
	}
}

/*
 * alaw2linear() - Convert an A-law value to 16-bit linear PCM
 *
 */
int
_af_alaw2linear(a_val)
	unsigned char	a_val;
{
	int		t;
	int		seg;

	a_val ^= 0x55;

	t = (a_val & QUANT_MASK) << 4;
	seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
	switch (seg) {
	case 0:
		t += 8;
		break;
	case 1:
		t += 0x108;
		break;
	default:
		t += 0x108;
		t <<= seg - 1;
	}
	return ((a_val & SIGN_BIT) ? t : -t);
}

#define	BIAS		(0x84)		/* Bias for linear code. */

/*
 * linear2ulaw() - Convert a linear PCM value to u-law
 *
 * In order to simplify the encoding process, the original linear magnitude
 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
 * (33 - 8191). The result can be seen in the following encoding table:
 *
 *	Biased Linear Input Code	Compressed Code
 *	------------------------	---------------
 *	00000001wxyza			000wxyz
 *	0000001wxyzab			001wxyz
 *	000001wxyzabc			010wxyz
 *	00001wxyzabcd			011wxyz
 *	0001wxyzabcde			100wxyz
 *	001wxyzabcdef			101wxyz
 *	01wxyzabcdefg			110wxyz
 *	1wxyzabcdefgh			111wxyz
 *
 * Each biased linear code has a leading 1 which identifies the segment
 * number. The value of the segment number is equal to 7 minus the number
 * of leading 0's. The quantization interval is directly available as the
 * four bits wxyz.  * The trailing bits (a - h) are ignored.
 *
 * Ordinarily the complement of the resulting code word is used for
 * transmission, and so the code word is complemented before it is returned.
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */

/* 2's complement (16-bit range) */
unsigned char _af_linear2ulaw (int pcm_val)
{
	int		mask;
	int		seg;
	unsigned char	uval;

	/* Get the sign and the magnitude of the value. */
	if (pcm_val < 0) {
		pcm_val = BIAS - pcm_val;
		mask = 0x7F;
	} else {
		pcm_val += BIAS;
		mask = 0xFF;
	}

	/* Convert the scaled magnitude to segment number. */
	seg = search(pcm_val, seg_end, 8);

	/*
	 * Combine the sign, segment, quantization bits;
	 * and complement the code word.
	 */
	if (seg >= 8)		/* out of range, return maximum value. */
		return (0x7F ^ mask);
	else {
		uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
		return (uval ^ mask);
	}

}

/*
 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
 *
 * First, a biased linear code is derived from the code word. An unbiased
 * output can then be obtained by subtracting 33 from the biased code.
 *
 * Note that this function expects to be passed the complement of the
 * original code word. This is in keeping with ISDN conventions.
 */
int _af_ulaw2linear (unsigned char u_val)
{
	int		t;

	/* Complement to obtain normal u-law value. */
	u_val = ~u_val;

	/*
	 * Extract and bias the quantization bits. Then
	 * shift up by the segment number and subtract out the bias.
	 */
	t = ((u_val & QUANT_MASK) << 3) + BIAS;
	t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;

	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
}

#endif
/*
 * This source code is a product of Sun Microsystems, Inc. and is provided
 * for unrestricted use.  Users may copy or modify this source code without
 * charge.
 *
 * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
 * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * Sun source code is provided with no support and without any obligation on
 * the part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 *
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
 * OR ANY PART THEREOF.
 *
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 *
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

/*
 * g711.h
 *
 * u-law, A-law and linear PCM conversions.
 */

#ifndef G711_H
#define G711_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
 *
 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
 *
 *		Linear Input Code	Compressed Code
 *	------------------------	---------------
 *	0000000wxyza			000wxyz
 *	0000001wxyza			001wxyz
 *	000001wxyzab			010wxyz
 *	00001wxyzabc			011wxyz
 *	0001wxyzabcd			100wxyz
 *	001wxyzabcde			101wxyz
 *	01wxyzabcdef			110wxyz
 *	1wxyzabcdefg			111wxyz
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */

/* pcm_val is 2's complement (16-bit range) */
unsigned char _af_linear2alaw (int pcm_val);

/*
 * alaw2linear() - Convert an A-law value to 16-bit linear PCM
 *
 */

int _af_alaw2linear (unsigned char a_val);

/*
 * linear2ulaw() - Convert a linear PCM value to u-law
 *
 * In order to simplify the encoding process, the original linear magnitude
 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
 * (33 - 8191). The result can be seen in the following encoding table:
 *
 *	Biased Linear Input Code	Compressed Code
 *	------------------------	---------------
 *	00000001wxyza			000wxyz
 *	0000001wxyzab			001wxyz
 *	000001wxyzabc			010wxyz
 *	00001wxyzabcd			011wxyz
 *	0001wxyzabcde			100wxyz
 *	001wxyzabcdef			101wxyz
 *	01wxyzabcdefg			110wxyz
 *	1wxyzabcdefgh			111wxyz
 *
 * Each biased linear code has a leading 1 which identifies the segment
 * number. The value of the segment number is equal to 7 minus the number
 * of leading 0's. The quantization interval is directly available as the
 * four bits wxyz.  * The trailing bits (a - h) are ignored.
 *
 * Ordinarily the complement of the resulting code word is used for
 * transmission, and so the code word is complemented before it is returned.
 *
 * For further information see John C. Bellamy's Digital Telephony, 1982,
 * John Wiley & Sons, pps 98-111 and 472-476.
 */

/* pcm_val is 2's complement (16-bit range) */
unsigned char _af_linear2ulaw (int pcm_val);

/*
 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
 *
 * First, a biased linear code is derived from the code word. An unbiased
 * output can then be obtained by subtracting 33 from the biased code.
 *
 * Note that this function expects to be passed the complement of the
 * original code word. This is in keeping with ISDN conventions.
 */

int _af_ulaw2linear (unsigned char u_val);

#ifdef __cplusplus
}
#endif

#endif /* G711_H */
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "ALAC.h"

#include "Buffer.h"
#include "Compiler.h"
#include "File.h"
#include "FileModule.h"
#include "PacketTable.h"
#include "SimpleModule.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "compression.h"
#include "units.h"
#include "util.h"

#include "../alac/ALACBitUtilities.h"
#include "../alac/ALACDecoder.h"
#include "../alac/ALACEncoder.h"

#include <assert.h>
#include <string.h>

enum
{
	kALACFormatFlag_16BitSourceData = 1,
	kALACFormatFlag_20BitSourceData = 2,
	kALACFormatFlag_24BitSourceData = 3,
	kALACFormatFlag_32BitSourceData = 4
};

class ALAC : public FileModule
{
public:
	static ALAC *createDecompress(Track *, File *, bool canSeek,
		bool headerless, AFframecount *chunkFrames);
	static ALAC *createCompress(Track *, File *, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual ~ALAC();

	virtual const char *name() const OVERRIDE
	{
		return mode() == Compress ?  "alac_compress" : "alac_decompress";
	}
	virtual void describe() OVERRIDE;
	virtual void runPull() OVERRIDE;
	virtual void reset1() OVERRIDE;
	virtual void reset2() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;
	virtual int bufferSize() const OVERRIDE;

private:
	AFframecount m_framesToIgnore;
	AFfileoffset m_savedPositionNextFrame;
	AFframecount m_savedNextFrame;

	SharedPtr<Buffer> m_codecData;
	ALACDecoder *m_decoder;
	ALACEncoder *m_encoder;
	int m_currentPacket;

	ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData);
	void initDecoder();
	void initEncoder();

	AudioFormatDescription outputFormat() const;
};

ALAC::ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData) :
	FileModule(mode, track, fh, canSeek),
	m_savedPositionNextFrame(-1),
	m_savedNextFrame(-1),
	m_codecData(codecData),
	m_decoder(NULL),
	m_encoder(NULL),
	m_currentPacket(0)
{
	if (mode == Decompress)
		initDecoder();
	else
		initEncoder();
}

ALAC::~ALAC()
{
	delete m_decoder;
	delete m_encoder;
}

void ALAC::initDecoder()
{
	m_decoder = new ALACDecoder();
	m_decoder->Init(m_codecData->data(), m_codecData->size());
}

void ALAC::initEncoder()
{
	m_encoder = new ALACEncoder();
	m_encoder->SetFrameSize(m_track->f.framesPerPacket);
	m_encoder->InitializeEncoder(outputFormat());

	uint32_t cookieSize = m_encoder->GetMagicCookieSize(m_track->f.channelCount);
	assert(cookieSize == m_codecData->size());
	m_encoder->GetMagicCookie(m_codecData->data(), &cookieSize);

	void *v = NULL;
	_af_pv_getptr(m_track->f.compressionParams, _AF_CODEC_DATA, &v);
	::memcpy(v, m_codecData->data(), cookieSize);
}

AudioFormatDescription ALAC::outputFormat() const
{
	AudioFormatDescription outputFormat;
	outputFormat.mSampleRate = m_track->f.sampleRate;
	outputFormat.mFormatID = kALACFormatAppleLossless;
	switch (m_track->f.sampleWidth)
	{
		case 16:
			outputFormat.mFormatFlags = kALACFormatFlag_16BitSourceData; break;
		case 20:
			outputFormat.mFormatFlags = kALACFormatFlag_20BitSourceData; break;
		case 24:
			outputFormat.mFormatFlags = kALACFormatFlag_24BitSourceData; break;
		case 32:
			outputFormat.mFormatFlags = kALACFormatFlag_32BitSourceData; break;
		default:
			outputFormat.mFormatFlags = 0; break;
	}
	outputFormat.mFramesPerPacket = m_track->f.framesPerPacket;
	outputFormat.mChannelsPerFrame = m_track->f.channelCount;
	outputFormat.mBytesPerPacket = 0;
	outputFormat.mBytesPerFrame = 0;
	outputFormat.mBitsPerChannel = 0;
	outputFormat.mReserved = 0;
	return outputFormat;
}

void ALAC::describe()
{
	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
}

ALAC *ALAC::createDecompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	AUpvlist pv = (AUpvlist) track->f.compressionParams;
	long codecDataSize;
	if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
		return NULL;
	}

	SharedPtr<Buffer> codecData = new Buffer(codecDataSize);

	void *data;
	if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
		return NULL;
	}

	memcpy(codecData->data(), data, codecDataSize);

	*chunkFrames = track->f.framesPerPacket;

	return new ALAC(Decompress, track, fh, canSeek, codecData.get());
}

ALAC *ALAC::createCompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	AUpvlist pv = (AUpvlist) track->f.compressionParams;
	long codecDataSize;
	if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
		return NULL;
	}

	SharedPtr<Buffer> codecData = new Buffer(codecDataSize);

	void *data;
	if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
		return NULL;
	}

	memcpy(codecData->data(), data, codecDataSize);

	*chunkFrames = track->f.framesPerPacket;

	return new ALAC(Compress, track, fh, canSeek, codecData.get());
}

void ALAC::runPull()
{
	SharedPtr<PacketTable> packetTable = m_track->m_packetTable;
	if (m_currentPacket >= static_cast<int>(packetTable->numPackets()))
	{
		m_outChunk->frameCount = 0;
		return;
	}
	assert(m_currentPacket < static_cast<int>(packetTable->numPackets()));

	ssize_t bytesPerPacket = packetTable->bytesPerPacket(m_currentPacket);
	assert(bytesPerPacket <= bufferSize());

	if (read(m_inChunk->buffer, bytesPerPacket) < bytesPerPacket)
	{
		reportReadError(0, m_track->f.framesPerPacket);
		return;
	}

	BitBuffer bitBuffer;
	BitBufferInit(&bitBuffer, static_cast<uint8_t *>(m_inChunk->buffer),
		bytesPerPacket);

	uint32_t numFrames;
	m_decoder->Decode(&bitBuffer, static_cast<uint8_t *>(m_outChunk->buffer),
		m_track->f.framesPerPacket, m_track->f.channelCount, &numFrames);
	m_outChunk->frameCount = numFrames;

	m_currentPacket++;
}

void ALAC::reset1()
{
	AFframecount nextFrame = m_track->nextfframe;
	m_currentPacket = nextFrame / m_track->f.framesPerPacket;
	m_track->nextfframe = m_currentPacket * m_track->f.framesPerPacket;
	m_framesToIgnore = nextFrame - m_track->nextfframe;
}

void ALAC::reset2()
{
	m_track->fpos_next_frame = m_track->fpos_first_frame +
		m_track->m_packetTable->startOfPacket(m_currentPacket);
	m_track->frames2ignore += m_framesToIgnore;
}

int ALAC::bufferSize() const
{
	return m_track->f.framesPerPacket * m_track->f.channelCount *
		((10 + m_track->f.sampleWidth) / 8) + 1;
}

void ALAC::runPush()
{
	AudioFormatDescription inputFormat;
	inputFormat.mSampleRate = m_track->f.sampleRate;
	inputFormat.mFormatID = kALACFormatLinearPCM;
	inputFormat.mFormatFlags = kALACFormatFlagsNativeEndian;
	inputFormat.mBytesPerPacket = _af_format_frame_size_uncompressed(&m_track->f, false);
	inputFormat.mFramesPerPacket = 1;
	inputFormat.mBytesPerFrame = _af_format_frame_size_uncompressed(&m_track->f, false);
	inputFormat.mChannelsPerFrame = m_track->f.channelCount;
	inputFormat.mBitsPerChannel = m_track->f.sampleWidth;
	inputFormat.mReserved = 0;

	int32_t numBytes = m_inChunk->frameCount * inputFormat.mBytesPerFrame;
	int32_t result = m_encoder->Encode(inputFormat, outputFormat(),
		static_cast<uint8_t *>(m_inChunk->buffer),
		static_cast<uint8_t *>(m_outChunk->buffer),
		&numBytes);
	if (result)
	{
		_af_error(AF_BAD_CODEC_STATE, "error encoding ALAC audio data");
		m_track->filemodhappy = false;
		return;
	}

	assert(numBytes <= bufferSize());

	ssize_t bytesWritten = write(m_outChunk->buffer, numBytes);
	if (bytesWritten != numBytes)
	{
		reportWriteError(0, m_track->f.framesPerPacket);
		return;
	}

	PacketTable *packetTable = m_track->m_packetTable.get();

	packetTable->append(numBytes);

	packetTable->setNumValidFrames(packetTable->numValidFrames() +
		m_inChunk->frameCount);
}

void ALAC::sync1()
{
	m_savedPositionNextFrame = m_track->fpos_next_frame;
	m_savedNextFrame = m_track->nextfframe;
}

void ALAC::sync2()
{
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));

	m_track->fpos_after_data = tell();

	m_track->fpos_next_frame = m_savedPositionNextFrame;
	m_track->nextfframe = m_savedNextFrame;
}

bool _af_alac_format_ok (AudioFormat *f)
{
	if (f->channelCount > kALACMaxChannels)
	{
		_af_error(AF_BAD_CHANNELS,
			"ALAC compression supports a maximum of 8 channels");
		return false;
	}

	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP)
	{
		_af_error(AF_BAD_COMPRESSION,
			"ALAC compression requires signed integer audio data");
		return false;
	}

	if (f->sampleWidth != 16 &&
		f->sampleWidth != 20 &&
		f->sampleWidth != 24 &&
		f->sampleWidth != 32)
	{
		_af_error(AF_BAD_WIDTH,
			"ALAC compression requires 16, 20, 24, or 32 bits per sample");
		return false;
	}

	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"ALAC compression requires native-endian format");
		f->byteOrder = _AF_BYTEORDER_NATIVE;
	}

	return true;
}

FileModule *_af_alac_init_decompress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return ALAC::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}

FileModule *_af_alac_init_compress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return ALAC::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef ALAC_h
#define ALAC_h

#include "Module.h"
#include "afinternal.h"
#include "audiofile.h"

class File;
class FileModule;
struct AudioFormat;
struct Track;

bool _af_alac_format_ok (AudioFormat *f);

FileModule *_af_alac_init_decompress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkframes);

FileModule *_af_alac_init_compress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkframes);

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "BlockCodec.h"

#include "Track.h"

#include <assert.h>

BlockCodec::BlockCodec(Mode mode, Track *track, File *fh, bool canSeek) :
	FileModule(mode, track, fh, canSeek),
	m_bytesPerPacket(-1),
	m_framesPerPacket(-1),
	m_framesToIgnore(-1),
	m_savedPositionNextFrame(-1),
	m_savedNextFrame(-1)
{
	m_framesPerPacket = track->f.framesPerPacket;
	m_bytesPerPacket = track->f.bytesPerPacket;
}

void BlockCodec::runPull()
{
	AFframecount framesToRead = m_outChunk->frameCount;
	AFframecount framesRead = 0;

	assert(framesToRead % m_framesPerPacket == 0);
	int blockCount = framesToRead / m_framesPerPacket;

	// Read the compressed data.
	ssize_t bytesRead = read(m_inChunk->buffer, m_bytesPerPacket * blockCount);
	int blocksRead = bytesRead >= 0 ? bytesRead / m_bytesPerPacket : 0;

	// Decompress into m_outChunk.
	for (int i=0; i<blocksRead; i++)
	{
		if (decodeBlock(static_cast<const uint8_t *>(m_inChunk->buffer) + i * m_bytesPerPacket,
			static_cast<int16_t *>(m_outChunk->buffer) + i * m_framesPerPacket * m_track->f.channelCount)==0)
			break;

		framesRead += m_framesPerPacket;
	}

	m_track->nextfframe += framesRead;

	assert(tell() == m_track->fpos_next_frame);

	if (framesRead < framesToRead)
		reportReadError(framesRead, framesToRead);

	m_outChunk->frameCount = framesRead;
}

void BlockCodec::reset1()
{
	AFframecount nextTrackFrame = m_track->nextfframe;
	m_track->nextfframe = (nextTrackFrame / m_framesPerPacket) *
		m_framesPerPacket;

	m_framesToIgnore = nextTrackFrame - m_track->nextfframe;
}

void BlockCodec::reset2()
{
	m_track->fpos_next_frame = m_track->fpos_first_frame +
		m_bytesPerPacket * (m_track->nextfframe / m_framesPerPacket);
	m_track->frames2ignore += m_framesToIgnore;

	assert(m_track->nextfframe % m_framesPerPacket == 0);
}

void BlockCodec::runPush()
{
	AFframecount framesToWrite = m_inChunk->frameCount;
	int channelCount = m_inChunk->f.channelCount;

	int blockCount = (framesToWrite + m_framesPerPacket - 1) / m_framesPerPacket;
	for (int i=0; i<blockCount; i++)
	{
		encodeBlock(static_cast<const int16_t *>(m_inChunk->buffer) + i * m_framesPerPacket * channelCount,
			static_cast<uint8_t *>(m_outChunk->buffer) + i * m_bytesPerPacket);
	}

	ssize_t bytesWritten = write(m_outChunk->buffer, m_bytesPerPacket * blockCount);
	ssize_t blocksWritten = bytesWritten >= 0 ? bytesWritten / m_bytesPerPacket : 0;
	AFframecount framesWritten = std::min((AFframecount) blocksWritten * m_framesPerPacket, framesToWrite);

	m_track->nextfframe += framesWritten;
	m_track->totalfframes = m_track->nextfframe;

	assert(tell() == m_track->fpos_next_frame);

	if (framesWritten < framesToWrite)
		reportWriteError(framesWritten, framesToWrite);
}

void BlockCodec::sync1()
{
	m_savedPositionNextFrame = m_track->fpos_next_frame;
	m_savedNextFrame = m_track->nextfframe;
}

void BlockCodec::sync2()
{
	assert(tell() == m_track->fpos_next_frame);
	m_track->fpos_after_data = tell();
	m_track->fpos_next_frame = m_savedPositionNextFrame;
	m_track->nextfframe = m_savedNextFrame;
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

// BlockCodec is a base class for codecs with fixed-size packets.

#ifndef BlockCodec_h
#define BlockCodec_h

#include "Compiler.h"
#include "FileModule.h"

class BlockCodec : public FileModule
{
public:
	virtual void runPull() OVERRIDE;
	virtual void reset1() OVERRIDE;
	virtual void reset2() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;

protected:
	int m_bytesPerPacket, m_framesPerPacket;
	AFframecount m_framesToIgnore;
	AFfileoffset m_savedPositionNextFrame;
	AFframecount m_savedNextFrame;

	BlockCodec(Mode, Track *, File *, bool canSeek);

	virtual int decodeBlock(const uint8_t *encoded, int16_t *decoded) = 0;
	virtual int encodeBlock(const int16_t *decoded, uint8_t *encoded) = 0;
};

#endif
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "FLAC.h"

#include "Compiler.h"
#include "FileModule.h"
#include "Features.h"
#include "Track.h"
#include "byteorder.h"

#if ENABLE(FLAC)

#include <FLAC/stream_decoder.h>
#include <FLAC/stream_encoder.h>
#include <assert.h>
#include <string.h>
#include <algorithm>
#include <vector>

class FLACDecoder : public FileModule
{
public:
	static FLACDecoder *create(Track *track, File *file, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual ~FLACDecoder();

	virtual const char *name() const OVERRIDE { return "flac_decompress"; }

	virtual void describe() OVERRIDE;
	virtual void runPull() OVERRIDE;
	virtual void reset1() OVERRIDE;
	virtual void reset2() OVERRIDE;

	virtual bool handlesSeeking() const OVERRIDE { return true; }

private:
	FLACDecoder(Track *track, File *file, bool canSeek);

	FLAC__StreamDecoder *m_decoder;
	std::vector<int32_t *> m_buffer;
	int m_bufferedFrames, m_bufferedOffset;

	void convertAndInterleave(int offset, int frameCount);

	static FLAC__StreamDecoderReadStatus readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		ssize_t result = flac->read(buffer, *bytes);
		if (result > 0)
		{
			*bytes = result;
			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
		}

		*bytes = 0;
		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
	}

	static FLAC__StreamDecoderSeekStatus seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		if (flac->seek(absoluteByteOffset) < 0)
			return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
	}

	static FLAC__StreamDecoderTellStatus tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		off_t result = flac->tell();
		if (result < 0)
			return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
		*absoluteByteOffset = static_cast<FLAC__uint64>(result);
		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
	}

	static FLAC__StreamDecoderLengthStatus lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		off_t result = flac->length();
		if (result < 0)
			return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
		*length = result;
		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
	}

	static FLAC__bool eofCallback(const FLAC__StreamDecoder *, void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		return flac->tell() == flac->length();
	}

	static FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData)
	{
		FLACDecoder *flac = static_cast<FLACDecoder *>(clientData);
		flac->didDecodeFrame(frame, buffer);
		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
	}

	static void metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData)
	{
	}

	static void errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "FLAC decoding error %d", status);
	}

	void didDecodeFrame(const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
	{
		m_bufferedFrames = frame->header.blocksize;
		m_bufferedOffset = 0;
		for (unsigned c=0; c<frame->header.channels; c++)
			memcpy(m_buffer[c], buffer[c], frame->header.blocksize * sizeof (int32_t));

		m_track->nextfframe += frame->header.blocksize;
	}
};

FLACDecoder *FLACDecoder::create(Track *track, File *file, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return new FLACDecoder(track, file, canSeek);
}

FLACDecoder::FLACDecoder(Track *track, File *file, bool canSeek) :
	FileModule(Decompress, track, file, canSeek),
	m_decoder(NULL),
	m_bufferedFrames(0),
	m_bufferedOffset(0)
{
	m_decoder = FLAC__stream_decoder_new();

	if (FLAC__stream_decoder_init_stream(m_decoder,
		readCallback,
		seekCallback,
		tellCallback,
		lengthCallback,
		eofCallback,
		writeCallback,
		metadataCallback,
		errorCallback,
		this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC decoder");
		return;
	}

	m_buffer.resize(m_track->f.channelCount);
	for (int c=0; c<m_track->f.channelCount; c++)
		m_buffer[c] = new int32_t[FLAC__MAX_BLOCK_SIZE];
}

FLACDecoder::~FLACDecoder()
{
	if (m_decoder)
	{
		FLAC__stream_decoder_delete(m_decoder);
		m_decoder = NULL;
	}

	for (size_t i=0; i<m_buffer.size(); i++)
		delete [] m_buffer[i];
}

void FLACDecoder::describe()
{
	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
}

void FLACDecoder::convertAndInterleave(int offset, int frameCount)
{
	int channelCount = m_outChunk->f.channelCount;

	if (m_track->f.sampleWidth == 16)
	{
		int16_t *out = static_cast<int16_t *>(m_outChunk->buffer);
		for (int i=0; i<frameCount; i++)
		{
			for (int c=0; c<channelCount; c++)
			{
				int outIndex = (offset+i) * channelCount + c;
				out[outIndex] = m_buffer[c][m_bufferedOffset + i];
			}
		}
	}
	else if (m_track->f.sampleWidth == 24)
	{
		uint8_t *out = static_cast<uint8_t *>(m_outChunk->buffer);
		for (int i=0; i<frameCount; i++)
		{
			for (int c=0; c<channelCount; c++)
			{
				int32_t in = m_buffer[c][m_bufferedOffset + i];
				uint8_t c0, c1, c2;

#ifdef WORDS_BIGENDIAN
				c0 = (in >> 16) & 0xff;
				c1 = (in >> 8) & 0xff;
				c2 = in & 0xff;
#else
				c2 = (in >> 16) & 0xff;
				c1 = (in >> 8) & 0xff;
				c0 = in & 0xff;
#endif

				int outIndex = (offset+i) * channelCount + c;
				out[3*outIndex] = c0;
				out[3*outIndex+1] = c1;
				out[3*outIndex+2] = c2;
			}
		}
	}

	m_bufferedOffset += frameCount;
}

void FLACDecoder::runPull()
{
	int framesToRead = m_outChunk->frameCount;
	int offset = 0;
	while (framesToRead > 0)
	{
		int bufferedFramesToRead = std::min<int>(framesToRead,
			m_bufferedFrames - m_bufferedOffset);
		convertAndInterleave(offset, bufferedFramesToRead);
		offset += bufferedFramesToRead;
		framesToRead -= bufferedFramesToRead;

		if (framesToRead > 0)
		{
			if (!FLAC__stream_decoder_process_single(m_decoder))
				break;
			if (FLAC__stream_decoder_get_state(m_decoder) >= FLAC__STREAM_DECODER_END_OF_STREAM)
				break;
		}
	}
}

void FLACDecoder::reset1()
{
}

void FLACDecoder::reset2()
{
	if (!FLAC__stream_decoder_seek_absolute(m_decoder, m_track->nextfframe))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not seek to frame %jd",
			static_cast<intmax_t>(m_track->nextfframe));
	}
}

class FLACEncoder : public FileModule
{
public:
	static FLACEncoder *create(Track *track, File *file, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual ~FLACEncoder();

	virtual const char *name() const OVERRIDE { return "flac_compress"; }

	virtual void describe() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;

	virtual bool handlesSeeking() const OVERRIDE { return true; }

private:
	FLAC__StreamEncoder *m_encoder;
	FLAC__int32 *m_buffer;

	FLACEncoder(Track *track, File *file, bool canSeek);

	void convert16To32();
	void convert24To32();

	static FLAC__StreamEncoderSeekStatus seekCallback(const FLAC__StreamEncoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
	{
		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
		off_t result = flac->seek(absoluteByteOffset);
		if (result < 0)
			return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
	}

	static FLAC__StreamEncoderTellStatus tellCallback(const FLAC__StreamEncoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
	{
		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
		off_t offset = flac->tell();
		if (offset < 0)
			return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
		*absoluteByteOffset = static_cast<FLAC__uint64>(offset);
		return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
	}

	static FLAC__StreamEncoderWriteStatus writeCallback(const FLAC__StreamEncoder *, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned currentFrame, void *clientData)
	{
		FLACEncoder *flac = static_cast<FLACEncoder *>(clientData);
		ssize_t result = flac->write(buffer, bytes);
		if (result == static_cast<ssize_t>(bytes))
			return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
	}
};

FLACEncoder::FLACEncoder(Track *track, File *file, bool canSeek) :
	FileModule(Compress, track, file, canSeek),
	m_encoder(NULL),
	m_buffer(NULL)
{
	m_encoder = FLAC__stream_encoder_new();
	if (!m_encoder)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not create encoder");
		return;
	}

	if (!FLAC__stream_encoder_set_channels(m_encoder, m_track->f.channelCount))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not set channel count");
		return;
	}

	if (!FLAC__stream_encoder_set_sample_rate(m_encoder, m_track->f.sampleRate))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not set sample rate");
		return;
	}

	if (!FLAC__stream_encoder_set_bits_per_sample(m_encoder, m_track->f.sampleWidth))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not set sample width");
		return;
	}

	if (FLAC__stream_encoder_init_stream(m_encoder,
		writeCallback,
		seekCallback,
		tellCallback,
		NULL,
		this) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC encoder");
		return;
	}

	m_buffer = new int32_t[FLAC__MAX_BLOCK_SIZE * m_track->f.channelCount];
}

FLACEncoder::~FLACEncoder()
{
	if (m_encoder)
	{
		FLAC__stream_encoder_delete(m_encoder);
		m_encoder = NULL;
	}

	delete [] m_buffer;
}

FLACEncoder *FLACEncoder::create(Track *track, File *file, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return new FLACEncoder(track, file, canSeek);
}

void FLACEncoder::describe()
{
	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
	m_outChunk->f.compressionType = AF_COMPRESSION_FLAC;
}

void FLACEncoder::runPush()
{
	if (m_track->f.sampleWidth == 16)
		convert16To32();
	else if (m_track->f.sampleWidth == 24)
		convert24To32();

	if (!FLAC__stream_encoder_process_interleaved(m_encoder, m_buffer,
		m_inChunk->frameCount))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not encode data into FLAC stream");
	}

	m_track->nextfframe += m_inChunk->frameCount;
	m_track->totalfframes = m_track->nextfframe;
}

void FLACEncoder::sync1()
{
}

void FLACEncoder::sync2()
{
	if (!FLAC__stream_encoder_finish(m_encoder))
	{
		_af_error(AF_BAD_CODEC_CONFIG, "could not finish encoding");
	}
}

void FLACEncoder::convert16To32()
{
	int channelCount = m_track->f.channelCount;
	const int16_t *src = static_cast<const int16_t *>(m_inChunk->buffer);
	for (unsigned i=0; i<m_inChunk->frameCount; i++)
		for (int c=0; c<channelCount; c++)
			m_buffer[channelCount * i + c] = src[channelCount * i + c];
}

void FLACEncoder::convert24To32()
{
	int channelCount = m_track->f.channelCount;
	const uint8_t *src = static_cast<const uint8_t *>(m_inChunk->buffer);
	for (unsigned i=0; i<m_inChunk->frameCount; i++)
		for (int c=0; c<channelCount; c++)
		{
			int srcIndex = channelCount * i + c; 
			int32_t t =
#ifdef WORDS_BIGENDIAN
				(src[3*srcIndex] << 24) |
				(src[3*srcIndex+1] << 16) |
				src[3*srcIndex+2] << 8;
#else
				(src[3*srcIndex+2] << 24) |
				(src[3*srcIndex+1] << 16) |
				src[3*srcIndex] << 8;
#endif
			m_buffer[channelCount * i + c] = t >> 8;
		}
}

bool _af_flac_format_ok(AudioFormat *f)
{
	if (f->channelCount > static_cast<int>(FLAC__MAX_CHANNELS))
	{
		_af_error(AF_BAD_COMPRESSION,
			"FLAC compression supports a maximum of 8 channels");
		return false;
	}

	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP ||
		(f->sampleWidth != 16 && f->sampleWidth != 24))
	{
		_af_error(AF_BAD_COMPRESSION,
			"FLAC compression requires 16- or 24-bit signed integer format");
		return false;
	}

	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"FLAC compression requires native byte order");
		return false;
	}

	return true;
}

#else

bool _af_flac_format_ok(AudioFormat *)
{
	return false;
}

#endif

FileModule *_af_flac_init_compress(Track *track, File *file, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
#if ENABLE(FLAC)
	return FLACEncoder::create(track, file, canSeek, headerless, chunkFrames);
#else
	return NULL;
#endif
}

FileModule *_af_flac_init_decompress(Track *track, File *file, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
#if ENABLE(FLAC)
	return FLACDecoder::create(track, file, canSeek, headerless, chunkFrames);
#else
	return NULL;
#endif
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef FLAC_h
#define FLAC_h

#include "afinternal.h"
#include "audiofile.h"

class FileModule;
class File;
struct AudioFormat;
struct Track;

bool _af_flac_format_ok (AudioFormat *f);

FileModule *_af_flac_init_decompress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);

FileModule *_af_flac_init_compress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);

#endif
/*
	Audio File Library
	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "FileModule.h"

#include "File.h"
#include "Track.h"

#include <errno.h>
#include <string.h>

FileModule::FileModule(Mode mode, Track *track, File *fh, bool canSeek) :
	m_mode(mode),
	m_track(track),
	m_fh(fh),
	m_canSeek(canSeek)
{
	track->fpos_next_frame = track->fpos_first_frame;
	track->frames2ignore = 0;
}

ssize_t FileModule::read(void *data, size_t nbytes)
{
	ssize_t bytesRead = m_fh->read(data, nbytes);
	if (bytesRead > 0)
	{
		m_track->fpos_next_frame += bytesRead;
	}
	return bytesRead;
}

ssize_t FileModule::write(const void *data, size_t nbytes)
{
	ssize_t bytesWritten = m_fh->write(data, nbytes);
	if (bytesWritten > 0)
	{
		m_track->fpos_next_frame += bytesWritten;
		m_track->data_size += bytesWritten;
	}
	return bytesWritten;
}

off_t FileModule::seek(off_t offset)
{
	return m_fh->seek(offset, File::SeekFromBeginning);
}

off_t FileModule::tell()
{
	return m_fh->tell();
}

off_t FileModule::length()
{
	return m_fh->length();
}

void FileModule::reportReadError(AFframecount framesRead,
	AFframecount framesToRead)
{
	// Report error if we haven't already.
	if (!m_track->filemodhappy)
		return;

	_af_error(AF_BAD_READ,
		"file missing data -- read %jd frames, should be %jd",
		static_cast<intmax_t>(m_track->nextfframe),
		static_cast<intmax_t>(m_track->totalfframes));
	m_track->filemodhappy = false;
}

void FileModule::reportWriteError(AFframecount framesWritten,
	AFframecount framesToWrite)
{
	// Report error if we haven't already.
	if (!m_track->filemodhappy)
		return;

	if (framesWritten < 0)
	{
		// Signal I/O error.
		_af_error(AF_BAD_WRITE,
			"unable to write data (%s) -- wrote %jd out of %jd frames",
			strerror(errno),
			static_cast<intmax_t>(m_track->nextfframe),
			static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
	}
	else
	{
		// Signal disk full error.
		_af_error(AF_BAD_WRITE,
			"unable to write data (disk full) -- "
			"wrote %jd out of %jd frames",
			static_cast<intmax_t>(m_track->nextfframe + framesWritten),
			static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
	}

	m_track->filemodhappy = false;
}

int FileModule::bufferSize() const
{
	if (mode() == Compress)
		return outChunk()->frameCount * inChunk()->f.bytesPerFrame(true);
	else
		return inChunk()->frameCount * outChunk()->f.bytesPerFrame(true);
}
/*
	Audio File Library
	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef FILE_MODULE_H
#define FILE_MODULE_H

#include "Module.h"

class FileModule : public Module
{
public:
	virtual bool handlesSeeking() const { return false; }

	virtual int bufferSize() const;

protected:
	enum Mode { Compress, Decompress };
	FileModule(Mode, Track *, File *fh, bool canSeek);

	Mode mode() const { return m_mode; }
	bool canSeek() const { return m_canSeek; }

	ssize_t read(void *data, size_t nbytes);
	ssize_t write(const void *data, size_t nbytes);
	off_t seek(off_t offset);
	off_t tell();
	off_t length();

private:
	Mode m_mode;

protected:
	Track *m_track;

	void reportReadError(AFframecount framesRead, AFframecount framesRequested);
	void reportWriteError(AFframecount framesWritten, AFframecount framesRequested);

private:
	File *m_fh;
	bool m_canSeek;
};

#endif // FILE_MODULE_H
/*
	Audio File Library
	Copyright (C) 2000-2001, Silicon Graphics, Inc.
	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "G711.h"

#include <assert.h>

#include "Compiler.h"
#include "FileModule.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "compression.h"
#include "units.h"
#include "util.h"

#include "../g711.h"

static void ulaw2linear_buf (const uint8_t *ulaw, int16_t *linear, int nsamples)
{
	for (int i=0; i < nsamples; i++)
		linear[i] = _af_ulaw2linear(ulaw[i]);
}

static void linear2ulaw_buf (const int16_t *linear, uint8_t *ulaw, int nsamples)
{
	for (int i=0; i < nsamples; i++)
		ulaw[i] = _af_linear2ulaw(linear[i]);
}

static void alaw2linear_buf (const uint8_t *alaw, int16_t *linear, int nsamples)
{
	for (int i=0; i < nsamples; i++)
		linear[i] = _af_alaw2linear(alaw[i]);
}

static void linear2alaw_buf (const int16_t *linear, uint8_t *alaw, int nsamples)
{
	for (int i=0; i < nsamples; i++)
		alaw[i] = _af_linear2alaw(linear[i]);
}

bool _af_g711_format_ok (AudioFormat *f)
{
	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
	{
		_af_error(AF_BAD_COMPRESSION,
		       "G.711 compression requires 16-bit signed integer format");
		return false;
	}

	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"G.711 compression requires native byte order");
		return false;
	}

	return true;
}

class G711 : public FileModule
{
public:
	static G711 *createCompress(Track *trk, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkframes);
	static G711 *createDecompress(Track *trk, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkframes);

	virtual const char *name() const OVERRIDE
	{
		return mode() == Compress ? "g711compress" : "g711decompress";
	}
	virtual void describe() OVERRIDE;
	virtual void runPull() OVERRIDE;
	virtual void reset2() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;

private:
	G711(Mode mode, Track *track, File *fh, bool canSeek);

	AFfileoffset m_savedPositionNextFrame;
	AFframecount m_savedNextFrame;
};

G711::G711(Mode mode, Track *track, File *fh, bool canSeek) :
	FileModule(mode, track, fh, canSeek),
	m_savedPositionNextFrame(-1),
	m_savedNextFrame(-1)
{
	if (mode == Decompress)
		track->f.compressionParams = AU_NULL_PVLIST;
}

G711 *G711::createCompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkframes)
{
	return new G711(Compress, track, fh, canSeek);
}

void G711::runPush()
{
	AFframecount framesToWrite = m_inChunk->frameCount;
	AFframecount samplesToWrite = m_inChunk->frameCount * m_inChunk->f.channelCount;
	int framesize = m_inChunk->f.channelCount;

	assert(m_track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
		m_track->f.compressionType == AF_COMPRESSION_G711_ALAW);

	/* Compress frames into i->outc. */

	if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
		linear2ulaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
			static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);
	else
		linear2alaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
			static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);

	/* Write the compressed data. */

	ssize_t bytesWritten = write(m_outChunk->buffer, framesize * framesToWrite);
	AFframecount framesWritten = bytesWritten >= 0 ? bytesWritten / framesize : 0;

	if (framesWritten != framesToWrite)
		reportWriteError(framesWritten, framesToWrite);

	m_track->nextfframe += framesWritten;
	m_track->totalfframes = m_track->nextfframe;

	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
}

void G711::sync1()
{
	m_savedPositionNextFrame = m_track->fpos_next_frame;
	m_savedNextFrame = m_track->nextfframe;
}

void G711::sync2()
{
	/* sanity check. */
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));

	/* We can afford to do an lseek just in case because sync2 is rare. */
	m_track->fpos_after_data = tell();

	m_track->fpos_next_frame = m_savedPositionNextFrame;
	m_track->nextfframe = m_savedNextFrame;
}

void G711::describe()
{
	if (mode() == Compress)
	{
		m_outChunk->f.compressionType = m_track->f.compressionType;
	}
	else
	{
		m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
		m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
	}
}

G711 *G711::createDecompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkframes)
{
	return new G711(Decompress, track, fh, canSeek);
}

void G711::runPull()
{
	AFframecount framesToRead = m_outChunk->frameCount;
	AFframecount samplesToRead = m_outChunk->frameCount * m_outChunk->f.channelCount;
	int framesize = m_outChunk->f.channelCount;

	/* Read the compressed frames. */

	ssize_t bytesRead = read(m_inChunk->buffer, framesize * framesToRead);
	AFframecount framesRead = bytesRead >= 0 ? bytesRead / framesize : 0;

	/* Decompress into i->outc. */

	if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
		ulaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
			static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);
	else
		alaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
			static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);

	m_track->nextfframe += framesRead;
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));

	/*
		If we got EOF from read, then we return the actual amount read.

		Complain only if there should have been more frames in the file.
	*/

	if (m_track->totalfframes != -1 && framesRead != framesToRead)
		reportReadError(framesRead, framesToRead);

	m_outChunk->frameCount = framesRead;
}

void G711::reset2()
{
	int framesize = m_inChunk->f.channelCount;

	m_track->fpos_next_frame = m_track->fpos_first_frame +
		framesize * m_track->nextfframe;

	m_track->frames2ignore = 0;
}

FileModule *_AFg711initcompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return G711::createCompress(track, fh, canSeek, headerless, chunkFrames);
}

FileModule *_AFg711initdecompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return G711::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	g711.h
*/

#ifndef MODULES_G711_H
#define MODULES_G711_H

#include "afinternal.h"
#include "audiofile.h"

class File;
class FileModule;
struct AudioFormat;
struct Track;

bool _af_g711_format_ok (AudioFormat *f);

FileModule *_AFg711initcompress (Track *, File *, bool canSeek,
	bool headerless, AFframecount *chunkframes);

FileModule *_AFg711initdecompress (Track *, File *, bool canSeek,
	bool headerless, AFframecount *chunkframes);

#endif /* MODULES_G711_H */
/*
	Audio File Library
	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	This module implements IMA ADPCM compression.
*/

#include "config.h"
#include "IMA.h"

#include <assert.h>

#include <audiofile.h>

#include "BlockCodec.h"
#include "Compiler.h"
#include "File.h"
#include "Track.h"
#include "afinternal.h"
#include "byteorder.h"
#include "util.h"
#include "../pcm.h"

struct adpcmState
{
	int previousValue;	// previous output value
	int index;			// index into step table

	adpcmState()
	{
		previousValue = 0;
		index = 0;
	}
};

class IMA : public BlockCodec
{
public:
	static IMA *createDecompress(Track *track, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkFrames);
	static IMA *createCompress(Track *track, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual ~IMA();

	virtual const char *name() const OVERRIDE
	{
		return mode() == Compress ?
			"ima_adpcm_compress" : "ima_adpcm_decompress";
	}
	virtual void describe() OVERRIDE;

private:
	int m_imaType;
	adpcmState *m_adpcmState;

	IMA(Mode, Track *, File *fh, bool canSeek);

	int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE;
	int decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded);
	int decodeBlockQT(const uint8_t *encoded, int16_t *decoded);

	int encodeBlock(const int16_t *input, uint8_t *output) OVERRIDE;
	int encodeBlockWAVE(const int16_t *input, uint8_t *output);
	int encodeBlockQT(const int16_t *input, uint8_t *output);
};

IMA::IMA(Mode mode, Track *track, File *fh, bool canSeek) :
	BlockCodec(mode, track, fh, canSeek),
	m_imaType(0)
{
	AUpvlist pv = (AUpvlist) track->f.compressionParams;

	m_framesPerPacket = track->f.framesPerPacket;
	m_bytesPerPacket = track->f.bytesPerPacket;

	long l;
	if (_af_pv_getlong(pv, _AF_IMA_ADPCM_TYPE, &l))
		m_imaType = l;

	m_adpcmState = new adpcmState[track->f.channelCount];
}

IMA::~IMA()
{
	delete [] m_adpcmState;
}

int IMA::decodeBlock(const uint8_t *encoded, int16_t *decoded)
{
	if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE)
		return decodeBlockWAVE(encoded, decoded);
	else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT)
		return decodeBlockQT(encoded, decoded);
	return 0;
}

static const int8_t indexTable[16] =
{
	-1, -1, -1, -1, 2, 4, 6, 8,
	-1, -1, -1, -1, 2, 4, 6, 8,
};

static const int16_t stepTable[89] =
{
	7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
	19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
	50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
	130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
	337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
	876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
	2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
	5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
	15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};

static inline int clamp(int x, int low, int high)
{
	if (x < low) return low;
	if (x > high) return high;
	return x;
}

static inline int16_t decodeSample(adpcmState &state, uint8_t code)
{
	int step = stepTable[state.index];

	int diff = step >> 3;
	if (code & 4) diff += step;
	if (code & 2) diff += step>>1;
	if (code & 1) diff += step>>2;

	int predictor = state.previousValue;
	if (code & 8)
		predictor -= diff;
	else
		predictor += diff;

	state.previousValue = clamp(predictor, MIN_INT16, MAX_INT16);
	state.index = clamp(state.index + indexTable[code], 0, 88);
	return state.previousValue;
}

int IMA::decodeBlockWAVE(const uint8_t *encoded, int16_t *decoded)
{
	int channelCount = m_track->f.channelCount;

	for (int c=0; c<channelCount; c++)
	{
		m_adpcmState[c].previousValue = (encoded[1]<<8) | encoded[0];
		if (encoded[1] & 0x80)
			m_adpcmState[c].previousValue -= 0x10000;

		m_adpcmState[c].index = encoded[2];

		*decoded++ = m_adpcmState[c].previousValue;

		encoded += 4;
	}

	for (int n=0; n<m_framesPerPacket - 1; n += 8)
	{
		for (int c=0; c<channelCount; c++)
		{
			int16_t *output = decoded + c;
			for (int s=0; s<4; s++)
			{
				*output = decodeSample(m_adpcmState[c], *encoded & 0xf);
				output += channelCount;
				*output = decodeSample(m_adpcmState[c], *encoded >> 4);
				output += channelCount;
				encoded++;
			}
		}

		decoded += channelCount * 8;
	}

	return m_framesPerPacket * channelCount * sizeof (int16_t);
}


int IMA::decodeBlockQT(const uint8_t *encoded, int16_t *decoded)
{
	int channelCount = m_track->f.channelCount;

	for (int c=0; c<channelCount; c++)
	{
		adpcmState state;
		int predictor = (encoded[0] << 8) | (encoded[1] & 0x80);
		if (predictor & 0x8000)
			predictor -= 0x10000;

		state.previousValue = clamp(predictor, MIN_INT16, MAX_INT16);
		state.index = encoded[1] & 0x7f;
		encoded += 2;

		for (int n=0; n<m_framesPerPacket; n+=2)
		{
			uint8_t e = *encoded;
			decoded[n*channelCount + c] = decodeSample(state, e & 0xf);
			decoded[(n+1)*channelCount + c] = decodeSample(state, e >> 4);
			encoded++;
		}
	}

	return m_framesPerPacket * channelCount * sizeof (int16_t);
}

int IMA::encodeBlock(const int16_t *input, uint8_t *output)
{
	if (m_imaType == _AF_IMA_ADPCM_TYPE_WAVE)
		return encodeBlockWAVE(input, output);
	else if (m_imaType == _AF_IMA_ADPCM_TYPE_QT)
		return encodeBlockQT(input, output);
	return 0;
}

static inline uint8_t encodeSample(adpcmState &state, int16_t sample)
{
	int step = stepTable[state.index];
	int diff = sample - state.previousValue;
	int vpdiff = step >> 3;
	uint8_t code = 0;
	if (diff < 0)
	{
		code = 8;
		diff = -diff;
	}
	if (diff >= step)
	{
		code |= 4;
		diff -= step;
		vpdiff += step;
	}
	step >>= 1;
	if (diff >= step)
	{
		code |= 2;
		diff -= step;
		vpdiff += step;
	}
	step >>= 1;
	if (diff >= step)
	{
		code |= 1;
		vpdiff += step;
	}

	if (code & 8)
		vpdiff = -vpdiff;
	state.previousValue = clamp(state.previousValue + vpdiff,
		MIN_INT16, MAX_INT16);

	state.index = clamp(state.index + indexTable[code], 0, 88);
	return code & 0xf;
}

int IMA::encodeBlockWAVE(const int16_t *input, uint8_t *output)
{
	int channelCount = m_track->f.channelCount;

	for (int c=0; c<channelCount; c++)
	{
		output[0] = m_adpcmState[c].previousValue & 0xff;
		output[1] = m_adpcmState[c].previousValue >> 8;
		output[2] = m_adpcmState[c].index;
		output[3] = 0;

		output += 4;
	}

	for (int n=0; n<m_framesPerPacket - 1; n += 8)
	{
		for (int c=0; c<channelCount; c++)
		{
			const int16_t *currentInput = input + c;
			for (int s=0; s<4; s++)
			{
				uint8_t encodedValue = encodeSample(m_adpcmState[c], *currentInput);
				currentInput += channelCount;
				encodedValue |= encodeSample(m_adpcmState[c], *currentInput) << 4;
				currentInput += channelCount;
				*output++ = encodedValue;
			}
		}

		input += channelCount * 8;
	}

	return m_bytesPerPacket;
}

int IMA::encodeBlockQT(const int16_t *input, uint8_t *output)
{
	int channelCount = m_track->f.channelCount;

	for (int c=0; c<channelCount; c++)
	{
		adpcmState state = m_adpcmState[c];

		state.previousValue &= ~0x7f;

		output[0] = (state.previousValue >> 8) & 0xff;
		output[1] = (state.previousValue & 0x80) | (state.index & 0x7f);
		output += 2;

		for (int n=0; n<m_framesPerPacket; n+=2)
		{
			uint8_t encoded = encodeSample(state, input[n*channelCount + c]);
			encoded |= encodeSample(state, input[(n+1)*channelCount + c]) << 4;
			*output++ = encoded;
		}

		m_adpcmState[c] = state;
	}

	return m_bytesPerPacket;
}

bool _af_ima_adpcm_format_ok (AudioFormat *f)
{
	if (f->channelCount != 1 && f->channelCount != 2)
	{
		_af_error(AF_BAD_COMPRESSION,
			"IMA ADPCM compression requires 1 or 2 channels");
		return false;
	}

	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
	{
		_af_error(AF_BAD_COMPRESSION,
			"IMA ADPCM compression requires 16-bit signed integer format");
		return false;
	}

	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"IMA ADPCM compression requires native byte order");
		return false;
	}

	return true;
}

void IMA::describe()
{
	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
}

IMA *IMA::createDecompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	IMA *ima = new IMA(Decompress, track, fh, canSeek);

	if (!ima->m_imaType)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "IMA type not set");
		delete ima;
		return NULL;
	}

	*chunkFrames = ima->m_framesPerPacket;
	return ima;
}

IMA *IMA::createCompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	IMA *ima = new IMA(Compress, track, fh, canSeek);

	if (!ima->m_imaType)
	{
		_af_error(AF_BAD_CODEC_CONFIG, "IMA type not set");
		delete ima;
		return NULL;
	}

	*chunkFrames = ima->m_framesPerPacket;
	return ima;
}

FileModule *_af_ima_adpcm_init_decompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return IMA::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}

FileModule *_af_ima_adpcm_init_compress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return IMA::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
/*
	Audio File Library
	Copyright (C) 2010-2012, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	IMA.h

	This module declares the interface for the IMA ADPCM
	compression module.
*/

#ifndef IMA_H
#define IMA_H

#include "afinternal.h"
#include "audiofile.h"

class File;
class FileModule;
struct AudioFormat;
struct Track;

bool _af_ima_adpcm_format_ok(AudioFormat *);

FileModule *_af_ima_adpcm_init_compress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);
FileModule *_af_ima_adpcm_init_decompress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);

#endif
/*
	Audio File Library
	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	This module implements Microsoft ADPCM compression.
*/

#include "config.h"
#include "MSADPCM.h"

#include <assert.h>
#include <cstdlib>
#include <limits>
#include <string.h>

#include "BlockCodec.h"
#include "Compiler.h"
#include "File.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"
#include "../pcm.h"

struct ms_adpcm_state
{
	uint8_t predictorIndex;
	int delta;
	int16_t sample1, sample2;

	ms_adpcm_state()
	{
		predictorIndex = 0;
		delta = 16;
		sample1 = 0;
		sample2 = 0;
	}
};

class MSADPCM : public BlockCodec
{
public:
	static MSADPCM *createDecompress(Track *, File *, bool canSeek,
		bool headerless, AFframecount *chunkFrames);
	static MSADPCM *createCompress(Track *, File *, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual ~MSADPCM();

	bool initializeCoefficients();

	virtual const char *name() const OVERRIDE
	{
		return mode() == Compress ? "ms_adpcm_compress" : "ms_adpcm_decompress";
	}
	virtual void describe() OVERRIDE;

private:
	// m_coefficients is an array of m_numCoefficients ADPCM coefficient pairs.
	int m_numCoefficients;
	int16_t m_coefficients[256][2];

	ms_adpcm_state *m_state;

	MSADPCM(Mode mode, Track *track, File *fh, bool canSeek);

	int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE;
	int encodeBlock(const int16_t *decoded, uint8_t *encoded) OVERRIDE;
	void choosePredictorForBlock(const int16_t *decoded);
};

static inline int clamp(int x, int low, int high)
{
	if (x < low) return low;
	if (x > high) return high;
	return x;
}

static const int16_t adaptationTable[] =
{
	230, 230, 230, 230, 307, 409, 512, 614,
	768, 614, 512, 409, 307, 230, 230, 230
};

int firstBitSet(int x)
{
        int position=0;
        while (x!=0)
        {
                x>>=1;
                ++position;
        }
        return position;
}

#ifndef __has_builtin
#define __has_builtin(x) 0
#endif

int multiplyCheckOverflow(int a, int b, int *result)
{
#if (defined __GNUC__ && __GNUC__ >= 5) || ( __clang__ && __has_builtin(__builtin_mul_overflow))
	return __builtin_mul_overflow(a, b, result);
#else
	if (firstBitSet(a)+firstBitSet(b)>31) // int is signed, so we can't use 32 bits
		return true;
	*result = a * b;
	return false;
#endif
}


// Compute a linear PCM value from the given differential coded value.
static int16_t decodeSample(ms_adpcm_state &state,
	uint8_t code, const int16_t *coefficient, bool *ok=NULL)
{
	int linearSample = (state.sample1 * coefficient[0] +
		state.sample2 * coefficient[1]) >> 8;
	int delta;

	linearSample += ((code & 0x08) ? (code - 0x10) : code) * state.delta;

	linearSample = clamp(linearSample, MIN_INT16, MAX_INT16);

	if (multiplyCheckOverflow(state.delta, adaptationTable[code], &delta))
	{
                if (ok) *ok=false;
		_af_error(AF_BAD_COMPRESSION, "Error decoding sample");
		return 0;
	}
	delta >>= 8;
	if (delta < 16)
		delta = 16;

	state.delta = delta;
	state.sample2 = state.sample1;
	state.sample1 = linearSample;
	if (ok) *ok=true;

	return static_cast<int16_t>(linearSample);
}

// Compute a differential coded value from the given linear PCM sample.
static uint8_t encodeSample(ms_adpcm_state &state, int16_t sample,
	const int16_t *coefficient)
{
	int predictor = (state.sample1 * coefficient[0] +
		state.sample2 * coefficient[1]) >> 8;
	int code = sample - predictor;
	int bias = state.delta / 2;
	if (code < 0)
		bias = -bias;
	code = (code + bias) / state.delta;
	code = clamp(code, -8, 7) & 0xf;

	predictor += ((code & 0x8) ? (code - 0x10) : code) * state.delta;

	state.sample2 = state.sample1;
	state.sample1 = clamp(predictor, MIN_INT16, MAX_INT16);
	state.delta = (adaptationTable[code] * state.delta) >> 8;
	if (state.delta < 16)
		state.delta = 16;
	return code;
}

// Decode one block of MS ADPCM data.
int MSADPCM::decodeBlock(const uint8_t *encoded, int16_t *decoded)
{
	ms_adpcm_state decoderState[2];
	ms_adpcm_state *state[2];

	int channelCount = m_track->f.channelCount;

	// Calculate the number of bytes needed for decoded data.
	int outputLength = m_framesPerPacket * sizeof (int16_t) * channelCount;

	state[0] = &decoderState[0];
	if (channelCount == 2)
		state[1] = &decoderState[1];
	else
		state[1] = &decoderState[0];

	// Initialize block predictor.
	for (int i=0; i<channelCount; i++)
	{
		state[i]->predictorIndex = *encoded++;
		assert(state[i]->predictorIndex < m_numCoefficients);
	}

	// Initialize delta.
	for (int i=0; i<channelCount; i++)
	{
		state[i]->delta = (encoded[1]<<8) | encoded[0];
		encoded += sizeof (uint16_t);
	}

	// Initialize first two samples.
	for (int i=0; i<channelCount; i++)
	{
		state[i]->sample1 = (encoded[1]<<8) | encoded[0];
		encoded += sizeof (uint16_t);
	}

	for (int i=0; i<channelCount; i++)
	{
		state[i]->sample2 = (encoded[1]<<8) | encoded[0];
		encoded += sizeof (uint16_t);
	}

	const int16_t *coefficient[2] =
	{
		m_coefficients[state[0]->predictorIndex],
		m_coefficients[state[1]->predictorIndex]
	};

	for (int i=0; i<channelCount; i++)
		*decoded++ = state[i]->sample2;

	for (int i=0; i<channelCount; i++)
		*decoded++ = state[i]->sample1;

	/*
		The first two samples have already been 'decoded' in
		the block header.
	*/
	int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;

	while (samplesRemaining > 0)
	{
		uint8_t code;
		int16_t newSample;
		bool ok;

		code = *encoded >> 4;
		newSample = decodeSample(*state[0], code, coefficient[0], &ok);
		if (!ok) return 0;
		*decoded++ = newSample;

		code = *encoded & 0x0f;
		newSample = decodeSample(*state[1], code, coefficient[1], &ok);
		if (!ok) return 0;
		*decoded++ = newSample;

		encoded++;
		samplesRemaining -= 2;
	}

	return outputLength;
}

int MSADPCM::encodeBlock(const int16_t *decoded, uint8_t *encoded)
{
	choosePredictorForBlock(decoded);

	int channelCount = m_track->f.channelCount;

	// Encode predictor.
	for (int c=0; c<channelCount; c++)
		*encoded++ = m_state[c].predictorIndex;

	// Encode delta.
	for (int c=0; c<channelCount; c++)
	{
		*encoded++ = m_state[c].delta & 0xff;
		*encoded++ = m_state[c].delta >> 8;
	}

	// Enccode first two samples.
	for (int c=0; c<channelCount; c++)
		m_state[c].sample2 = *decoded++;

	for (int c=0; c<channelCount; c++)
		m_state[c].sample1 = *decoded++;

	for (int c=0; c<channelCount; c++)
	{
		*encoded++ = m_state[c].sample1 & 0xff;
		*encoded++ = m_state[c].sample1 >> 8;
	}

	for (int c=0; c<channelCount; c++)
	{
		*encoded++ = m_state[c].sample2 & 0xff;
		*encoded++ = m_state[c].sample2 >> 8;
	}

	ms_adpcm_state *state[2] = { &m_state[0], &m_state[channelCount - 1] };
	const int16_t *coefficient[2] =
	{
		m_coefficients[state[0]->predictorIndex],
		m_coefficients[state[1]->predictorIndex]
	};

	int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;
	while (samplesRemaining > 0)
	{
		uint8_t code1 = encodeSample(*state[0], *decoded++, coefficient[0]);
		uint8_t code2 = encodeSample(*state[1], *decoded++, coefficient[1]);

		*encoded++ = (code1 << 4) | code2;
		samplesRemaining -= 2;
	}

	return m_bytesPerPacket;
}

void MSADPCM::choosePredictorForBlock(const int16_t *decoded)
{
	const int kPredictorSampleLength = 3;

	int channelCount = m_track->f.channelCount;

	for (int c=0; c<channelCount; c++)
	{
		int bestPredictorIndex = 0;
		int bestPredictorError = std::numeric_limits<int>::max();
		for (int k=0; k<m_numCoefficients; k++)
		{
			int a0 = m_coefficients[k][0];
			int a1 = m_coefficients[k][1];

			int currentPredictorError = 0;
			for (int i=2; i<2+kPredictorSampleLength; i++)
			{
				int error = std::abs(decoded[i*channelCount + c] -
					((a0 * decoded[(i-1)*channelCount + c] +
					a1 * decoded[(i-2)*channelCount + c]) >> 8));
				currentPredictorError += error;
			}

			currentPredictorError /= 4 * kPredictorSampleLength;

			if (currentPredictorError < bestPredictorError)
			{
				bestPredictorError = currentPredictorError;
				bestPredictorIndex = k;
			}

			if (!currentPredictorError)
				break;
		}

		if (bestPredictorError < 16)
			bestPredictorError = 16;

		m_state[c].predictorIndex = bestPredictorIndex;
		m_state[c].delta = bestPredictorError;
	}
}

void MSADPCM::describe()
{
	m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
	m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
	m_outChunk->f.compressionParams = AU_NULL_PVLIST;
}

MSADPCM::MSADPCM(Mode mode, Track *track, File *fh, bool canSeek) :
	BlockCodec(mode, track, fh, canSeek),
	m_numCoefficients(0),
	m_state(NULL)
{
	m_state = new ms_adpcm_state[m_track->f.channelCount];
}

MSADPCM::~MSADPCM()
{
	delete [] m_state;
}

bool MSADPCM::initializeCoefficients()
{
	AUpvlist pv = m_track->f.compressionParams;

	long l;
	if (_af_pv_getlong(pv, _AF_MS_ADPCM_NUM_COEFFICIENTS, &l))
	{
		m_numCoefficients = l;
	}
	else
	{
		_af_error(AF_BAD_CODEC_CONFIG, "number of coefficients not set");
		return false;
	}

	void *v;
	if (_af_pv_getptr(pv, _AF_MS_ADPCM_COEFFICIENTS, &v))
	{
		memcpy(m_coefficients, v, m_numCoefficients * 2 * sizeof (int16_t));
	}
	else
	{
		_af_error(AF_BAD_CODEC_CONFIG, "coefficient array not set");
		return false;
	}

	return true;
}

MSADPCM *MSADPCM::createDecompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	MSADPCM *msadpcm = new MSADPCM(Decompress, track, fh, canSeek);

	if (!msadpcm->initializeCoefficients())
	{
		delete msadpcm;
		return NULL;
	}

	*chunkFrames = msadpcm->m_framesPerPacket;

	return msadpcm;
}

MSADPCM *MSADPCM::createCompress(Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	assert(fh->tell() == track->fpos_first_frame);

	MSADPCM *msadpcm = new MSADPCM(Compress, track, fh, canSeek);

	if (!msadpcm->initializeCoefficients())
	{
		delete msadpcm;
		return NULL;
	}

	*chunkFrames = msadpcm->m_framesPerPacket;

	return msadpcm;
}

bool _af_ms_adpcm_format_ok (AudioFormat *f)
{
	if (f->channelCount != 1 && f->channelCount != 2)
	{
		_af_error(AF_BAD_COMPRESSION,
			"MS ADPCM compression requires 1 or 2 channels");
		return false;
	}

	if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
	{
		_af_error(AF_BAD_COMPRESSION,
			"MS ADPCM compression requires 16-bit signed integer format");
		return false;
	}

	if (f->byteOrder != _AF_BYTEORDER_NATIVE)
	{
		_af_error(AF_BAD_COMPRESSION,
			"MS ADPCM compression requires native byte order");
		return false;
	}

	return true;
}

FileModule *_af_ms_adpcm_init_decompress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return MSADPCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}

FileModule *_af_ms_adpcm_init_compress (Track *track, File *fh,
	bool canSeek, bool headerless, AFframecount *chunkFrames)
{
	return MSADPCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
/*
	Audio File Library
	Copyright (C) 2001, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	msadpcm.h

	This module declares the interface for the Microsoft ADPCM
	compression module.
*/

#ifndef MSADPCM_H
#define MSADPCM_H

#include "afinternal.h"
#include "audiofile.h"

class File;
class FileModule;
struct AudioFormat;
struct Track;

bool _af_ms_adpcm_format_ok (AudioFormat *f);

FileModule *_af_ms_adpcm_init_decompress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);

FileModule *_af_ms_adpcm_init_compress(Track *, File *,
	bool canSeek, bool headerless, AFframecount *chunkframes);

#endif
noinst_LTLIBRARIES = libmodules.la

AM_CPPFLAGS = -I$(srcdir)/..

libmodules_la_SOURCES = \
	ALAC.cpp \
	ALAC.h \
	BlockCodec.cpp \
	BlockCodec.h \
	FLAC.cpp \
	FLAC.h \
	FileModule.cpp \
	FileModule.h \
	G711.cpp \
	G711.h \
	IMA.cpp \
	IMA.h \
	Module.cpp \
	Module.h \
	ModuleState.cpp \
	ModuleState.h \
	MSADPCM.cpp \
	MSADPCM.h \
	PCM.cpp \
	PCM.h \
	RebufferModule.cpp \
	RebufferModule.h \
	SimpleModule.cpp \
	SimpleModule.h

# GNU gcc
# AM_CFLAGS = -Wall -g
# SGI MIPSpro cc
# AM_CFLAGS = -fullwarn -g
# No debugging.
AM_CFLAGS = \
	-DNDEBUG \
	-Wall \
	-Wno-multichar \
	$(WERROR_CFLAGS) \
	$(COVERAGE_CFLAGS) \
	$(FLAC_CFLAGS) \
	-fvisibility=hidden
AM_CXXFLAGS = $(AM_CFLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden

CLEANFILES = *.gcda *.gcno
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "Module.h"

#include "File.h"
#include "SimpleModule.h"
#include "byteorder.h"
#include "compression.h"
#include "units.h"
#include "../pcm.h"

Module::Module() :
	m_sink(NULL)
{
}

Module::~Module()
{
}

void Module::setSink(Module *module) { m_sink = module; }
void Module::setSource(Module *module) { m_source = module; }

const char *Module::name() const { return ""; }

void Module::describe()
{
}

void Module::maxPull()
{
	m_inChunk->frameCount = m_outChunk->frameCount;
}

void Module::maxPush()
{
	m_outChunk->frameCount = m_inChunk->frameCount;
}

void Module::runPull()
{
}

void Module::runPush()
{
}

void Module::pull(size_t frames)
{
	m_inChunk->frameCount = frames;
	m_source->runPull();
}

void Module::push(size_t frames)
{
	m_outChunk->frameCount = frames;
	m_sink->runPush();
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef MODULE_H
#define MODULE_H

#include "AudioFormat.h"
#include "Shared.h"
#include "afinternal.h"

#include <vector>

enum FormatCode
{
	kUndefined = -1,
	kInt8,
	kInt16,
	kInt24,
	kInt32,
	kFloat,
	kDouble,
};

class Chunk : public Shared<Chunk>
{
public:
	void *buffer;
	size_t frameCount;
	AudioFormat f;
	bool ownsMemory;

	Chunk() : buffer(NULL), frameCount(0), ownsMemory(false) { }
	~Chunk()
	{
		deallocate();
	}
	void allocate(size_t capacity)
	{
		deallocate();
		ownsMemory = true;
		buffer = ::operator new(capacity);
	}
	void deallocate()
	{
		if (ownsMemory)
			::operator delete(buffer);
		ownsMemory = false;
		buffer = NULL;
	}
};

class Module : public Shared<Module>
{
public:
	Module();
	virtual ~Module();

	void setSink(Module *);
	void setSource(Module *);
	Chunk *inChunk() const { return m_inChunk.get(); }
	void setInChunk(Chunk *chunk) { m_inChunk = chunk; }
	Chunk *outChunk() const { return m_outChunk.get(); }
	void setOutChunk(Chunk *chunk) { m_outChunk = chunk; }

	virtual const char *name() const;
	/*
		Set format of m_outChunk based on how this module transforms m_inChunk.
	*/
	virtual void describe();
	/*
		Set frame count of m_inChunk to the maximum number of frames needed to
		produce frame count of m_outChunk.
	*/
	virtual void maxPull();
	/*
		Set frame count of m_outChunk to the maximum number of frames needed to
		produce frame count of m_inChunk.
	*/
	virtual void maxPush();
	virtual void runPull();
	virtual void reset1() { }
	virtual void reset2() { }
	virtual void runPush();
	virtual void sync1() { }
	virtual void sync2() { }

protected:
	SharedPtr<Chunk> m_inChunk, m_outChunk;
	union
	{
		Module *m_sink;
		Module *m_source;
	};

	void pull(size_t frames);
	void push(size_t frames);
};

/*
	_AF_ATOMIC_NVFRAMES is NOT the maximum number of frames a module
	can be requested to produce.

	This IS the maximum number of virtual (user) frames that will
	be produced or processed per run of the modules.

	Modules can be requested more frames than this because of rate
	conversion and rebuffering.
*/

#define _AF_ATOMIC_NVFRAMES 1024

#endif // MODULE_H
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010-2013, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "ModuleState.h"

#include "File.h"
#include "FileHandle.h"
#include "FileModule.h"
#include "RebufferModule.h"
#include "SimpleModule.h"
#include "Track.h"
#include "byteorder.h"
#include "compression.h"
#include "units.h"
#include "util.h"
#include "../pcm.h"

#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <stdio.h>

ModuleState::ModuleState() :
	m_isDirty(true)
{
}

ModuleState::~ModuleState()
{
}

status ModuleState::initFileModule(AFfilehandle file, Track *track)
{
	const CompressionUnit *unit = _af_compression_unit_from_id(track->f.compressionType);
	if (!unit)
		return AF_FAIL;

	// Validate compression format and parameters.
	if (!unit->fmtok(&track->f))
		return AF_FAIL;

	if (file->m_seekok &&
		file->m_fh->seek(track->fpos_first_frame, File::SeekFromBeginning) !=
			track->fpos_first_frame)
	{
		_af_error(AF_BAD_LSEEK, "unable to position file handle at beginning of sound data");
		return AF_FAIL;
	}

	AFframecount chunkFrames;
	if (file->m_access == _AF_READ_ACCESS)
		m_fileModule = unit->initdecompress(track, file->m_fh, file->m_seekok,
			file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);
	else
		m_fileModule = unit->initcompress(track, file->m_fh, file->m_seekok,
			file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);

	if (unit->needsRebuffer)
	{
		assert(unit->nativeSampleFormat == AF_SAMPFMT_TWOSCOMP);

		RebufferModule::Direction direction =
			file->m_access == _AF_WRITE_ACCESS ?
				RebufferModule::VariableToFixed : RebufferModule::FixedToVariable;

		m_fileRebufferModule = new RebufferModule(direction,
			track->f.bytesPerFrame(false), chunkFrames,
			unit->multiple_of);
	}

	track->filemodhappy = true;

	return AF_SUCCEED;
}

status ModuleState::init(AFfilehandle file, Track *track)
{
	if (initFileModule(file, track) == AF_FAIL)
		return AF_FAIL;

	return AF_SUCCEED;
}

bool ModuleState::fileModuleHandlesSeeking() const
{
	return m_fileModule->handlesSeeking();
}

status ModuleState::setup(AFfilehandle file, Track *track)
{
	AFframecount fframepos = llrint(track->nextvframe * track->f.sampleRate / track->v.sampleRate);
	bool isReading = file->m_access == _AF_READ_ACCESS;

	if (!track->v.isUncompressed())
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED,
			"library does not support compression in virtual format yet");
		return AF_FAIL;
	}

	if (arrange(file, track) == AF_FAIL)
		return AF_FAIL;

	track->filemodhappy = true;
	int maxbufsize = 0;
	if (isReading)
	{
		m_chunks.back()->frameCount = _AF_ATOMIC_NVFRAMES;
		for (int i=m_modules.size() - 1; i >= 0; i--)
		{
			SharedPtr<Chunk> inChunk = m_chunks[i];
			SharedPtr<Chunk> outChunk = m_chunks[i+1];
			int bufsize = outChunk->frameCount * outChunk->f.bytesPerFrame(true);
			if (bufsize > maxbufsize)
				maxbufsize = bufsize;
			if (i != 0)
				m_modules[i]->setSource(m_modules[i-1].get());
			m_modules[i]->maxPull();
		}

		if (!track->filemodhappy)
			return AF_FAIL;
		int bufsize = m_fileModule->bufferSize();
		if (bufsize > maxbufsize)
			maxbufsize = bufsize;
	}
	else
	{
		m_chunks.front()->frameCount = _AF_ATOMIC_NVFRAMES;
		for (size_t i=0; i<m_modules.size(); i++)
		{
			SharedPtr<Chunk> inChunk = m_chunks[i];
			SharedPtr<Chunk> outChunk = m_chunks[i+1];
			int bufsize = inChunk->frameCount * inChunk->f.bytesPerFrame(true);
			if (bufsize > maxbufsize)
				maxbufsize = bufsize;
			if (i != m_modules.size() - 1)
				m_modules[i]->setSink(m_modules[i+1].get());
			m_modules[i]->maxPush();
		}

		if (!track->filemodhappy)
			return AF_FAIL;

		int bufsize = m_fileModule->bufferSize();
		if (bufsize > maxbufsize)
			maxbufsize = bufsize;
	}

	for (size_t i=0; i<m_chunks.size(); i++)
	{
		if ((isReading && i==m_chunks.size() - 1) || (!isReading && i==0))
			continue;
		m_chunks[i]->allocate(maxbufsize);
	}

	if (isReading)
	{
		if (track->totalfframes == -1)
			track->totalvframes = -1;
		else
			track->totalvframes = llrint(track->totalfframes *
				(track->v.sampleRate / track->f.sampleRate));

		track->nextfframe = fframepos;
		track->nextvframe = llrint(fframepos * track->v.sampleRate / track->f.sampleRate);

		m_isDirty = false;

		if (reset(file, track) == AF_FAIL)
			return AF_FAIL;
	}
	else
	{
		track->nextvframe = track->totalvframes =
			(AFframecount) (fframepos * track->v.sampleRate / track->f.sampleRate);
		m_isDirty = false;
	}

	return AF_SUCCEED;
}

const std::vector<SharedPtr<Module> > &ModuleState::modules() const
{
	return m_modules;
}

const std::vector<SharedPtr<Chunk> > &ModuleState::chunks() const
{
	return m_chunks;
}

status ModuleState::reset(AFfilehandle file, Track *track)
{
	track->filemodhappy = true;
	for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
			i != m_modules.rend(); ++i)
		(*i)->reset1();
	track->frames2ignore = 0;
	if (!track->filemodhappy)
		return AF_FAIL;
	for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
			i != m_modules.end(); ++i)
		(*i)->reset2();
	if (!track->filemodhappy)
		return AF_FAIL;
	return AF_SUCCEED;
}

status ModuleState::sync(AFfilehandle file, Track *track)
{
	track->filemodhappy = true;
	for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
			i != m_modules.rend(); ++i)
		(*i)->sync1();
	if (!track->filemodhappy)
		return AF_FAIL;
	for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
			i != m_modules.end(); ++i)
		(*i)->sync2();
	return AF_SUCCEED;
}

static const PCMInfo * const intmappings[6] =
{
	&_af_default_signed_integer_pcm_mappings[1],
	&_af_default_signed_integer_pcm_mappings[2],
	&_af_default_signed_integer_pcm_mappings[3],
	&_af_default_signed_integer_pcm_mappings[4],
	NULL,
	NULL
};

static FormatCode getFormatCode(const AudioFormat &format)
{
	if (format.sampleFormat == AF_SAMPFMT_FLOAT)
		return kFloat;
	if (format.sampleFormat == AF_SAMPFMT_DOUBLE)
		return kDouble;
	if (format.isInteger())
	{
		switch (format.bytesPerSample(false))
		{
			case 1: return kInt8;
			case 2: return kInt16;
			case 3: return kInt24;
			case 4: return kInt32;
		}
	}

	/* NOTREACHED */
	assert(false);
	return kUndefined;
}

static bool isInteger(FormatCode code) { return code >= kInt8 && code <= kInt32; }
static bool isFloat(FormatCode code) { return code >= kFloat && code <= kDouble; }

static bool isTrivialIntMapping(const AudioFormat &format, FormatCode code)
{
	return intmappings[code] != NULL &&
		format.pcm.slope == intmappings[code]->slope &&
		format.pcm.intercept == intmappings[code]->intercept;
}

static bool isTrivialIntClip(const AudioFormat &format, FormatCode code)
{
	return intmappings[code] != NULL &&
		format.pcm.minClip == intmappings[code]->minClip &&
		format.pcm.maxClip == intmappings[code]->maxClip;
}

status ModuleState::arrange(AFfilehandle file, Track *track)
{
	bool isReading = file->m_access == _AF_READ_ACCESS;
	AudioFormat in, out;
	if (isReading)
	{
		in = track->f;
		out = track->v;
	}
	else
	{
		in = track->v;
		out = track->f;
	}

	FormatCode infc = getFormatCode(in);
	FormatCode outfc = getFormatCode(out);
	if (infc == kUndefined || outfc == kUndefined)
		return AF_FAIL;

	m_chunks.clear();
	m_chunks.push_back(new Chunk());
	m_chunks.back()->f = in;

	m_modules.clear();

	if (isReading)
	{
		addModule(m_fileModule.get());
		addModule(m_fileRebufferModule.get());
	}

	// Convert to native byte order.
	if (in.byteOrder != _AF_BYTEORDER_NATIVE)
	{
		size_t bytesPerSample = in.bytesPerSample(!isReading);
		if (bytesPerSample > 1 && in.compressionType == AF_COMPRESSION_NONE)
			addModule(new SwapModule());
		else
			in.byteOrder = _AF_BYTEORDER_NATIVE;
	}

	// Handle 24-bit integer input format.
	if (in.isInteger() && in.bytesPerSample(false) == 3)
	{
		if (isReading || in.compressionType != AF_COMPRESSION_NONE)
			addModule(new Expand3To4Module(in.isSigned()));
	}

	// Make data signed.
	if (in.isUnsigned())
		addModule(new ConvertSign(infc, false));

	in.pcm = m_chunks.back()->f.pcm;

	// Reverse the unsigned shift for output.
	if (out.isUnsigned())
	{
		const double shift = intmappings[outfc]->minClip;
		out.pcm.intercept += shift;
		out.pcm.minClip += shift;
		out.pcm.maxClip += shift;
	}

	// Clip input samples if necessary.
	if (in.pcm.minClip < in.pcm.maxClip && !isTrivialIntClip(in, infc))
		addModule(new Clip(infc, in.pcm));

	bool alreadyClippedOutput = false;
	bool alreadyTransformedOutput = false;
	// Perform range transformation if input and output PCM mappings differ.
	bool transforming = (in.pcm.slope != out.pcm.slope ||
		in.pcm.intercept != out.pcm.intercept) &&
		!(isTrivialIntMapping(in, infc) &&
		isTrivialIntMapping(out, outfc));

	// Range transformation requires input to be floating-point.
	if (isInteger(infc) && transforming)
	{
		if (infc == kInt32 || outfc == kDouble || outfc == kInt32)
		{
			addConvertIntToFloat(infc, kDouble);
			infc = kDouble;
		}
		else
		{
			addConvertIntToFloat(infc, kFloat);
			infc = kFloat;
		}
	}

	if (transforming && infc == kDouble && isFloat(outfc))
		addModule(new Transform(infc, in.pcm, out.pcm));

	// Add format conversion if needed.
	if (isInteger(infc) && isInteger(outfc))
		addConvertIntToInt(infc, outfc);
	else if (isInteger(infc) && isFloat(outfc))
		addConvertIntToFloat(infc, outfc);
	else if (isFloat(infc) && isInteger(outfc))
	{
		addConvertFloatToInt(infc, outfc, in.pcm, out.pcm);
		alreadyClippedOutput = true;
		alreadyTransformedOutput = true;
	}
	else if (isFloat(infc) && isFloat(outfc))
		addConvertFloatToFloat(infc, outfc);

	if (transforming && !alreadyTransformedOutput && infc != kDouble)
		addModule(new Transform(outfc, in.pcm, out.pcm));

	if (in.channelCount != out.channelCount)
		addModule(new ApplyChannelMatrix(outfc, isReading,
			in.channelCount, out.channelCount,
			in.pcm.minClip, in.pcm.maxClip,
			track->channelMatrix));

	// Perform clipping if necessary.
	if (!alreadyClippedOutput)
	{
		if (out.pcm.minClip < out.pcm.maxClip && !isTrivialIntClip(out, outfc))
			addModule(new Clip(outfc, out.pcm));
	}

	// Make data unsigned if necessary.
	if (out.isUnsigned())
		addModule(new ConvertSign(outfc, true));

	// Handle 24-bit integer output format.
	if (out.isInteger() && out.bytesPerSample(false) == 3)
	{
		if (!isReading || out.compressionType != AF_COMPRESSION_NONE)
			addModule(new Compress4To3Module(out.isSigned()));
	}

	if (out.byteOrder != _AF_BYTEORDER_NATIVE)
	{
		size_t bytesPerSample = out.bytesPerSample(isReading);
		if (bytesPerSample > 1 && out.compressionType == AF_COMPRESSION_NONE)
			addModule(new SwapModule());
		else
			out.byteOrder = _AF_BYTEORDER_NATIVE;
	}

	if (!isReading)
	{
		addModule(m_fileRebufferModule.get());
		addModule(m_fileModule.get());
	}

	return AF_SUCCEED;
}

void ModuleState::addModule(Module *module)
{
	if (!module)
		return;

	m_modules.push_back(module);
	module->setInChunk(m_chunks.back().get());
	Chunk *chunk = new Chunk();
	chunk->f = m_chunks.back()->f;
	m_chunks.push_back(chunk);
	module->setOutChunk(chunk);
	module->describe();
}

void ModuleState::addConvertIntToInt(FormatCode input, FormatCode output)
{
	if (input == output)
		return;

	assert(isInteger(input));
	assert(isInteger(output));
	addModule(new ConvertInt(input, output));
}

void ModuleState::addConvertIntToFloat(FormatCode input, FormatCode output)
{
	addModule(new ConvertIntToFloat(input, output));
}

void ModuleState::addConvertFloatToInt(FormatCode input, FormatCode output,
	const PCMInfo &inputMapping, const PCMInfo &outputMapping)
{
	addModule(new ConvertFloatToIntClip(input, output, inputMapping, outputMapping));
}

void ModuleState::addConvertFloatToFloat(FormatCode input, FormatCode output)
{
	if (input == output)
		return;

	assert((input == kFloat && output == kDouble) ||
		(input == kDouble && output == kFloat));
	addModule(new ConvertFloat(input, output));
}

void ModuleState::print()
{
	fprintf(stderr, "modules:\n");
	for (size_t i=0; i<m_modules.size(); i++)
		fprintf(stderr, " %s (%p) in %p out %p\n",
			m_modules[i]->name(), m_modules[i].get(),
			m_modules[i]->inChunk(),
			m_modules[i]->outChunk());
	fprintf(stderr, "chunks:\n");
	for (size_t i=0; i<m_chunks.size(); i++)
		fprintf(stderr, " %p %s\n",
			m_chunks[i].get(),
			m_chunks[i]->f.description().c_str());
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef MODULESTATE_H
#define MODULESTATE_H

#include "Module.h"
#include "Shared.h"
#include "afinternal.h"
#include <vector>

class FileModule;
class Module;

class ModuleState : public Shared<ModuleState>
{
public:
	ModuleState();
	virtual ~ModuleState();

	bool isDirty() const { return m_isDirty; }
	void setDirty() { m_isDirty = true; }
	status init(AFfilehandle file, Track *track);
	status setup(AFfilehandle file, Track *track);
	status reset(AFfilehandle file, Track *track);
	status sync(AFfilehandle file, Track *track);

	int numModules() const { return m_modules.size(); }
	const std::vector<SharedPtr<Module> > &modules() const;
	const std::vector<SharedPtr<Chunk> > &chunks() const;

	bool mustUseAtomicNVFrames() const { return true; }

	void print();

	bool fileModuleHandlesSeeking() const;

private:
	std::vector<SharedPtr<Module> > m_modules;
	std::vector<SharedPtr<Chunk> > m_chunks;
	bool m_isDirty;

	SharedPtr<FileModule> m_fileModule;
	SharedPtr<Module> m_fileRebufferModule;

	status initFileModule(AFfilehandle file, Track *track);

	status arrange(AFfilehandle file, Track *track);

	void addModule(Module *module);

	void addConvertIntToInt(FormatCode input, FormatCode output);
	void addConvertIntToFloat(FormatCode input, FormatCode output);
	void addConvertFloatToInt(FormatCode input, FormatCode output,
		const PCMInfo &inputMapping, const PCMInfo &outputMapping);
	void addConvertFloatToFloat(FormatCode input, FormatCode output);
};

#endif
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	PCM.cpp - read and file write module for uncompressed data
*/

#include "config.h"
#include "PCM.h"

#include <assert.h>
#include <math.h>

#include "Compiler.h"
#include "FileModule.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "compression.h"
#include "util.h"

bool _af_pcm_format_ok (AudioFormat *f)
{
	assert(!isnan(f->pcm.slope));
	assert(!isnan(f->pcm.intercept));
	assert(!isnan(f->pcm.minClip));
	assert(!isnan(f->pcm.maxClip));

	return true;
}

class PCM : public FileModule
{
public:
	static PCM *createCompress(Track *track, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkFrames);
	static PCM *createDecompress(Track *track, File *fh, bool canSeek,
		bool headerless, AFframecount *chunkFrames);

	virtual const char *name() const OVERRIDE { return "pcm"; }
	virtual void runPull() OVERRIDE;
	virtual void reset2() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;

private:
	int m_bytesPerFrame;

	/* saved_fpos_next_frame and saved_nextfframe apply only to writing. */
	int m_saved_fpos_next_frame;
	int m_saved_nextfframe;

	PCM(Mode, Track *, File *, bool canSeek);
};

PCM::PCM(Mode mode, Track *track, File *fh, bool canSeek) :
	FileModule(mode, track, fh, canSeek),
	m_bytesPerFrame(track->f.bytesPerFrame(false)),
	m_saved_fpos_next_frame(-1),
	m_saved_nextfframe(-1)
{
	if (mode == Decompress)
		track->f.compressionParams = AU_NULL_PVLIST;
}

PCM *PCM::createCompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkframes)
{
	return new PCM(Compress, track, fh, canSeek);
}

void PCM::runPush()
{
	AFframecount frames2write = m_inChunk->frameCount;
	AFframecount n;

	/*
		WARNING: due to the optimization explained at the end
		of arrangemodules(), the pcm file module cannot depend
		on the presence of the intermediate working buffer
		which _AFsetupmodules usually allocates for file
		modules in their input or output chunk (for reading or
		writing, respectively).

		Fortunately, the pcm module has no need for such a buffer.
	*/

	ssize_t bytesWritten = write(m_inChunk->buffer, m_bytesPerFrame * frames2write);
	n = bytesWritten >= 0 ? bytesWritten / m_bytesPerFrame : 0;

	if (n != frames2write)
		reportWriteError(n, frames2write);

	m_track->nextfframe += n;
	m_track->totalfframes = m_track->nextfframe;
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));
}

void PCM::sync1()
{
	m_saved_fpos_next_frame = m_track->fpos_next_frame;
	m_saved_nextfframe = m_track->nextfframe;
}

void PCM::sync2()
{
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));

	/* We can afford to seek because sync2 is rare. */
	m_track->fpos_after_data = tell();

	m_track->fpos_next_frame = m_saved_fpos_next_frame;
	m_track->nextfframe = m_saved_nextfframe;
}

PCM *PCM::createDecompress(Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkframes)
{
	return new PCM(Decompress, track, fh, canSeek);
}

void PCM::runPull()
{
	AFframecount framesToRead = m_outChunk->frameCount;

	/*
		WARNING: Due to the optimization explained at the end of
		arrangemodules(), the pcm file module cannot depend on
		the presence of the intermediate working buffer which
		_AFsetupmodules usually allocates for file modules in
		their input or output chunk (for reading or writing,
		respectively).

		Fortunately, the pcm module has no need for such a buffer.
	*/

	/*
		Limit the number of frames to be read to the number of
		frames left in the track.
	*/
	if (m_track->totalfframes != -1 &&
		m_track->nextfframe + framesToRead > m_track->totalfframes)
	{
		framesToRead = m_track->totalfframes - m_track->nextfframe;
	}

	ssize_t bytesRead = read(m_outChunk->buffer, m_bytesPerFrame * framesToRead);
	AFframecount framesRead = bytesRead >= 0 ? bytesRead / m_bytesPerFrame : 0;

	m_track->nextfframe += framesRead;
	assert(!canSeek() || (tell() == m_track->fpos_next_frame));

	/*
		If we got EOF from read, then we return the actual amount read.

		Complain only if there should have been more frames in the file.
	*/

	if (framesRead != framesToRead && m_track->totalfframes != -1)
		reportReadError(framesRead, framesToRead);

	m_outChunk->frameCount = framesRead;
}

void PCM::reset2()
{
	m_track->fpos_next_frame = m_track->fpos_first_frame +
		m_bytesPerFrame * m_track->nextfframe;

	m_track->frames2ignore = 0;
}

FileModule *_AFpcminitcompress (Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return PCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
}

FileModule *_AFpcminitdecompress (Track *track, File *fh, bool canSeek,
	bool headerless, AFframecount *chunkFrames)
{
	return PCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	PCM.h
*/

#ifndef MODULES_PCM_H
#define MODULES_PCM_H

#include "afinternal.h"
#include "audiofile.h"

class File;
class FileModule;
struct AudioFormat;
struct Track;

bool _af_pcm_format_ok (AudioFormat *f);

FileModule *_AFpcminitcompress(Track *, File *, bool seekok,
	bool headerless, AFframecount *chunkframes);

FileModule *_AFpcminitdecompress(Track *, File *, bool seekok,
	bool headerless, AFframecount *chunkframes);

#endif /* MODULES_PCM_H */
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "RebufferModule.h"

#include <algorithm>
#include <assert.h>
#include <string.h>

RebufferModule::RebufferModule(Direction direction, int bytesPerFrame,
	int numFrames, bool multipleOf) :
	m_direction(direction),
	m_bytesPerFrame(bytesPerFrame),
	m_numFrames(numFrames),
	m_multipleOf(multipleOf),
	m_eof(false),
	m_sentShortChunk(false),
	m_buffer(NULL),
	m_offset(-1),
	m_savedBuffer(NULL),
	m_savedOffset(-1)
{
	if (m_direction == FixedToVariable)
		initFixedToVariable();
	else
		initVariableToFixed();
}

RebufferModule::~RebufferModule()
{
	delete [] m_buffer;
	delete [] m_savedBuffer;
}

void RebufferModule::initFixedToVariable()
{
	m_offset = m_numFrames;
	m_buffer = new char[m_numFrames * m_bytesPerFrame];
}

void RebufferModule::initVariableToFixed()
{
	m_offset = 0;
	m_buffer = new char[m_numFrames * m_bytesPerFrame];
	m_savedBuffer = new char[m_numFrames * m_bytesPerFrame];
}

void RebufferModule::maxPull()
{
	assert(m_direction == FixedToVariable);
	if (m_multipleOf)
		m_inChunk->frameCount = m_outChunk->frameCount + m_numFrames;
	else
		m_inChunk->frameCount = m_numFrames;
}

void RebufferModule::maxPush()
{
	assert(m_direction == VariableToFixed);
	if (m_multipleOf)
		m_outChunk->frameCount = m_inChunk->frameCount + m_numFrames;
	else
		m_outChunk->frameCount = m_numFrames;
}

void RebufferModule::runPull()
{
	int framesToPull = m_outChunk->frameCount;
	const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
	char *outBuffer = static_cast<char *>(m_outChunk->buffer);

	assert(m_offset > 0 && m_offset <= m_numFrames);

	/*
		A module should not pull more frames from its input
		after receiving a short chunk.
	*/
	assert(!m_sentShortChunk);

	if (m_offset < m_numFrames)
	{
		int buffered = m_numFrames - m_offset;
		int n = std::min(framesToPull, buffered);
		memcpy(outBuffer, m_buffer + m_offset * m_bytesPerFrame,
			n * m_bytesPerFrame);
		outBuffer += buffered * m_bytesPerFrame;
		framesToPull -= buffered;
		m_offset += n;
	}

	// Try to pull more frames from the source.
	while (!m_eof && framesToPull > 0)
	{
		int framesRequested;
		if (m_multipleOf)
			// Round framesToPull up to nearest multiple of m_numFrames.
			framesRequested = ((framesToPull - 1) / m_numFrames + 1) * m_numFrames;
		else
			framesRequested = m_numFrames;

		assert(framesRequested > 0);

		pull(framesRequested);

		int framesReceived = m_inChunk->frameCount;

		if (framesReceived != framesRequested)
			m_eof = true;

		memcpy(outBuffer, inBuffer,
			std::min(framesToPull, framesReceived) * m_bytesPerFrame);

		outBuffer += framesReceived * m_bytesPerFrame;
		framesToPull -= framesReceived;

		if (m_multipleOf)
			assert(m_eof || framesToPull <= 0);

		if (framesToPull < 0)
		{
			assert(m_offset == m_numFrames);

			m_offset = m_numFrames + framesToPull;

			assert(m_offset > 0 && m_offset <= m_numFrames);

			memcpy(m_buffer + m_offset * m_bytesPerFrame,
				inBuffer + (framesReceived + framesToPull) * m_bytesPerFrame,
				(m_numFrames - m_offset) * m_bytesPerFrame);
		}
		else
		{
			assert(m_offset == m_numFrames);
		}
	}

	if (m_eof && framesToPull > 0)
	{
		// Output short chunk.
		m_outChunk->frameCount -= framesToPull;
		m_sentShortChunk = true;
		assert(m_offset == m_numFrames);
	}
	else
	{
		assert(framesToPull <= 0);
		assert(m_offset == m_numFrames + framesToPull);
	}
	assert(m_offset > 0 && m_offset <= m_numFrames);
}

void RebufferModule::reset1()
{
	m_offset = m_numFrames;
	m_eof = false;
	m_sentShortChunk = false;
	assert(m_offset > 0 && m_offset <= m_numFrames);
}

void RebufferModule::reset2()
{
	assert(m_offset > 0 && m_offset <= m_numFrames);
}

void RebufferModule::runPush()
{
	int framesToPush = m_inChunk->frameCount;
	const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
	char *outBuffer = static_cast<char *>(m_outChunk->buffer);

	assert(m_offset >= 0 && m_offset < m_numFrames);

	// Check that we will be able to push even one block.
	if (m_offset + framesToPush >= m_numFrames)
	{
		if (m_offset > 0)
			memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);

		if (m_multipleOf)
		{
			// Round down to nearest multiple of m_numFrames.
			int n = ((m_offset + framesToPush) / m_numFrames) * m_numFrames;

			assert(n > m_offset);
			memcpy(outBuffer + m_offset * m_bytesPerFrame,
				inBuffer,
				(n - m_offset) * m_bytesPerFrame);

			push(n);

			inBuffer += (n - m_offset) * m_bytesPerFrame;
			framesToPush -= n - m_offset;
			assert(framesToPush >= 0);
			m_offset = 0;
		}
		else
		{
			while (m_offset + framesToPush >= m_numFrames)
			{
				int n = m_numFrames - m_offset;
				memcpy(outBuffer + m_offset * m_bytesPerFrame,
					inBuffer,
					n * m_bytesPerFrame);

				push(m_numFrames);

				inBuffer += n * m_bytesPerFrame;
				framesToPush -= n;
				assert(framesToPush >= 0);
				m_offset = 0;
			}
		}

		assert(m_offset == 0);
	}

	assert(m_offset + framesToPush < m_numFrames);

	// Save remaining samples in buffer.
	if (framesToPush > 0)
	{
		memcpy(m_buffer + m_offset * m_bytesPerFrame,
			inBuffer,
			framesToPush * m_bytesPerFrame);
		m_offset += framesToPush;
	}

	assert(m_offset >= 0 && m_offset < m_numFrames);
}

void RebufferModule::sync1()
{
	assert(m_offset >= 0 && m_offset < m_numFrames);

	// Save all the frames and the offset so we can restore our state later.
	memcpy(m_savedBuffer, m_buffer, m_numFrames * m_bytesPerFrame);
	m_savedOffset = m_offset;
}

void RebufferModule::sync2()
{
	assert(m_offset >= 0 && m_offset < m_numFrames);

	memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);

	push(m_offset);

	memcpy(m_buffer, m_savedBuffer, m_numFrames * m_bytesPerFrame);
	m_offset = m_savedOffset;

	assert(m_offset >= 0 && m_offset < m_numFrames);
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef REBUFFER_MODULE_H
#define REBUFFER_MODULE_H

#include "Compiler.h"
#include "Module.h"

class RebufferModule : public Module
{
public:
	enum Direction
	{
		FixedToVariable,
		VariableToFixed
	};

	RebufferModule(Direction, int bytesPerFrame, int numFrames, bool multipleOf);
	virtual ~RebufferModule();

	virtual const char *name() const OVERRIDE { return "rebuffer"; }

	virtual void maxPull() OVERRIDE;
	virtual void maxPush() OVERRIDE;

	virtual void runPull() OVERRIDE;
	virtual void reset1() OVERRIDE;
	virtual void reset2() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void sync1() OVERRIDE;
	virtual void sync2() OVERRIDE;

private:
	Direction m_direction;
	int m_bytesPerFrame;
	int m_numFrames;
	bool m_multipleOf; // buffer to multiple of m_numFrames
	bool m_eof; // end of input stream reached
	bool m_sentShortChunk; // end of input stream indicated
	char *m_buffer;
	int m_offset;
	char *m_savedBuffer;
	int m_savedOffset;

	void initFixedToVariable();
	void initVariableToFixed();
};

#endif // REBUFFER_MODULE_H
/*
	Audio File Library
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"
#include "SimpleModule.h"

#include <algorithm>

void SimpleModule::runPull()
{
	pull(m_outChunk->frameCount);
	run(*m_inChunk, *m_outChunk);
}

void SimpleModule::runPush()
{
	m_outChunk->frameCount = m_inChunk->frameCount;
	run(*m_inChunk, *m_outChunk);
	push(m_outChunk->frameCount);
}

ApplyChannelMatrix::ApplyChannelMatrix(FormatCode format, bool isReading,
	int inChannels, int outChannels,
	double minClip, double maxClip, const double *matrix) :
	m_format(format),
	m_inChannels(inChannels),
	m_outChannels(outChannels),
	m_minClip(minClip),
	m_maxClip(maxClip),
	m_matrix(NULL)
{
	m_matrix = new double[m_inChannels * m_outChannels];
	if (matrix)
	{
		if (isReading)
		{
			// Copy channel matrix for reading.
			std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
		}
		else
		{
			// Transpose channel matrix for writing.
			for (int i=0; i < inChannels; i++)
				for (int j=0; j < outChannels; j++)
					m_matrix[j*inChannels + i] = matrix[i*outChannels + j];
		}
	}
	else
	{
		initDefaultMatrix();
	}
}

ApplyChannelMatrix::~ApplyChannelMatrix()
{
	delete [] m_matrix;
}

const char *ApplyChannelMatrix::name() const { return "channelMatrix"; }

void ApplyChannelMatrix::describe()
{
	m_outChunk->f.channelCount = m_outChannels;
	m_outChunk->f.pcm.minClip = m_minClip;
	m_outChunk->f.pcm.maxClip = m_maxClip;
}

void ApplyChannelMatrix::run(Chunk &inChunk, Chunk &outChunk)
{
	switch (m_format)
	{
		case kInt8:
			run<int8_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
			break;
		case kInt16:
			run<int16_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
			break;
		case kInt24:
		case kInt32:
			run<int32_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
			break;
		case kFloat:
			run<float>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
			break;
		case kDouble:
			run<double>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
			break;
		default:
			assert(false);
	}
}

template <typename T>
void ApplyChannelMatrix::run(const void *inputData, void *outputData, int frameCount)
{
	const T *input = reinterpret_cast<const T *>(inputData);
	T *output = reinterpret_cast<T *>(outputData);
	for (int frame=0; frame<frameCount; frame++)
	{
		const T *inputSave = input;
		const double *m = m_matrix;
		for (int outChannel=0; outChannel < m_outChannels; outChannel++)
		{
			input = inputSave;
			double t = 0;
			for (int inChannel=0; inChannel < m_inChannels; inChannel++)
				t += *input++ * *m++;
			*output++ = t;
		}
	}
}

void ApplyChannelMatrix::initDefaultMatrix()
{
	const double *matrix = NULL;
	if (m_inChannels==1 && m_outChannels==2)
	{
		static const double m[]={1,1};
		matrix = m;
	}
	else if (m_inChannels==1 && m_outChannels==4)
	{
		static const double m[]={1,1,0,0};
		matrix = m;
	}
	else if (m_inChannels==2 && m_outChannels==1)
	{
		static const double m[]={.5,.5};
		matrix = m;
	}
	else if (m_inChannels==2 && m_outChannels==4)
	{
		static const double m[]={1,0,0,1,0,0,0,0};
		matrix = m;
	}
	else if (m_inChannels==4 && m_outChannels==1)
	{
		static const double m[]={.5,.5,.5,.5};
		matrix = m;
	}
	else if (m_inChannels==4 && m_outChannels==2)
	{
		static const double m[]={1,0,1,0,0,1,0,1};
		matrix = m;
	}

	if (matrix)
	{
		std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
	}
	else
	{
		for (int i=0; i < m_inChannels; i++)
			for (int j=0; j < m_outChannels; j++)
				m_matrix[j*m_inChannels + i] = (i==j) ? 1 : 0;
	}
}
/*
	Audio File Library
	Copyright (C) 2010, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef SIMPLE_MODULE_H
#define SIMPLE_MODULE_H

#include "config.h"

#include "Compiler.h"
#include "Module.h"
#include "byteorder.h"

#include <algorithm>
#include <cassert>
#include <climits>
#include <functional>

class SimpleModule : public Module
{
public:
	virtual void runPull() OVERRIDE;
	virtual void runPush() OVERRIDE;
	virtual void run(Chunk &inChunk, Chunk &outChunk) = 0;
};

struct SwapModule : public SimpleModule
{
public:
	virtual const char *name() const OVERRIDE { return "swap"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.byteOrder = m_inChunk->f.byteOrder == AF_BYTEORDER_BIGENDIAN ?
			AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		switch (m_inChunk->f.bytesPerSample(false))
		{
			case 2:
				run<2, int16_t>(inChunk, outChunk); break;
			case 3:
				run<3, char>(inChunk, outChunk); break;
			case 4:
				run<4, int32_t>(inChunk, outChunk); break;
			case 8:
				run<8, int64_t>(inChunk, outChunk); break;
			default:
				assert(false); break;
		}
	}

private:
	template <int N, typename T>
	void run(Chunk &inChunk, Chunk &outChunk)
	{
		int sampleCount = inChunk.f.channelCount * inChunk.frameCount;
		runSwap<N, T>(reinterpret_cast<const T *>(inChunk.buffer),
			reinterpret_cast<T *>(outChunk.buffer),
			sampleCount);
	}
	template <int N, typename T>
	void runSwap(const T *input, T *output, int sampleCount)
	{
		for (int i=0; i<sampleCount; i++)
			output[i] = byteswap(input[i]);
	}
};

template <>
inline void SwapModule::runSwap<3, char>(const char *input, char *output, int count)
{
	for (int i=0; i<count; i++)
	{
		output[3*i] = input[3*i+2];
		output[3*i+1] = input[3*i+1];
		output[3*i+2] = input[3*i];
	}
}

template <typename UnaryFunction>
void transform(const void *srcData, void *dstData, size_t count)
{
	typedef typename UnaryFunction::argument_type InputType;
	typedef typename UnaryFunction::result_type OutputType;
	const InputType *src = reinterpret_cast<const InputType *>(srcData);
	OutputType *dst = reinterpret_cast<OutputType *>(dstData);
	std::transform(src, src + count, dst, UnaryFunction());
}

template <FormatCode>
struct IntTypes;

template <>
struct IntTypes<kInt8> { typedef int8_t SignedType; typedef uint8_t UnsignedType; };
template <>
struct IntTypes<kInt16> { typedef int16_t SignedType; typedef uint16_t UnsignedType; };
template <>
struct IntTypes<kInt24> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template <>
struct IntTypes<kInt32> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };

template <FormatCode Format>
struct signConverter
{
	typedef typename IntTypes<Format>::SignedType SignedType;
	typedef typename IntTypes<Format>::UnsignedType UnsignedType;

	static const int kScaleBits = (Format + 1) * CHAR_BIT - 1;
	static const int kMaxSignedValue = (((1 << (kScaleBits - 1)) - 1) << 1) + 1;
	static const int kMinSignedValue = -kMaxSignedValue - 1;

	struct signedToUnsigned : public std::unary_function<SignedType, UnsignedType>
	{
		UnsignedType operator()(SignedType x) { return x - kMinSignedValue; }
	};

	struct unsignedToSigned : public std::unary_function<SignedType, UnsignedType>
	{
		SignedType operator()(UnsignedType x) { return x + kMinSignedValue; }
	};
};

class ConvertSign : public SimpleModule
{
public:
	ConvertSign(FormatCode format, bool fromSigned) :
		m_format(format),
		m_fromSigned(fromSigned)
	{
	}
	virtual const char *name() const OVERRIDE { return "sign"; }
	virtual void describe() OVERRIDE
	{
		const int scaleBits = m_inChunk->f.bytesPerSample(false) * CHAR_BIT;
		m_outChunk->f.sampleFormat =
			m_fromSigned ? AF_SAMPFMT_UNSIGNED : AF_SAMPFMT_TWOSCOMP;
		double shift = -(1 << (scaleBits - 1));
		if (m_fromSigned)
			shift = -shift;
		m_outChunk->f.pcm.intercept += shift;
		m_outChunk->f.pcm.minClip += shift;
		m_outChunk->f.pcm.maxClip += shift;
	}
	virtual void run(Chunk &input, Chunk &output) OVERRIDE
	{
		size_t count = input.frameCount * m_inChunk->f.channelCount;
		if (m_fromSigned)
			convertSignedToUnsigned(input.buffer, output.buffer, count);
		else
			convertUnsignedToSigned(input.buffer, output.buffer, count);
	}

private:
	FormatCode m_format;
	bool m_fromSigned;

	template <FormatCode Format>
	static void convertSignedToUnsigned(const void *src, void *dst, size_t count)
	{
		transform<typename signConverter<Format>::signedToUnsigned>(src, dst, count);
	}
	void convertSignedToUnsigned(const void *src, void *dst, size_t count)
	{
		switch (m_format)
		{
			case kInt8:
				convertSignedToUnsigned<kInt8>(src, dst, count);
				break;
			case kInt16:
				convertSignedToUnsigned<kInt16>(src, dst, count);
				break;
			case kInt24:
				convertSignedToUnsigned<kInt24>(src, dst, count);
				break;
			case kInt32:
				convertSignedToUnsigned<kInt32>(src, dst, count);
				break;
			default:
				assert(false);
		}
	}

	template <FormatCode Format>
	static void convertUnsignedToSigned(const void *src, void *dst, size_t count)
	{
		transform<typename signConverter<Format>::unsignedToSigned>(src, dst, count);
	}
	void convertUnsignedToSigned(const void *src, void *dst, size_t count)
	{
		switch (m_format)
		{
			case kInt8:
				convertUnsignedToSigned<kInt8>(src, dst, count);
				break;
			case kInt16:
				convertUnsignedToSigned<kInt16>(src, dst, count);
				break;
			case kInt24:
				convertUnsignedToSigned<kInt24>(src, dst, count);
				break;
			case kInt32:
				convertUnsignedToSigned<kInt32>(src, dst, count);
				break;
			default:
				assert(false);
		}
	}
};

struct Expand3To4Module : public SimpleModule
{
public:
	Expand3To4Module(bool isSigned) : m_isSigned(isSigned)
	{
	}
	virtual const char *name() const OVERRIDE { return "expand3to4"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.packed = false;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		int count = inChunk.f.channelCount * inChunk.frameCount;
		if (m_isSigned)
			run<int32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
				reinterpret_cast<int32_t *>(outChunk.buffer),
				count);
		else
			run<uint32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
				reinterpret_cast<uint32_t *>(outChunk.buffer),
				count);
	}

private:
	bool m_isSigned;

	template <typename T>
	void run(const uint8_t *input, T *output, int sampleCount)
	{
		for (int i=0; i<sampleCount; i++)
		{
			T t =
#ifdef WORDS_BIGENDIAN
				(input[3*i] << 24) |
				(input[3*i+1] << 16) |
				input[3*i+2] << 8;
#else
				(input[3*i+2] << 24) |
				(input[3*i+1] << 16) |
				input[3*i] << 8;
#endif
			output[i] = t >> 8;
		}
	}
};

struct Compress4To3Module : public SimpleModule
{
public:
	Compress4To3Module(bool isSigned) : m_isSigned(isSigned)
	{
	}
	virtual const char *name() const OVERRIDE { return "compress4to3"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.packed = true;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		int count = inChunk.f.channelCount * inChunk.frameCount;
		if (m_isSigned)
			run<int32_t>(inChunk.buffer, outChunk.buffer, count);
		else
			run<uint32_t>(inChunk.buffer, outChunk.buffer, count);
	}

private:
	bool m_isSigned;

	template <typename T>
	void run(const void *input, void *output, int count)
	{
		const T *in = reinterpret_cast<const T *>(input);
		uint8_t *out = reinterpret_cast<uint8_t *>(output);
		for (int i=0; i<count; i++)
		{
			uint8_t c0, c1, c2;
			extract3(in[i], c0, c1, c2);
			out[3*i] = c0;
			out[3*i+1] = c1;
			out[3*i+2] = c2;
		}
	}
	template <typename T>
	void extract3(T in, uint8_t &c0, uint8_t &c1, uint8_t &c2)
	{
#ifdef WORDS_BIGENDIAN
			c0 = (in >> 16) & 0xff;
			c1 = (in >> 8) & 0xff;
			c2 = in & 0xff;
#else
			c2 = (in >> 16) & 0xff;
			c1 = (in >> 8) & 0xff;
			c0 = in & 0xff;
#endif
	}
};

template <typename Arg, typename Result>
struct intToFloat : public std::unary_function<Arg, Result>
{
	Result operator()(Arg x) const { return x; }
};

struct ConvertIntToFloat : public SimpleModule
{
	ConvertIntToFloat(FormatCode inFormat, FormatCode outFormat) :
		m_inFormat(inFormat), m_outFormat(outFormat)
	{
	}
	virtual const char *name() const OVERRIDE { return "intToFloat"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.sampleFormat = m_outFormat == kDouble ?
			AF_SAMPFMT_DOUBLE : AF_SAMPFMT_FLOAT;
		m_outChunk->f.sampleWidth = m_outFormat == kDouble ? 64 : 32;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		const void *src = inChunk.buffer;
		void *dst = outChunk.buffer;
		int count = inChunk.frameCount * inChunk.f.channelCount;
		if (m_outFormat == kFloat)
		{
			switch (m_inFormat)
			{
				case kInt8:
					run<int8_t, float>(src, dst, count); break;
				case kInt16:
					run<int16_t, float>(src, dst, count); break;
				case kInt24:
				case kInt32:
					run<int32_t, float>(src, dst, count); break;
				default:
					assert(false);
			}
		}
		else if (m_outFormat == kDouble)
		{
			switch (m_inFormat)
			{
				case kInt8:
					run<int8_t, double>(src, dst, count); break;
				case kInt16:
					run<int16_t, double>(src, dst, count); break;
				case kInt24:
				case kInt32:
					run<int32_t, double>(src, dst, count); break;
				default:
					assert(false);
			}
		}
	}

private:
	FormatCode m_inFormat, m_outFormat;

	template <typename Arg, typename Result>
	static void run(const void *src, void *dst, int count)
	{
		transform<intToFloat<Arg, Result> >(src, dst, count);
	}
};

template <typename Arg, typename Result, unsigned shift>
struct lshift : public std::unary_function<Arg, Result>
{
	Result operator()(const Arg &x) const { return x << shift; }
};

template <typename Arg, typename Result, unsigned shift>
struct rshift : public std::unary_function<Arg, Result>
{
	Result operator()(const Arg &x) const { return x >> shift; }
};

struct ConvertInt : public SimpleModule
{
	ConvertInt(FormatCode inFormat, FormatCode outFormat) :
		m_inFormat(inFormat),
		m_outFormat(outFormat)
	{
		assert(isInteger(m_inFormat));
		assert(isInteger(m_outFormat));
	}
	virtual const char *name() const OVERRIDE { return "convertInt"; }
	virtual void describe() OVERRIDE
	{
		getDefaultPCMMapping(m_outChunk->f.sampleWidth,
			m_outChunk->f.pcm.slope,
			m_outChunk->f.pcm.intercept,
			m_outChunk->f.pcm.minClip,
			m_outChunk->f.pcm.maxClip);
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		const void *src = inChunk.buffer;
		void *dst = outChunk.buffer;
		size_t count = inChunk.frameCount * inChunk.f.channelCount;

#define MASK(N, M) (((N)<<3) | (M))
#define HANDLE(N, M) \
	case MASK(N, M): convertInt<N, M>(src, dst, count); break;
		switch (MASK(m_inFormat, m_outFormat))
		{
			HANDLE(kInt8, kInt16)
			HANDLE(kInt8, kInt24)
			HANDLE(kInt8, kInt32)
			HANDLE(kInt16, kInt8)
			HANDLE(kInt16, kInt24)
			HANDLE(kInt16, kInt32)
			HANDLE(kInt24, kInt8)
			HANDLE(kInt24, kInt16)
			HANDLE(kInt24, kInt32)
			HANDLE(kInt32, kInt8)
			HANDLE(kInt32, kInt16)
			HANDLE(kInt32, kInt24)
		}
#undef MASK
#undef HANDLE
	}

private:
	FormatCode m_inFormat, m_outFormat;

	void getDefaultPCMMapping(int &bits, double &slope, double &intercept,
		double &minClip, double &maxClip)
	{
		bits = (m_outFormat + 1) * CHAR_BIT;
		slope = (1LL << (bits - 1));
		intercept = 0;
		minClip = -(1 << (bits - 1));
		maxClip = (1LL << (bits - 1)) - 1;
	}

	static bool isInteger(FormatCode code)
	{
		return code >= kInt8 && code <= kInt32;
	}

	template <FormatCode Input, FormatCode Output, bool = (Input > Output)>
		struct shift;

	template <FormatCode Input, FormatCode Output>
	struct shift<Input, Output, true> :
		public rshift<typename IntTypes<Input>::SignedType,
			typename IntTypes<Output>::SignedType,
			(Input - Output) * CHAR_BIT>
	{
	};

	template <FormatCode Input, FormatCode Output>
	struct shift<Input, Output, false> :
		public lshift<typename IntTypes<Input>::SignedType,
			typename IntTypes<Output>::SignedType,
			(Output - Input) * CHAR_BIT>
	{
	};

	template <FormatCode Input, FormatCode Output>
	static void convertInt(const void *src, void *dst, int count)
	{
		transform<shift<Input, Output> >(src, dst, count);
	}
};

template <typename Arg, typename Result>
struct floatToFloat : public std::unary_function<Arg, Result>
{
	Result operator()(Arg x) const { return x; }
};

struct ConvertFloat : public SimpleModule
{
	ConvertFloat(FormatCode inFormat, FormatCode outFormat) :
		m_inFormat(inFormat), m_outFormat(outFormat)
	{
		assert((m_inFormat == kFloat && m_outFormat == kDouble) ||
			(m_inFormat == kDouble && m_outFormat == kFloat));
	}
	virtual const char *name() const OVERRIDE { return "convertFloat"; }
	virtual void describe() OVERRIDE
	{
		switch (m_outFormat)
		{
			case kFloat:
				m_outChunk->f.sampleFormat = AF_SAMPFMT_FLOAT;
				m_outChunk->f.sampleWidth = 32;
				break;
			case kDouble:
				m_outChunk->f.sampleFormat = AF_SAMPFMT_DOUBLE;
				m_outChunk->f.sampleWidth = 64;
				break;
			default:
				assert(false);
		}
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		const void *src = inChunk.buffer;
		void *dst = outChunk.buffer;
		size_t count = inChunk.frameCount * inChunk.f.channelCount;

		switch (m_outFormat)
		{
			case kFloat:
				transform<floatToFloat<double, float> >(src, dst, count);
				break;
			case kDouble:
				transform<floatToFloat<float, double> >(src, dst, count);
				break;
			default:
				assert(false);
		}
	}

private:
	FormatCode m_inFormat, m_outFormat;
};

struct Clip : public SimpleModule
{
	Clip(FormatCode format, const PCMInfo &outputMapping) :
		m_format(format),
		m_outputMapping(outputMapping)
	{
	}
	virtual const char *name() const OVERRIDE { return "clip"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.pcm = m_outputMapping;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		const void *src = inChunk.buffer;
		void *dst = outChunk.buffer;
		int count = inChunk.frameCount * inChunk.f.channelCount;

		switch (m_format)
		{
			case kInt8:
				run<int8_t>(src, dst, count); break;
			case kInt16:
				run<int16_t>(src, dst, count); break;
			case kInt24:
			case kInt32:
				run<int32_t>(src, dst, count); break;
			case kFloat:
				run<float>(src, dst, count); break;
			case kDouble:
				run<double>(src, dst, count); break;
			default:
				assert(false);
		}
	}

private:
	FormatCode m_format;
	PCMInfo m_outputMapping;

	template <typename T>
	void run(const void *srcData, void *dstData, int count)
	{
		const T minValue = m_outputMapping.minClip;
		const T maxValue = m_outputMapping.maxClip;

		const T *src = reinterpret_cast<const T *>(srcData);
		T *dst = reinterpret_cast<T *>(dstData);

		for (int i=0; i<count; i++)
		{
			T t = src[i];
			t = std::min(t, maxValue);
			t = std::max(t, minValue);
			dst[i] = t;
		}
	}
};

struct ConvertFloatToIntClip : public SimpleModule
{
	ConvertFloatToIntClip(FormatCode inputFormat, FormatCode outputFormat,
		const PCMInfo &inputMapping, const PCMInfo &outputMapping) :
		m_inputFormat(inputFormat),
		m_outputFormat(outputFormat),
		m_inputMapping(inputMapping),
		m_outputMapping(outputMapping)
	{
		assert(m_inputFormat == kFloat || m_inputFormat == kDouble);
		assert(m_outputFormat == kInt8 ||
			m_outputFormat == kInt16 ||
			m_outputFormat == kInt24 ||
			m_outputFormat == kInt32);
	}
	virtual const char *name() const OVERRIDE { return "convertPCMMapping"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
		m_outChunk->f.sampleWidth = (m_outputFormat + 1) * CHAR_BIT;
		m_outChunk->f.pcm = m_outputMapping;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		const void *src = inChunk.buffer;
		void *dst = outChunk.buffer;
		int count = inChunk.frameCount * inChunk.f.channelCount;

		if (m_inputFormat == kFloat)
		{
			switch (m_outputFormat)
			{
				case kInt8:
					run<float, int8_t>(src, dst, count); break;
				case kInt16:
					run<float, int16_t>(src, dst, count); break;
				case kInt24:
				case kInt32:
					run<float, int32_t>(src, dst, count); break;
				default:
					assert(false);
			}
		}
		else if (m_inputFormat == kDouble)
		{
			switch (m_outputFormat)
			{
				case kInt8:
					run<double, int8_t>(src, dst, count); break;
				case kInt16:
					run<double, int16_t>(src, dst, count); break;
				case kInt24:
				case kInt32:
					run<double, int32_t>(src, dst, count); break;
				default:
					assert(false);
			}
		}
	}

private:
	FormatCode m_inputFormat, m_outputFormat;
	PCMInfo m_inputMapping, m_outputMapping;

	template <typename Input, typename Output>
	void run(const void *srcData, void *dstData, int count)
	{
		const Input *src = reinterpret_cast<const Input *>(srcData);
		Output *dst = reinterpret_cast<Output *>(dstData);

		double m = m_outputMapping.slope / m_inputMapping.slope;
		double b = m_outputMapping.intercept - m * m_inputMapping.intercept;
		double minValue = m_outputMapping.minClip;
		double maxValue = m_outputMapping.maxClip;

		for (int i=0; i<count; i++)
		{
			double t = m * src[i] + b;
			t = std::min(t, maxValue);
			t = std::max(t, minValue);
			dst[i] = static_cast<Output>(t);
		}
	}
};

struct ApplyChannelMatrix : public SimpleModule
{
public:
	ApplyChannelMatrix(FormatCode format, bool isReading,
		int inChannels, int outChannels,
		double minClip, double maxClip, const double *matrix);
	virtual ~ApplyChannelMatrix();
	virtual const char *name() const OVERRIDE;
	virtual void describe() OVERRIDE;
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE;

private:
	FormatCode m_format;
	int m_inChannels, m_outChannels;
	double m_minClip, m_maxClip;
	double *m_matrix;

	void initDefaultMatrix();
	template <typename T>
		void run(const void *input, void *output, int frameCount);
};

struct Transform : public SimpleModule
{
public:
	Transform(FormatCode format,
		const PCMInfo &inputMapping,
		const PCMInfo &outputMapping) :
		m_format(format),
		m_inputMapping(inputMapping),
		m_outputMapping(outputMapping)
	{
		assert(m_format == kFloat || m_format == kDouble);
	}
	virtual const char *name() const OVERRIDE { return "transform"; }
	virtual void describe() OVERRIDE
	{
		m_outChunk->f.pcm = m_outputMapping;
	}
	virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
	{
		int count = inChunk.frameCount * inChunk.f.channelCount;
		if (m_format == kFloat)
			run<float>(inChunk.buffer, outChunk.buffer, count);
		else if (m_format == kDouble)
			run<double>(inChunk.buffer, outChunk.buffer, count);
		else
			assert(false);
	}

private:
	FormatCode m_format;
	PCMInfo m_inputMapping, m_outputMapping;

	template <typename T>
	void run(const void *srcData, void *dstData, int count)
	{
		const T *src = reinterpret_cast<const T *>(srcData);
		T *dst = reinterpret_cast<T *>(dstData);

		double m = m_outputMapping.slope / m_inputMapping.slope;
		double b = m_outputMapping.intercept - m * m_inputMapping.intercept;

		for (int i=0; i<count; i++)
			dst[i] = m * src[i] + b;
	}
};

#endif // SIMPLE_MODULE_H
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"

#include <audiofile.h>
#include <gtest/gtest.h>
#include <limits>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "byteorder.h"
#include "RebufferModule.h"

static void setChunkData(Chunk &chunk, int frameOffset)
{
	int16_t *data = static_cast<int16_t *>(chunk.buffer);
	int channels = chunk.f.channelCount;
	for (unsigned i=0; i<chunk.frameCount; i++)
		for (int c=0; c<channels; c++)
			data[i*channels + c] = (frameOffset + i) * channels + c;
}

static void validateChunkData(const Chunk &chunk, int frameOffset)
{
	const int16_t *data = static_cast<const int16_t *>(chunk.buffer);
	int channels = chunk.f.channelCount;
	for (unsigned i=0; i < chunk.frameCount; i++)
		for (int c=0; c < channels; c++)
			EXPECT_EQ(data[i * channels + c],
				int(frameOffset + i) * channels + c);
}

class TestSourceModule : public Module
{
public:
	TestSourceModule() :
		m_startFrame(0),
		m_frameCount(0),
		m_expectedRequestLength(0)
	{
	}
	unsigned startFrame() const { return m_startFrame; }
	void setStartFrame(unsigned startFrame) { m_startFrame = startFrame; }
	unsigned frameCount() const { return m_frameCount; }
	void setFrameCount(unsigned frameCount) { m_frameCount = frameCount; }
	unsigned expectedRequestLength() const { return m_expectedRequestLength; }
	void setExpectedRequestLength(unsigned expectedRequestLength)
	{
		m_expectedRequestLength = expectedRequestLength;
	}

	void runPull()
	{
		EXPECT_EQ(m_outChunk->frameCount, m_expectedRequestLength);
		unsigned frameCount = std::min<unsigned>(m_outChunk->frameCount, m_frameCount);
		m_outChunk->frameCount = frameCount;
		setChunkData(*m_outChunk, m_startFrame);
		m_startFrame += frameCount;
		m_frameCount -= frameCount;
	}

private:
	unsigned m_startFrame;
	unsigned m_frameCount;
	unsigned m_expectedRequestLength;
};

class TestSinkModule : public Module
{
public:
	TestSinkModule() :
		m_startFrame(0),
		m_expectedRequestLength(0)
	{
	}
	unsigned startFrame() const { return m_startFrame; }
	void setStartFrame(unsigned startFrame) { m_startFrame = startFrame; }
	unsigned expectedRequestLength() const { return m_expectedRequestLength; }
	void setExpectedRequestLength(unsigned expectedRequestLength)
	{
		m_expectedRequestLength = expectedRequestLength;
	}
	void runPush()
	{
		EXPECT_EQ(m_inChunk->frameCount, m_expectedRequestLength);
		validateChunkData(*m_inChunk, m_startFrame);
		m_startFrame += m_inChunk->frameCount;
	}

private:
	unsigned m_startFrame;
	unsigned m_expectedRequestLength;
};

static AudioFormat createAudioFormat(int channels)
{
	AudioFormat f =
	{
		44100,
		AF_SAMPFMT_TWOSCOMP,
		16,
		_AF_BYTEORDER_NATIVE,
		{ 0, 0, 0, 0 },
		channels,
		AF_COMPRESSION_NONE,
		NULL,
		false
	};

	return f;
}

static void testFixedToVariable(bool multiple)
{
	const int channels = 2;
	AudioFormat f = createAudioFormat(channels);

	SharedPtr<RebufferModule> rebuffer =
		new RebufferModule(RebufferModule::FixedToVariable, f.bytesPerFrame(),
			10, multiple);

	SharedPtr<TestSourceModule> source = new TestSourceModule();
	rebuffer->setSource(source.get());

	SharedPtr<Chunk> fixedChunk(new Chunk());
	SharedPtr<Chunk> variableChunk(new Chunk());

	const int maxFrameCount = 50;
	fixedChunk->f = f;
	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());

	variableChunk->f = f;
	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());

	rebuffer->setInChunk(fixedChunk.get());
	rebuffer->setOutChunk(variableChunk.get());

	source->setOutChunk(fixedChunk.get());

	// Initialize source to contain 100 frames.
	source->setFrameCount(100);

	// Request 22 frames from rebuffer module.
	variableChunk->frameCount = 22;
	source->setExpectedRequestLength(multiple ? 30 : 10);
	rebuffer->runPull();
	// Check that 30 frames have been pulled from source module.
	EXPECT_EQ(30u, source->startFrame());
	// Check that rebuffer module has fulfilled request of 22 frames.
	EXPECT_EQ(22u, variableChunk->frameCount);
	// Validate output data.
	validateChunkData(*variableChunk, 0);

	// Request 30 frames from rebuffer module.
	variableChunk->frameCount = 30;
	source->setExpectedRequestLength(multiple ? 30 : 10);
	rebuffer->runPull();
	// Check that 60 frames have been pulled from source module.
	EXPECT_EQ(60u, source->startFrame());
	// Check that rebuffer module has fulfilled request of 28 frames.
	EXPECT_EQ(30u, variableChunk->frameCount);
	// Validate output data.
	validateChunkData(*variableChunk, 22);

	// Request 50 frames from rebuffer module.
	variableChunk->frameCount = 50;
	source->setExpectedRequestLength(multiple ? 50 : 10);
	rebuffer->runPull();
	// Check that 100 frames have been pulled from source module.
	EXPECT_EQ(100u, source->startFrame());
	// Check that rebuffer module has filled 48 of 50 frames requested.
	EXPECT_EQ(48u, variableChunk->frameCount);
	// Validate output data.
	validateChunkData(*variableChunk, 52);
}

TEST(RebufferModule, FixedToVariable)
{
	testFixedToVariable(false);
}

TEST(RebufferModule, FixedToVariable_Multiple)
{
	testFixedToVariable(true);
}

/*
	Make a request to the rebuffer module which is large enough
	to pull the final short chunk from the test source but which
	doesn't consume all the frames of that chunk.

	Verify that a subsequent request to the rebuffer module correctly
	produces the remaining frames of that chunk.
*/
static void testBufferingAfterShortChunk(bool multiple)
{
	const int channels = 2;
	AudioFormat f = createAudioFormat(channels);

	SharedPtr<RebufferModule> rebuffer =
		new RebufferModule(RebufferModule::FixedToVariable, f.bytesPerFrame(),
			10, multiple);

	SharedPtr<TestSourceModule> source = new TestSourceModule();
	rebuffer->setSource(source.get());

	SharedPtr<Chunk> fixedChunk(new Chunk());
	SharedPtr<Chunk> variableChunk(new Chunk());

	const int maxFrameCount = 30;
	fixedChunk->f = f;
	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());

	variableChunk->f = f;
	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());

	rebuffer->setInChunk(fixedChunk.get());
	rebuffer->setOutChunk(variableChunk.get());

	source->setOutChunk(fixedChunk.get());

	// Initialize source to contain 23 frames.
	source->setFrameCount(23);

	// Request 21 frames from rebuffer module.
	variableChunk->frameCount = 21;
	source->setExpectedRequestLength(multiple ? 30 : 10);
	rebuffer->runPull();
	// Check that all 23 frames have been pulled from source module.
	EXPECT_EQ(23u, source->startFrame());
	// Check that rebuffer module has fulfilled request of 21 frames.
	EXPECT_EQ(21u, variableChunk->frameCount);
	// Validate output data.
	validateChunkData(*variableChunk, 0);

	// Request 5 frames from rebuffer module.
	variableChunk->frameCount = 5;
	source->setExpectedRequestLength(-1);
	rebuffer->runPull();
	// Check that rebuffer module has delivered remaining 2 frames.
	EXPECT_EQ(2u, variableChunk->frameCount);
	// Validate output data.
	validateChunkData(*variableChunk, 21);
}

TEST(RebufferModule, FixedToVariable_BufferingAfterShortChunk)
{
	testBufferingAfterShortChunk(false);
}

TEST(RebufferModule, FixedToVariable_BufferingAfterShortChunk_Multiple)
{
	testBufferingAfterShortChunk(true);
}

static void testVariableToFixed(bool multiple)
{
	const int channels = 2;
	AudioFormat f = createAudioFormat(channels);

	SharedPtr<RebufferModule> rebuffer =
		new RebufferModule(RebufferModule::VariableToFixed, f.bytesPerFrame(),
			10, multiple);
	SharedPtr<TestSinkModule> sink = new TestSinkModule();
	rebuffer->setSink(sink.get());

	SharedPtr<Chunk> variableChunk(new Chunk());
	SharedPtr<Chunk> fixedChunk(new Chunk());

	const int maxFrameCount = 40;
	variableChunk->f = f;
	variableChunk->allocate(maxFrameCount * f.bytesPerFrame());

	fixedChunk->f = f;
	fixedChunk->allocate(maxFrameCount * f.bytesPerFrame());

	rebuffer->setInChunk(variableChunk.get());
	rebuffer->setOutChunk(fixedChunk.get());

	sink->setInChunk(fixedChunk.get());

	// Push 23 frames to the rebuffer module.
	variableChunk->frameCount = 23;
	setChunkData(*variableChunk, 0);
	sink->setExpectedRequestLength(multiple ? 20 : 10);
	rebuffer->runPush();
	// Check that 20 frames have been pushed to the sink module.
	EXPECT_EQ(sink->startFrame(), 20u);
	// Check that the last push contained 20 (multiple) or 10 (single) frames.
	EXPECT_EQ(fixedChunk->frameCount, multiple ? 20u : 10u);

	// Push another 37 frames to the rebuffer module.
	variableChunk->frameCount = 37;
	setChunkData(*variableChunk, 23);
	sink->setExpectedRequestLength(multiple ? 40 : 10);
	rebuffer->runPush();
	// Check that 60 frames have been pushed to the sink module.
	EXPECT_EQ(sink->startFrame(), 60u);
	// Check that the last push contained 40 (multiple) or 10 (single) frames.
	EXPECT_EQ(fixedChunk->frameCount, multiple ? 40u : 10u);
}

TEST(RebufferModule, VariableToFixed)
{
	testVariableToFixed(false);
}

TEST(RebufferModule, VariableToFixed_Multiple)
{
	testVariableToFixed(true);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "config.h"

#include <stdlib.h>
#include <assert.h>
#include <string.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <audiofile.h>

#include "File.h"
#include "FileHandle.h"
#include "Instrument.h"
#include "Marker.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "modules/Module.h"
#include "modules/ModuleState.h"
#include "units.h"
#include "util.h"

static status _afOpenFile (int access, File *f, const char *filename,
	AFfilehandle *file, AFfilesetup filesetup);

int _af_identify (File *f, int *implemented)
{
	if (!f->canSeek())
	{
		_af_error(AF_BAD_LSEEK, "Cannot seek in file");
		return AF_FILE_UNKNOWN;
	}

	AFfileoffset curpos = f->tell();

	for (int i=0; i<_AF_NUM_UNITS; i++)
	{
		if (_af_units[i].recognize &&
			_af_units[i].recognize(f))
		{
			if (implemented != NULL)
				*implemented = _af_units[i].implemented;
			f->seek(curpos, File::SeekFromBeginning);
			return _af_units[i].fileFormat;
		}
	}

	f->seek(curpos, File::SeekFromBeginning);

	if (implemented != NULL)
		*implemented = false;

	return AF_FILE_UNKNOWN;
}

int afIdentifyFD (int fd)
{
	/*
		Duplicate the file descriptor since otherwise the
		original file descriptor would get closed when we close
		the virtual file below.
	*/
	fd = dup(fd);
	File *f = File::create(fd, File::ReadAccess);

	int result = _af_identify(f, NULL);

	delete f;

	return result;
}

int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
{
	/*
		Duplicate the file descriptor since otherwise the
		original file descriptor would get closed when we close
		the virtual file below.
	*/
	fd = dup(fd);

	File *f = File::create(fd, File::ReadAccess);
	if (!f)
	{
		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
		return AF_FILE_UNKNOWN;
	}

	int result = _af_identify(f, implemented);

	delete f;

	return result;
}

AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
{
	if (!mode)
	{
		_af_error(AF_BAD_ACCMODE, "null access mode");
		return AF_NULL_FILEHANDLE;
	}

	int access;
	if (mode[0] == 'r')
	{
		access = _AF_READ_ACCESS;
	}
	else if (mode[0] == 'w')
	{
		access = _AF_WRITE_ACCESS;
	}
	else
	{
		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
		return AF_NULL_FILEHANDLE;
	}

	File *f = File::create(fd, access == _AF_READ_ACCESS ?
		File::ReadAccess : File::WriteAccess);

	AFfilehandle filehandle = NULL;
	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
	{
		delete f;
	}

	return filehandle;
}

AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
	const char *filename)
{
	if (!mode)
	{
		_af_error(AF_BAD_ACCMODE, "null access mode");
		return AF_NULL_FILEHANDLE;
	}

	int access;
	if (mode[0] == 'r')
		access = _AF_READ_ACCESS;
	else if (mode[0] == 'w')
		access = _AF_WRITE_ACCESS;
	else
	{
		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
		return AF_NULL_FILEHANDLE;
	}

	File *f = File::create(fd, access == _AF_READ_ACCESS ?
		File::ReadAccess : File::WriteAccess);

	AFfilehandle filehandle;
	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
	{
		delete f;
	}

	return filehandle;
}

AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
{
	if (!mode)
	{
		_af_error(AF_BAD_ACCMODE, "null access mode");
		return AF_NULL_FILEHANDLE;
	}

	int access;
	if (mode[0] == 'r')
	{
		access = _AF_READ_ACCESS;
	}
	else if (mode[0] == 'w')
	{
		access = _AF_WRITE_ACCESS;
	}
	else
	{
		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
		return AF_NULL_FILEHANDLE;
	}

	File *f = File::open(filename,
		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
	if (!f)
	{
		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
		return AF_NULL_FILEHANDLE;
	}

	AFfilehandle filehandle;
	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
	{
		delete f;
	}

	return filehandle;
}

AFfilehandle afOpenVirtualFile (AFvirtualfile *vf, const char *mode,
	AFfilesetup setup)
{
	if (!vf)
	{
		_af_error(AF_BAD_OPEN, "null virtual file");
		return AF_NULL_FILEHANDLE;
	}

	if (!mode)
	{
		_af_error(AF_BAD_ACCMODE, "null access mode");
		return AF_NULL_FILEHANDLE;
	}

	int access;
	if (mode[0] == 'r')
	{
		access = _AF_READ_ACCESS;
	}
	else if (mode[0] == 'w')
	{
		access = _AF_WRITE_ACCESS;
	}
	else
	{
		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
		return AF_NULL_FILEHANDLE;
	}

	File *f = File::create(vf,
		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
	if (!f)
	{
		_af_error(AF_BAD_OPEN, "could not open virtual file");
		return AF_NULL_FILEHANDLE;
	}

	AFfilehandle filehandle;
	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
	{
		delete f;
	}

	return filehandle;
}

static status _afOpenFile (int access, File *f, const char *filename,
	AFfilehandle *file, AFfilesetup filesetup)
{
	int	fileFormat = AF_FILE_UNKNOWN;
	int	implemented = true;

	int		userSampleFormat = 0;
	double		userSampleRate = 0.0;
	PCMInfo	userPCM = {0};
	bool		userFormatSet = false;

	AFfilehandle	filehandle = AF_NULL_FILEHANDLE;
	AFfilesetup	completesetup = AF_NULL_FILESETUP;

	*file = AF_NULL_FILEHANDLE;

	if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
	{
		if (!_af_filesetup_ok(filesetup))
			return AF_FAIL;

		fileFormat = filesetup->fileFormat;
		if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
		{
			_af_error(AF_BAD_FILESETUP,
				"warning: opening file for read access: "
				"ignoring file setup with non-raw file format");
			filesetup = AF_NULL_FILESETUP;
			fileFormat = _af_identify(f, &implemented);
		}
	}
	else if (filesetup == AF_NULL_FILESETUP)
		fileFormat = _af_identify(f, &implemented);

	if (fileFormat == AF_FILE_UNKNOWN)
	{
		if (filename != NULL)
			_af_error(AF_BAD_NOT_IMPLEMENTED,
				"'%s': unrecognized audio file format",
				filename);
		else
			_af_error(AF_BAD_NOT_IMPLEMENTED,
				"unrecognized audio file format");
		return AF_FAIL;
	}

	const char *formatName = _af_units[fileFormat].name;

	if (!implemented)
	{
		_af_error(AF_BAD_NOT_IMPLEMENTED,
			"%s format not currently supported", formatName);
	}

	completesetup = NULL;
	if (filesetup != AF_NULL_FILESETUP)
	{
		userSampleFormat = filesetup->tracks[0].f.sampleFormat;
		userPCM = filesetup->tracks[0].f.pcm;
		userSampleRate = filesetup->tracks[0].f.sampleRate;
		userFormatSet = true;
		if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
			return AF_FAIL;
	}

	filehandle = _AFfilehandle::create(fileFormat);
	if (!filehandle)
	{
		if (completesetup)
			afFreeFileSetup(completesetup);
		return AF_FAIL;
	}

	filehandle->m_fh = f;
	filehandle->m_access = access;
	filehandle->m_seekok = f->canSeek();
	if (filename != NULL)
		filehandle->m_fileName = strdup(filename);
	else
		filehandle->m_fileName = NULL;
	filehandle->m_fileFormat = fileFormat;

	status result = access == _AF_READ_ACCESS ?
		filehandle->readInit(completesetup) :
		filehandle->writeInit(completesetup);

	if (result != AF_SUCCEED)
	{
		delete filehandle;
		filehandle = AF_NULL_FILEHANDLE;
		if (completesetup)
			afFreeFileSetup(completesetup);
		return AF_FAIL;
	}

	if (completesetup)
		afFreeFileSetup(completesetup);

	/*
		Initialize virtual format.
	*/
	for (int t=0; t<filehandle->m_trackCount; t++)
	{
		Track *track = &filehandle->m_tracks[t];

		track->v = track->f;

		if (userFormatSet)
		{
			track->v.sampleFormat = userSampleFormat;
			track->v.pcm = userPCM;
			track->v.sampleRate = userSampleRate;
		}

		track->v.compressionType = AF_COMPRESSION_NONE;
		track->v.compressionParams = NULL;

#if WORDS_BIGENDIAN
		track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
#else
		track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
#endif

		track->ms = new ModuleState();
		if (track->ms->init(filehandle, track) == AF_FAIL)
		{
			delete filehandle;
			return AF_FAIL;
		}
	}

	*file = filehandle;

	return AF_SUCCEED;
}

int afSyncFile (AFfilehandle handle)
{
	if (!_af_filehandle_ok(handle))
		return -1;

	if (handle->m_access == _AF_WRITE_ACCESS)
	{
		/* Finish writes on all tracks. */
		for (int trackno = 0; trackno < handle->m_trackCount; trackno++)
		{
			Track *track = &handle->m_tracks[trackno];

			if (track->ms->isDirty() && track->ms->setup(handle, track) == AF_FAIL)
				return -1;

			if (track->ms->sync(handle, track) != AF_SUCCEED)
				return -1;
		}

		/* Update file headers. */
		if (handle->update() != AF_SUCCEED)
			return AF_FAIL;
	}
	else if (handle->m_access == _AF_READ_ACCESS)
	{
		/* Do nothing. */
	}
	else
	{
		_af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
			handle->m_access);
		return AF_FAIL;
	}

	return AF_SUCCEED;
}

int afCloseFile (AFfilehandle file)
{
	int	err;

	if (!_af_filehandle_ok(file))
		return -1;

	afSyncFile(file);

	err = file->m_fh->close();
	if (err < 0)
		_af_error(AF_BAD_CLOSE, "close returned %d", err);

	delete file->m_fh;
	delete file;

	return 0;
}
/*
	Audio File Library
	Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	pcm.cpp

	This file declares default PCM mappings and defines routines
	for accessing and modifying PCM mappings in a track.
*/

#include "config.h"

#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "modules/Module.h"
#include "modules/ModuleState.h"
#include "pcm.h"
#include "util.h"

extern const PCMInfo _af_default_signed_integer_pcm_mappings[] =
{
	{0, 0, 0, 0},
	{SLOPE_INT8, 0, MIN_INT8, MAX_INT8},
	{SLOPE_INT16, 0, MIN_INT16, MAX_INT16},
	{SLOPE_INT24, 0, MIN_INT24, MAX_INT24},
	{SLOPE_INT32, 0, MIN_INT32, MAX_INT32}
};

extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[] =
{
	{0, 0, 0, 0},
	{SLOPE_INT8, INTERCEPT_U_INT8, 0, MAX_U_INT8},
	{SLOPE_INT16, INTERCEPT_U_INT16, 0, MAX_U_INT16},
	{SLOPE_INT24, INTERCEPT_U_INT24, 0, MAX_U_INT24},
	{SLOPE_INT32, INTERCEPT_U_INT32, 0, MAX_U_INT32}
};

extern const PCMInfo _af_default_float_pcm_mapping =
{1, 0, 0, 0};

extern const PCMInfo _af_default_double_pcm_mapping =
{1, 0, 0, 0};

/*
	Initialize the PCM mapping for a given track.
*/
void afInitPCMMapping (AFfilesetup setup, int trackid,
	double slope, double intercept, double minClip, double maxClip)
{
	if (!_af_filesetup_ok(setup))
		return;

	TrackSetup *track = setup->getTrack(trackid);
	if (!track)
		return;

	track->f.pcm.slope = slope;
	track->f.pcm.intercept = intercept;
	track->f.pcm.minClip = minClip;
	track->f.pcm.maxClip = maxClip;
}

int afSetVirtualPCMMapping (AFfilehandle file, int trackid,
	double slope, double intercept, double minClip, double maxClip)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	track->v.pcm.slope = slope;
	track->v.pcm.intercept = intercept;
	track->v.pcm.minClip = minClip;
	track->v.pcm.maxClip = maxClip;

	track->ms->setDirty();

	return 0;
}

int afSetTrackPCMMapping (AFfilehandle file, int trackid,
	double slope, double intercept, double minClip, double maxClip)
{
	if (!_af_filehandle_ok(file))
		return -1;

	Track *track = file->getTrack(trackid);
	if (!track)
		return -1;

	/*
		NOTE: this is highly unusual: we don't ordinarily
		change track.f after the file is opened.

		PCM mapping is the exception because this information
		is not encoded in sound files' headers using today's
		formats, so the user will probably want to set this
		information on a regular basis.  The defaults may or
		may not be what the user wants.
	*/

	track->f.pcm.slope = slope;
	track->f.pcm.intercept = intercept;
	track->f.pcm.minClip = minClip;
	track->f.pcm.maxClip = maxClip;

	track->ms->setDirty();

	return 0;
}

void afGetPCMMapping (AFfilehandle file, int trackid,
	double *slope, double *intercept, double *minClip, double *maxClip)
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (slope)
		*slope = track->f.pcm.slope;
	if (intercept)
		*intercept = track->f.pcm.intercept;
	if (minClip)
		*minClip = track->f.pcm.minClip;
	if (maxClip)
		*maxClip = track->f.pcm.maxClip;
}

void afGetVirtualPCMMapping (AFfilehandle file, int trackid,
	double *slope, double *intercept, double *minClip, double *maxClip)
{
	if (!_af_filehandle_ok(file))
		return;

	Track *track = file->getTrack(trackid);
	if (!track)
		return;

	if (slope)
		*slope = track->v.pcm.slope;
	if (intercept)
		*intercept = track->v.pcm.intercept;
	if (minClip)
		*minClip = track->v.pcm.minClip;
	if (maxClip)
		*maxClip = track->v.pcm.maxClip;
}
/*
	Audio File Library
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	pcm.h

	This file defines various constants for PCM mapping.
*/

#ifndef PCM_H
#define PCM_H

/*
	SLOPE_INTN = 2^(N-1)
*/
#define SLOPE_INT8 (128.0)
#define SLOPE_INT16 (32768.0)
#define SLOPE_INT24 (8388608.0)
#define SLOPE_INT32 (2147483648.0)

/*
	INTERCEPT_U_INTN = 2^(N-1)
*/
#define INTERCEPT_U_INT8 (128.0)
#define INTERCEPT_U_INT16 (32768.0)
#define INTERCEPT_U_INT24 (8388608.0)
#define INTERCEPT_U_INT32 (2147483648.0)

/*
	MIN_INTN = -(2^(N-1))
*/
#define MIN_INT8 (-128.0)
#define MIN_INT16 (-32768.0)
#define MIN_INT24 (-8388608.0)
#define MIN_INT32 (-2147483648.0)

/*
	MAX_INTN = 2^(N-1) - 1
*/
#define MAX_INT8 127.0
#define MAX_INT16 32767.0
#define MAX_INT24 8388607.0
#define MAX_INT32 2147483647.0

/*
	MAX_U_INTN = 2^N - 1
*/
#define MAX_U_INT8 255.0
#define MAX_U_INT16 65535.0
#define MAX_U_INT24 16777215.0
#define MAX_U_INT32 4294967295.0

extern const PCMInfo _af_default_signed_integer_pcm_mappings[];
extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[];
extern const PCMInfo _af_default_float_pcm_mapping;
extern const PCMInfo _af_default_double_pcm_mapping;

#endif
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	query.cpp

	This file contains the implementation of the Audio File Library's
	query mechanism.  Querying through the afQuery calls can allow the
	programmer to determine the capabilities and characteristics of
	the Audio File Library implementation and its supported formats.
*/

#include "config.h"

#include <assert.h>
#include <stdlib.h>

#include "audiofile.h"
#include "afinternal.h"
#include "aupvlist.h"
#include "error.h"
#include "util.h"
#include "units.h"
#include "compression.h"
#include "Instrument.h"

AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryCompressionParameter (int arg1, int arg2, int arg3, int arg4);

AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4)
{
	switch (querytype)
	{
		case AF_QUERYTYPE_INST:
			return _afQueryInstrument(arg1, arg2, arg3, arg4);
		case AF_QUERYTYPE_INSTPARAM:
			return _afQueryInstrumentParameter(arg1, arg2, arg3, arg4);
		case AF_QUERYTYPE_LOOP:
			return _afQueryLoop(arg1, arg2, arg3, arg4);
		case AF_QUERYTYPE_FILEFMT:
			return _afQueryFileFormat(arg1, arg2, arg3, arg4);
		case AF_QUERYTYPE_COMPRESSION:
			return _afQueryCompression(arg1, arg2, arg3, arg4);
		case AF_QUERYTYPE_COMPRESSIONPARAM:
			/* FIXME: This selector is not implemented. */
			return AU_NULL_PVLIST;
		case AF_QUERYTYPE_MISC:
			/* FIXME: This selector is not implemented. */
			return AU_NULL_PVLIST;
		case AF_QUERYTYPE_MARK:
			return _afQueryMarker(arg1, arg2, arg3, arg4);
	}

	_af_error(AF_BAD_QUERYTYPE, "bad query type");
	return AU_NULL_PVLIST;
}

/* ARGSUSED3 */
AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4)
{
	switch (arg1)
	{
		/* The following select only on arg1. */
		case AF_QUERY_ID_COUNT:
		{
			int	count = 0, idx;
			for (idx = 0; idx < _AF_NUM_UNITS; idx++)
				if (_af_units[idx].implemented)
					count++;
			return _af_pv_long(count);
		}
		/* NOTREACHED */
		break;

		case AF_QUERY_IDS:
		{
			int	count = 0, idx;
			int	*buffer;

			buffer = (int *) _af_calloc(_AF_NUM_UNITS, sizeof (int));
			if (buffer == NULL)
				return AU_NULL_PVLIST;

			for (idx = 0; idx < _AF_NUM_UNITS; idx++)
				if (_af_units[idx].implemented)
					buffer[count++] = idx;

			if (count == 0)
			{
				free(buffer);
				return AU_NULL_PVLIST;
			}

			return _af_pv_pointer(buffer);
		}
		/* NOTREACHED */
		break;

		/* The following select on arg2. */
		case AF_QUERY_LABEL:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].label));

		case AF_QUERY_NAME:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].name));

		case AF_QUERY_DESC:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].description));

		case AF_QUERY_IMPLEMENTED:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return _af_pv_long(0);
			return _af_pv_long(_af_units[arg2].implemented);

		/* The following select on arg3. */
		case AF_QUERY_SAMPLE_FORMATS:
			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			switch (arg2)
			{
				case AF_QUERY_DEFAULT:
					return _af_pv_long(_af_units[arg3].defaultSampleFormat);
				default:
					break;
			}
			/* NOTREACHED */
			break;

		case AF_QUERY_SAMPLE_SIZES:
			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;

			switch (arg2)
			{
				case AF_QUERY_DEFAULT:
					return _af_pv_long(_af_units[arg3].defaultSampleWidth);
				default:
					break;
			}
			/* NOTREACHED */
			break;

		case AF_QUERY_COMPRESSION_TYPES:
		{
			int	idx, count;
			int	*buffer;

			if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
			{
				_af_error(AF_BAD_QUERY,
					"unrecognized file format %d", arg3);
				return AU_NULL_PVLIST;
			}

			switch (arg2)
			{
				case AF_QUERY_VALUE_COUNT:
					count = _af_units[arg3].compressionTypeCount;
					return _af_pv_long(count);

				case AF_QUERY_VALUES:
					count = _af_units[arg3].compressionTypeCount;
					if (count == 0)
						return AU_NULL_PVLIST;

					buffer = (int *) _af_calloc(count, sizeof (int));
					if (buffer == NULL)
						return AU_NULL_PVLIST;

					for (idx = 0; idx < count; idx++)
					{
						buffer[idx] = _af_units[arg3].compressionTypes[idx];
					}

					return _af_pv_pointer(buffer);
			}
		}
		break;
	}

	_af_error(AF_BAD_QUERY, "bad query selector");
	return AU_NULL_PVLIST;
}

long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4)
{
	AUpvlist	list;
	int		type;
	long		value;

	list = afQuery(querytype, arg1, arg2, arg3, arg4);
	if (list == AU_NULL_PVLIST)
		return -1;
	AUpvgetvaltype(list, 0, &type);
	if (type != AU_PVTYPE_LONG)
		return -1;
	AUpvgetval(list, 0, &value);
	AUpvfree(list);
	return value;
}

double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4)
{
	AUpvlist	list;
	int		type;
	double		value;

	list = afQuery(querytype, arg1, arg2, arg3, arg4);
	if (list == AU_NULL_PVLIST)
		return -1;
	AUpvgetvaltype(list, 0, &type);
	if (type != AU_PVTYPE_DOUBLE)
		return -1;
	AUpvgetval(list, 0, &value);
	AUpvfree(list);
	return value;
}

void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4)
{
	AUpvlist	list;
	int		type;
	void		*value;

	list = afQuery(querytype, arg1, arg2, arg3, arg4);
	if (list == AU_NULL_PVLIST)
		return NULL;
	AUpvgetvaltype(list, 0, &type);
	if (type != AU_PVTYPE_PTR)
		return NULL;
	AUpvgetval(list, 0, &value);
	AUpvfree(list);
	return value;
}

/* ARGSUSED3 */
AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4)
{
	switch (arg1)
	{
		/* For the following query types, arg2 is the file format. */
		case AF_QUERY_SUPPORTED:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_long(_af_units[arg2].instrumentParameterCount != 0);

		case AF_QUERY_ID_COUNT:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_long(_af_units[arg2].instrumentParameterCount);

		case AF_QUERY_IDS:
		{
			int	count;
			int	*buffer;

			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			count = _af_units[arg2].instrumentParameterCount;
			if (count == 0)
				return AU_NULL_PVLIST;
			buffer = (int *) _af_calloc(count, sizeof (int));
			if (buffer == NULL)
				return AU_NULL_PVLIST;
			for (int i=0; i<count; i++)
				buffer[i] = _af_units[arg2].instrumentParameters[i].id;
			return _af_pv_pointer(buffer);
		}
		/* NOTREACHED */
		break;

		/*
			For the next few query types, arg2 is the file
			format and arg3 is the instrument parameter id.
		*/
		case AF_QUERY_TYPE:
		{
			int	idx;

			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;

			idx = _af_instparam_index_from_id(arg2, arg3);
			if (idx<0)
				return AU_NULL_PVLIST;
			return _af_pv_long(_af_units[arg2].instrumentParameters[idx].type);
		}

		case AF_QUERY_NAME:
		{
			int	idx;

			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			idx = _af_instparam_index_from_id(arg2, arg3);
			if (idx < 0)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(_af_units[arg2].instrumentParameters[idx].name));
		}

		case AF_QUERY_DEFAULT:
		{
			int	idx;

			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			idx = _af_instparam_index_from_id(arg2, arg3);
			if (idx >= 0)
			{
				AUpvlist	ret = AUpvnew(1);
				AUpvsetparam(ret, 0, _af_units[arg2].instrumentParameters[idx].id);
				AUpvsetvaltype(ret, 0, _af_units[arg2].instrumentParameters[idx].type);
				AUpvsetval(ret, 0, const_cast<AFPVu *>(&_af_units[arg2].instrumentParameters[idx].defaultValue));
				return ret;
			}
			return AU_NULL_PVLIST;
		}
	}

	_af_error(AF_BAD_QUERY, "bad query selector");
	return AU_NULL_PVLIST;
}

/* ARGSUSED2 */
AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4)
{
	if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
		return AU_NULL_PVLIST;

	switch (arg1)
	{
		case AF_QUERY_SUPPORTED:
			return _af_pv_long(_af_units[arg2].loopPerInstrumentCount != 0);
		case AF_QUERY_MAX_NUMBER:
			return _af_pv_long(_af_units[arg2].loopPerInstrumentCount);
	}

	_af_error(AF_BAD_QUERY, "bad query selector");
	return AU_NULL_PVLIST;
}

/* ARGSUSED2 */
AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4)
{
	switch (arg1)
	{
		case AF_QUERY_SUPPORTED:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_long(_af_units[arg2].instrumentCount != 0);

		case AF_QUERY_MAX_NUMBER:
			if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
				return AU_NULL_PVLIST;
			return _af_pv_long(_af_units[arg2].instrumentCount);
	}

	_af_error(AF_BAD_QUERY, "bad query selector");
	return AU_NULL_PVLIST;
}

/* ARGSUSED0 */
AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4)
{
	_af_error(AF_BAD_NOT_IMPLEMENTED, "not implemented yet");
	return AU_NULL_PVLIST;
}

/* ARGSUSED2 */
AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4)
{
	switch (arg1)
	{
		case AF_QUERY_SUPPORTED:
			return _af_pv_long(_af_units[arg2].markerCount != 0);
		case AF_QUERY_MAX_NUMBER:
			return _af_pv_long(_af_units[arg2].markerCount);
	}

	_af_error(AF_BAD_QUERY, "bad query selector");
	return AU_NULL_PVLIST;
}

/* ARGSUSED0 */
AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4)
{
	const CompressionUnit *unit = NULL;

	switch (arg1)
	{
		case AF_QUERY_ID_COUNT:
		{
			int count = 0;
			for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
				if (_af_compression[i].implemented)
					count++;
			return _af_pv_long(count);
		}

		case AF_QUERY_IDS:
		{
			int *buf = (int *) _af_calloc(_AF_NUM_COMPRESSION, sizeof (int));
			if (!buf)
				return AU_NULL_PVLIST;

			int count = 0;
			for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
			{
				if (_af_compression[i].implemented)
					buf[count++] = _af_compression[i].compressionID;
			}
			return _af_pv_pointer(buf);
		}

		case AF_QUERY_IMPLEMENTED:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return _af_pv_long(0);
			return _af_pv_long(unit->implemented);

		case AF_QUERY_NATIVE_SAMPFMT:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return AU_NULL_PVLIST;
			return _af_pv_long(unit->nativeSampleFormat);

		case AF_QUERY_NATIVE_SAMPWIDTH:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return AU_NULL_PVLIST;
			return _af_pv_long(unit->nativeSampleWidth);

		case AF_QUERY_LABEL:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(unit->label));

		case AF_QUERY_NAME:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(unit->shortname));

		case AF_QUERY_DESC:
			unit = _af_compression_unit_from_id(arg2);
			if (!unit)
				return AU_NULL_PVLIST;
			return _af_pv_pointer(const_cast<char *>(unit->name));
	}

	_af_error(AF_BAD_QUERY, "unrecognized query selector %d\n", arg1);
	return AU_NULL_PVLIST;
}
/*
	Audio File Library
	Copyright (C) 2000-2001, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	units.cpp

	This file contains the file format units.
*/

#include "config.h"

#include "Features.h"
#include "audiofile.h"
#include "afinternal.h"
#include "units.h"

#include "AIFF.h"
#include "AVR.h"
#include "CAF.h"
#include "FLACFile.h"
#include "IFF.h"
#include "IRCAM.h"
#include "NeXT.h"
#include "NIST.h"
#include "Raw.h"
#include "SampleVision.h"
#include "VOC.h"
#include "WAVE.h"

#include "compression.h"

#include "modules/ALAC.h"
#include "modules/FLAC.h"
#include "modules/G711.h"
#include "modules/IMA.h"
#include "modules/MSADPCM.h"
#include "modules/PCM.h"

const Unit _af_units[_AF_NUM_UNITS] =
{
	{
		AF_FILE_RAWDATA,
		"Raw Data", "Raw Sound Data", "raw",
		true,
		&RawFile::completeSetup,
		&RawFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_RAW_NUM_COMPTYPES,
		_af_raw_compression_types,
		0,	/* maximum marker count */
		0,	/* maximum instrument count */
		0,	/* maxium number of loops per instrument */
		0, NULL,
	},
	{
		AF_FILE_AIFFC,
		"AIFF-C", "AIFF-C File Format", "aifc",
		true,
		AIFFFile::completeSetup,
		AIFFFile::recognizeAIFFC,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_AIFFC_NUM_COMPTYPES,
		_af_aiffc_compression_types,
		65535,	/* maximum marker count */
		1,	/* maximum instrument count */
		2,	/* maximum number of loops per instrument */
		_AF_AIFF_NUM_INSTPARAMS,
		_af_aiff_inst_params
	},
	{
		AF_FILE_AIFF,
		"AIFF", "Audio Interchange File Format", "aiff",
		true,
		AIFFFile::completeSetup,
		AIFFFile::recognizeAIFF,
		AF_SAMPFMT_TWOSCOMP, 16,
		0,	/* supported compression types */
		NULL,
		65535,	/* maximum marker count */
		1,	/* maximum instrument count */
		2,	/* maximum number of loops per instrument */
		_AF_AIFF_NUM_INSTPARAMS,
		_af_aiff_inst_params
	},
	{
		AF_FILE_NEXTSND,
		"NeXT .snd/Sun .au", "NeXT .snd/Sun .au Format", "next",
		true,
		NeXTFile::completeSetup,
		NeXTFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_NEXT_NUM_COMPTYPES,
		_af_next_compression_types,
		0,	/* maximum marker count */
		0,	/* maximum instrument count */
		0,	/* maximum number of loops per instrument */
		0, NULL
	},
	{
		AF_FILE_WAVE,
		"MS RIFF WAVE", "Microsoft RIFF WAVE Format", "wave",
		true,
		WAVEFile::completeSetup,
		WAVEFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_WAVE_NUM_COMPTYPES,
		_af_wave_compression_types,
		AF_NUM_UNLIMITED,	/* maximum marker count */
		1,			/* maximum instrument count */
		AF_NUM_UNLIMITED,	/* maximum number of loops per instrument */
		_AF_WAVE_NUM_INSTPARAMS,
		_af_wave_inst_params
	},
	{
		AF_FILE_IRCAM,
		"BICSF", "Berkeley/IRCAM/CARL Sound Format", "bicsf",
		true,
		IRCAMFile::completeSetup,
		IRCAMFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_IRCAM_NUM_COMPTYPES,
		_af_ircam_compression_types,
		0,		// maximum marker count
		0,		// maximum instrument count
		0,		// maximum number of loops per instrument
		0,		// number of instrument parameters
		NULL	// instrument parameters
	},
	{
		AF_FILE_MPEG1BITSTREAM,
		"MPEG", "MPEG Audio Bitstream", "mpeg",
		false
	},
	{
		AF_FILE_SOUNDDESIGNER1,
		"Sound Designer 1", "Sound Designer 1 File Format", "sd1",
		false
	},
	{
		AF_FILE_SOUNDDESIGNER2,
		"Sound Designer 2", "Sound Designer 2 File Format", "sd2",
		false
	},
	{
		AF_FILE_AVR,
		"AVR", "Audio Visual Research File Format", "avr",
		true,
		AVRFile::completeSetup,
		AVRFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		0,	/* number of compression types */
		NULL,	/* compression types */
		0,	/* maximum marker count */
		0,	/* maximum instrument count */
		0,	/* maximum number of loops per instrument */
		0,	/* number of instrument parameters */
	},
	{
		AF_FILE_IFF_8SVX,
		"IFF/8SVX", "Amiga IFF/8SVX Sound File Format", "iff",
		true,
		IFFFile::completeSetup,
		IFFFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 8,
		0,	/* number of compression types */
		NULL,	/* compression types */
		0,	/* maximum marker count */
		0,	/* maximum instrument count */
		0,	/* maximum number of loops per instrument */
		0,	/* number of instrument parameters */
	},
	{
		AF_FILE_SAMPLEVISION,
		"Sample Vision", "Sample Vision File Format", "smp",
		true,
		SampleVisionFile::completeSetup,
		SampleVisionFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		0,		// number of compression types
		NULL,	// compression types
		0,		// maximum marker count
		0,		// maximum instrument count
		0,		// maximum number of loops per instrument
		0,		// number of instrument parameters
		NULL	// instrument parameters
	},
	{
		AF_FILE_VOC,
		"VOC", "Creative Voice File Format", "voc",
		true,
		VOCFile::completeSetup,
		VOCFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_VOC_NUM_COMPTYPES,
		_af_voc_compression_types,
		0,		// maximum marker count
		0,		// maximum instrument count
		0,		// maximum number of loops per instrument
		0,		// number of instrument parameters
		NULL	// instrument parameters
	},
	{
		AF_FILE_NIST_SPHERE,
		"NIST SPHERE", "NIST SPHERE File Format", "nist",
		true,
		NISTFile::completeSetup,
		NISTFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		0,	/* number of compression types */
		NULL,	/* compression types */
		0,	/* maximum marker count */
		0,	/* maximum instrument count */
		0,	/* maximum number of loops per instrument */
		0,	/* number of instrument parameters */
		NULL	/* instrument parameters */
	},
	{
		AF_FILE_SOUNDFONT2,
		"SoundFont 2", "SoundFont 2 File Format", "sf2",
		false
	},
	{
		AF_FILE_CAF,
		"CAF", "Core Audio Format", "caf",
		true,
		CAFFile::completeSetup,
		CAFFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_CAF_NUM_COMPTYPES,
		_af_caf_compression_types,
		0,		// maximum marker count
		0,		// maximum instrument count
		0,		// maximum number of loops per instrument
		0,		// number of instrument parameters
		NULL	// instrument parameters
	},
	{
		AF_FILE_FLAC,
		"FLAC", "Free Lossless Audio Codec", "flac",
		true,
		FLACFile::completeSetup,
		FLACFile::recognize,
		AF_SAMPFMT_TWOSCOMP, 16,
		_AF_FLAC_NUM_COMPTYPES,
		_af_flac_compression_types,
		0,		// maximum marker count
		0,		// maximum instrument count
		0,		// maximum number of loops per instrument
		0,		// number of instrument parameters
		NULL	// instrument parameters
	}
};

const CompressionUnit _af_compression[_AF_NUM_COMPRESSION] =
{
	{
		AF_COMPRESSION_NONE,
		true,
		"none",	/* label */
		"none",	/* short name */
		"not compressed",
		1.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		false,	/* needsRebuffer */
		false,	/* multiple_of */
		_af_pcm_format_ok,
		_AFpcminitcompress, _AFpcminitdecompress
	},
	{
		AF_COMPRESSION_G711_ULAW,
		true,
		"ulaw",	/* label */
		"CCITT G.711 u-law",	/* shortname */
		"CCITT G.711 u-law",
		2.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		false,	/* needsRebuffer */
		false,	/* multiple_of */
		_af_g711_format_ok,
		_AFg711initcompress, _AFg711initdecompress
	},
	{
		AF_COMPRESSION_G711_ALAW,
		true,
		"alaw",	/* label */
		"CCITT G.711 A-law",	/* short name */
		"CCITT G.711 A-law",
		2.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		false,	/* needsRebuffer */
		false,	/* multiple_of */
		_af_g711_format_ok,
		_AFg711initcompress, _AFg711initdecompress
	},
	{
		AF_COMPRESSION_IMA,
		true,
		"ima4",	/* label */
		"IMA ADPCM",	/* short name */
		"IMA DVI ADPCM",
		4.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		true,	/* needsRebuffer */
		false,	/* multiple_of */
		_af_ima_adpcm_format_ok,
		_af_ima_adpcm_init_compress, _af_ima_adpcm_init_decompress
	},
	{
		AF_COMPRESSION_MS_ADPCM,
		true,
		"msadpcm",	/* label */
		"MS ADPCM",	/* short name */
		"Microsoft ADPCM",
		4.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		true,	/* needsRebuffer */
		false,	/* multiple_of */
		_af_ms_adpcm_format_ok,
		_af_ms_adpcm_init_compress, _af_ms_adpcm_init_decompress
	},
	{
		AF_COMPRESSION_FLAC,
#if ENABLE(FLAC)
		true,
#else
		false,
#endif
		"flac",	// label
		"FLAC",	// short name
		"Free Lossless Audio Codec",
		1.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		false,	// needsRebuffer
		false,	// multiple_of
		_af_flac_format_ok,
		_af_flac_init_compress, _af_flac_init_decompress
	},
	{
		AF_COMPRESSION_ALAC,
		true,
		"alac",	// label
		"ALAC",	// short name
		"Apple Lossless Audio Codec",
		1.0,
		AF_SAMPFMT_TWOSCOMP, 16,
		true,	// needsRebuffer
		false,	// multiple_of
		_af_alac_format_ok,
		_af_alac_init_compress, _af_alac_init_decompress
	}
};
/*
	Audio File Library
	Copyright (C) 2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	units.h

	This file defines the internal Unit and CompressionUnit
	structures for the Audio File Library.
*/

#ifndef UNIT_H
#define UNIT_H

#include "audiofile.h"
#include "afinternal.h"

struct AudioFormat;
class FileModule;

struct Unit
{
	int	fileFormat;	/* AF_FILEFMT_... */
	const char *name;		/* a 2-3 word name of the file format */
	const char *description;	/* a more descriptive name for the format */
	const char *label;		/* a 4-character label for the format */
	bool implemented;	/* if implemented */

	AFfilesetup (*completesetup) (AFfilesetup setup);
	bool (*recognize) (File *fh);

	int defaultSampleFormat;
	int defaultSampleWidth;

	int compressionTypeCount;
	const int *compressionTypes;

	int markerCount;

	int instrumentCount;
	int loopPerInstrumentCount;

	int instrumentParameterCount;
	const InstParamInfo *instrumentParameters;
};

struct CompressionUnit
{
	int	compressionID;	/* AF_COMPRESSION_... */
	bool implemented;
	const char *label;		/* 4-character (approximately) label */
	const char *shortname;	/* short name in English */
	const char *name;		/* long name in English */
	double squishFactor;	/* compression ratio */
	int	nativeSampleFormat;	/* AF_SAMPFMT_... */
	int	nativeSampleWidth;	/* sample width in bits */
	bool	needsRebuffer;	/* if there are chunk boundary requirements */
	bool	multiple_of;	/* can accept any multiple of chunksize */
	bool	(*fmtok) (AudioFormat *format);

	FileModule *(*initcompress) (Track *track, File *fh,
		bool seekok, bool headerless, AFframecount *chunkframes);
	FileModule *(*initdecompress) (Track *track, File *fh,
		bool seekok, bool headerless, AFframecount *chunkframes);
};

#define _AF_NUM_UNITS 17
#define _AF_NUM_COMPRESSION 7

extern const Unit _af_units[_AF_NUM_UNITS];
extern const CompressionUnit _af_compression[_AF_NUM_COMPRESSION];

#endif /* UNIT_H */
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2000, Silicon Graphics, Inc.

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	util.c

	This file contains general utility routines for the Audio File
	Library.
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "audiofile.h"
#include "aupvlist.h"

#include "AudioFormat.h"
#include "File.h"
#include "FileHandle.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "aupvinternal.h"
#include "byteorder.h"
#include "compression.h"
#include "pcm.h"
#include "units.h"
#include "util.h"

/*
	_af_filesetup_ok and _af_filehandle_ok are sanity check routines
	which are called at the beginning of every external subroutine.
*/
bool _af_filesetup_ok (AFfilesetup setup)
{
	if (setup == AF_NULL_FILESETUP)
	{
		_af_error(AF_BAD_FILESETUP, "null file setup");
		return false;
	}
	if (setup->valid != _AF_VALID_FILESETUP)
	{
		_af_error(AF_BAD_FILESETUP, "invalid file setup");
		return false;
	}
	return true;
}

bool _af_filehandle_ok (AFfilehandle file)
{
	if (file == AF_NULL_FILEHANDLE)
	{
		_af_error(AF_BAD_FILEHANDLE, "null file handle");
		return false;
	}
	if (file->m_valid != _AF_VALID_FILEHANDLE)
	{
		_af_error(AF_BAD_FILEHANDLE, "invalid file handle");
		return false;
	}
	return true;
}

void *_af_malloc (size_t size)
{
	void	*p;

	if (size <= 0)
	{
		_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
		return NULL;
	}

	p = malloc(size);

#ifdef AF_DEBUG
	if (p)
		memset(p, 0xff, size);
#endif

	if (p == NULL)
	{
		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
		return NULL;
	}

	return p;
}

char *_af_strdup (const char *s)
{
	char *p = (char *) malloc(strlen(s) + 1);

	if (p)
		strcpy(p, s);

	return p;
}

void *_af_realloc (void *p, size_t size)
{
	if (size <= 0)
	{
		_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
		return NULL;
	}

	p = realloc(p, size);

	if (p == NULL)
	{
		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
		return NULL;
	}

	return p;
}

void *_af_calloc (size_t nmemb, size_t size)
{
	void	*p;

	if (nmemb <= 0 || size <= 0)
	{
		_af_error(AF_BAD_MALLOC, "bad memory allocation size request "
			"%zd elements of %zd bytes each", nmemb, size);
		return NULL;
	}

	p = calloc(nmemb, size);

	if (p == NULL)
	{
		_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed",
			nmemb*size);
		return NULL;
	}

	return p;
}

AUpvlist _af_pv_long (long val)
{
	AUpvlist	ret = AUpvnew(1);
	AUpvsetparam(ret, 0, 0);
	AUpvsetvaltype(ret, 0, AU_PVTYPE_LONG);
	AUpvsetval(ret, 0, &val);
	return ret;
}

AUpvlist _af_pv_double (double val)
{
	AUpvlist	ret = AUpvnew(1);
	AUpvsetparam(ret, 0, 0);
	AUpvsetvaltype(ret, 0, AU_PVTYPE_DOUBLE);
	AUpvsetval(ret, 0, &val);
	return ret;
}

AUpvlist _af_pv_pointer (void *val)
{
	AUpvlist	ret = AUpvnew(1);
	AUpvsetparam(ret, 0, 0);
	AUpvsetvaltype(ret, 0, AU_PVTYPE_PTR);
	AUpvsetval(ret, 0, &val);
	return ret;
}

bool _af_pv_getlong (AUpvlist pvlist, int param, long *l)
{
	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
	{
		int	p, t;

		AUpvgetparam(pvlist, i, &p);

		if (p != param)
			continue;

		AUpvgetvaltype(pvlist, i, &t);

		/* Ensure that this parameter is of type AU_PVTYPE_LONG. */
		if (t != AU_PVTYPE_LONG)
			return false;

		AUpvgetval(pvlist, i, l);
		return true;
	}

	return false;
}

bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d)
{
	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
	{
		int	p, t;

		AUpvgetparam(pvlist, i, &p);

		if (p != param)
			continue;

		AUpvgetvaltype(pvlist, i, &t);

		/* Ensure that this parameter is of type AU_PVTYPE_DOUBLE. */
		if (t != AU_PVTYPE_DOUBLE)
			return false;

		AUpvgetval(pvlist, i, d);
		return true;
	}

	return false;
}

bool _af_pv_getptr (AUpvlist pvlist, int param, void **v)
{
	for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
	{
		int	p, t;

		AUpvgetparam(pvlist, i, &p);

		if (p != param)
			continue;

		AUpvgetvaltype(pvlist, i, &t);

		/* Ensure that this parameter is of type AU_PVTYPE_PTR. */
		if (t != AU_PVTYPE_PTR)
			return false;

		AUpvgetval(pvlist, i, v);
		return true;
	}

	return false;
}

int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4)
{
	int	size = 0;

	switch (format->sampleFormat)
	{
		case AF_SAMPFMT_FLOAT:
			size = sizeof (float);
			break;
		case AF_SAMPFMT_DOUBLE:
			size = sizeof (double);
			break;
		default:
			size = (int) (format->sampleWidth + 7) / 8;
			if (format->compressionType == AF_COMPRESSION_NONE &&
				size == 3 && stretch3to4)
				size = 4;
			break;
	}

	return size;
}

float _af_format_sample_size (const AudioFormat *fmt, bool stretch3to4)
{
	const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
	float squishFactor = unit->squishFactor;

	return _af_format_sample_size_uncompressed(fmt, stretch3to4) /
		squishFactor;
}

int _af_format_frame_size_uncompressed (const AudioFormat *fmt, bool stretch3to4)
{
	return _af_format_sample_size_uncompressed(fmt, stretch3to4) *
		fmt->channelCount;
}

float _af_format_frame_size (const AudioFormat *fmt, bool stretch3to4)
{
	const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
	float squishFactor = unit->squishFactor;

	return _af_format_frame_size_uncompressed(fmt, stretch3to4) /
		squishFactor;
}

/*
	Set the sampleFormat and sampleWidth fields in f, and set the
	PCM info to the appropriate default values for the given sample
	format and sample width.
*/
status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth)
{
	switch (sampleFormat)
	{
		case AF_SAMPFMT_UNSIGNED:
		case AF_SAMPFMT_TWOSCOMP:
		if (sampleWidth < 1 || sampleWidth > 32)
		{
			_af_error(AF_BAD_SAMPFMT,
				"illegal sample width %d for integer data",
				sampleWidth);
			return AF_FAIL;
		}
		else
		{
			int bytes;

			f->sampleFormat = sampleFormat;
			f->sampleWidth = sampleWidth;

			bytes = _af_format_sample_size_uncompressed(f, false);

			if (sampleFormat == AF_SAMPFMT_TWOSCOMP)
				f->pcm = _af_default_signed_integer_pcm_mappings[bytes];
			else
				f->pcm = _af_default_unsigned_integer_pcm_mappings[bytes];
		}
		break;

		case AF_SAMPFMT_FLOAT:
			f->sampleFormat = sampleFormat;
			f->sampleWidth = 32;
			f->pcm = _af_default_float_pcm_mapping;
			break;
		case AF_SAMPFMT_DOUBLE:
			f->sampleFormat = sampleFormat;
			f->sampleWidth = 64;      /*for convenience */
			f->pcm = _af_default_double_pcm_mapping;
			break;
		default:
			_af_error(AF_BAD_SAMPFMT, "unknown sample format %d",
				sampleFormat);
			return AF_FAIL;
	}

	return AF_SUCCEED;
}

/*
	Verify the uniqueness of the nids ids given.

	idname is the name of what the ids identify, as in "loop"
	iderr is an error as in AF_BAD_LOOPID
*/
bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr)
{
	for (int i = 0; i < nids; i++)
	{
		for (int j = 0; j < i; j++)
		{
			if (ids[i] == ids[j])
			{
				_af_error(iderr, "nonunique %s id %d", idname, ids[i]);
				return false;
			}
		}
	}

	return true;
}
/*
	Audio File Library
	Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

/*
	util.h

	This file contains some general utility functions for the Audio
	File Library.
*/

#ifndef UTIL_H
#define UTIL_H

#include <stdint.h>
#include <stdlib.h>

#include "audiofile.h"
#include "afinternal.h"

struct AudioFormat;

bool _af_filesetup_ok (AFfilesetup setup);
bool _af_filehandle_ok (AFfilehandle file);

void *_af_malloc (size_t size);
void *_af_realloc (void *ptr, size_t size);
void *_af_calloc (size_t nmemb, size_t size);
char *_af_strdup (const char *s);

AUpvlist _af_pv_long (long val);
AUpvlist _af_pv_double (double val);
AUpvlist _af_pv_pointer (void *val);

bool _af_pv_getlong (AUpvlist pvlist, int param, long *l);
bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d);
bool _af_pv_getptr (AUpvlist pvlist, int param, void **v);

bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr);

float _af_format_frame_size (const AudioFormat *format, bool stretch3to4);
int _af_format_frame_size_uncompressed (const AudioFormat *format, bool stretch3to4);
float _af_format_sample_size (const AudioFormat *format, bool stretch3to4);
int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4);

status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth);

#endif
sfconvert
sfinfo
AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile

bin_PROGRAMS = sfconvert sfinfo

sfconvert_SOURCES = sfconvert.c printinfo.c printinfo.h

sfinfo_SOURCES = sfinfo.c printinfo.c printinfo.h

LDADD = $(top_builddir)/libaudiofile/libaudiofile.la

DEPENDENCIES = $(top_builddir)/libaudiofile/libaudiofile.la

AM_CFLAGS = -Wall $(WERROR_CFLAGS)
/*
	Audio File Library

	Copyright 1998, 2011, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	printinfo.c

	This file contains the function used by the sf commands to print
	information regarding a file.
*/

#include "config.h"
#include "printinfo.h"

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

static char *copyrightstring (AFfilehandle file);

bool printfileinfo (const char *filename)
{
	AFfilehandle file = afOpenFile(filename, "r", NULL);
	if (!file)
		return false;

	int fileFormat = afGetFileFormat(file, NULL);
	const char *formatstring =
		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_DESC,
			fileFormat, 0, 0);
	const char *labelstring =
		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_LABEL,
			fileFormat, 0, 0);

	if (!formatstring || !labelstring)
		return false;

	printf("File Name      %s\n", filename);
	printf("File Format    %s (%s)\n", formatstring, labelstring);

	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);

	int byteOrder = afGetByteOrder(file, AF_DEFAULT_TRACK);

	printf("Data Format    ");

	int compressionType = afGetCompression(file, AF_DEFAULT_TRACK);
	if (compressionType == AF_COMPRESSION_NONE)
	{
		switch (sampleFormat)
		{
			case AF_SAMPFMT_TWOSCOMP:
				printf("%d-bit integer (2's complement, %s)",
					sampleWidth,
					byteOrder == AF_BYTEORDER_BIGENDIAN ?
						"big endian" : "little endian");
				break;
			case AF_SAMPFMT_UNSIGNED:
				printf("%d-bit integer (unsigned, %s)",
					sampleWidth,
					byteOrder == AF_BYTEORDER_BIGENDIAN ?
						"big endian" : "little endian");
				break;
			case AF_SAMPFMT_FLOAT:
				printf("single-precision (32-bit) floating point, %s",
					byteOrder == AF_BYTEORDER_BIGENDIAN ?
						"big endian" : "little endian");
				break;
			case AF_SAMPFMT_DOUBLE:
				printf("double-precision (64-bit) floating point, %s",
					byteOrder == AF_BYTEORDER_BIGENDIAN ?
						"big endian" : "little endian");
				break;
			default:
				printf("unknown");
				break;
		}
	}
	else
	{
		const char *compressionName =
			(const char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
				AF_QUERY_NAME, compressionType, 0, 0);

		if (!compressionName)
			printf("unknown compression");
		else
			printf("%s compression", compressionName);
	}
	printf("\n");

	printf("Audio Data     %jd bytes begins at offset %jd (%jx hex)\n",
		(intmax_t) afGetTrackBytes(file, AF_DEFAULT_TRACK),
		(intmax_t) afGetDataOffset(file, AF_DEFAULT_TRACK),
		(uintmax_t) afGetDataOffset(file, AF_DEFAULT_TRACK));

	printf("               %d channel%s, %jd frames\n",
		afGetChannels(file, AF_DEFAULT_TRACK),
		afGetChannels(file, AF_DEFAULT_TRACK) > 1 ? "s" : "",
		(intmax_t) afGetFrameCount(file, AF_DEFAULT_TRACK));

	printf("Sampling Rate  %.2f Hz\n", afGetRate(file, AF_DEFAULT_TRACK));

	printf("Duration       %.3f seconds\n",
		afGetFrameCount(file, AF_DEFAULT_TRACK) /
		afGetRate(file, AF_DEFAULT_TRACK));

	char *copyright = copyrightstring(file);
	if (copyright)
	{
		printf("Copyright      %s\n", copyright);
		free(copyright);
	}

	afCloseFile(file);

	return true;
}

static char *copyrightstring (AFfilehandle file)
{
	char	*copyright = NULL;
	int		*miscids;
	int		i, misccount;

	misccount = afGetMiscIDs(file, NULL);
	miscids = (int *) malloc(sizeof (int) * misccount);
	afGetMiscIDs(file, miscids);

	for (i=0; i<misccount; i++)
	{
		if (afGetMiscType(file, miscids[i]) != AF_MISC_COPY)
			continue;

		/*
			If this code executes, the miscellaneous chunk is a
			copyright chunk.
		*/
		int datasize = afGetMiscSize(file, miscids[i]);
		char *data = (char *) malloc(datasize);
		afReadMisc(file, miscids[i], data, datasize);
		copyright = data;
		break;
	}

	free(miscids);

	return copyright;
}

/*
    0.73s 44100.00 aiff  1ch 16b -- flute.aif
*/
bool printshortinfo (const char *filename)
{
	AFfilehandle file = afOpenFile(filename, "r", NULL);;
	if (!file)
		return false;

	int fileFormat = afGetFileFormat(file, NULL);
	double sampleRate = afGetRate(file, AF_DEFAULT_TRACK);
	double duration = afGetFrameCount(file, AF_DEFAULT_TRACK) / sampleRate;
	const char *labelString =
		(const char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_LABEL,
			fileFormat, 0, 0);
	int channels = afGetChannels(file, AF_DEFAULT_TRACK);
	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);

	int compressionType = afGetCompression(file, AF_DEFAULT_TRACK);
	const char *compressionName = "--";
	if (compressionType != AF_COMPRESSION_NONE)
	{
		compressionName =
			(const char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
				AF_QUERY_NAME, compressionType, 0, 0);
		if (!compressionName)
			compressionName = "unk";
	}

	printf("%8.2fs %8.2f %4s %2dch %2db %s %s\n",
		duration,
		sampleRate,
		labelString,
		channels,
		sampleWidth,
		compressionName,
		filename);

	afCloseFile(file);

	return true;
}
/*
	Audio File Library

	Copyright 2011, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef PRINTINFO_H
#define PRINTINFO_H

#include <stdbool.h>

bool printfileinfo(const char *filename);
bool printshortinfo(const char *filename);

#endif
/*
	Audio File Library

	Copyright (C) 1998, 2011-2012, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	sfconvert is a program which can convert various parameters of
	sound files.
*/

#include "config.h"

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "printinfo.h"

void printversion (void);
void printusage (void);
void usageerror (void);
bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid);

int main (int argc, char **argv)
{
	if (argc == 2)
	{
		if (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))
		{
			printversion();
			exit(EXIT_SUCCESS);
		}

		if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
		{
			printusage();
			exit(EXIT_SUCCESS);
		}
	}

	if (argc < 3)
		usageerror();

	const char *inFileName = argv[1];
	const char *outFileName = argv[2];

	int outFileFormat = AF_FILE_UNKNOWN;
	int outSampleFormat = -1, outSampleWidth = -1, outChannelCount = -1;
	int outCompression = AF_COMPRESSION_NONE;
	double outMaxAmp = 1.0;

	int i = 3;

	while (i < argc)
	{
		if (!strcmp(argv[i], "format"))
		{
			if (i + 1 >= argc)
				usageerror();

			if (!strcmp(argv[i+1], "aiff"))
				outFileFormat = AF_FILE_AIFF;
			else if (!strcmp(argv[i+1], "aifc"))
				outFileFormat = AF_FILE_AIFFC;
			else if (!strcmp(argv[i+1], "wave"))
				outFileFormat = AF_FILE_WAVE;
			else if (!strcmp(argv[i+1], "next"))
				outFileFormat = AF_FILE_NEXTSND;
			else if (!strcmp(argv[i+1], "bics"))
				outFileFormat = AF_FILE_BICSF;
			else if (!strcmp(argv[i+1], "smp"))
				outFileFormat = AF_FILE_SAMPLEVISION;
			else if (!strcmp(argv[i+1], "voc"))
				outFileFormat = AF_FILE_VOC;
			else if (!strcmp(argv[i+1], "nist"))
				outFileFormat = AF_FILE_NIST_SPHERE;
			else if (!strcmp(argv[i+1], "caf"))
				outFileFormat = AF_FILE_CAF;
			else if (!strcmp(argv[i+1], "flac"))
				outFileFormat = AF_FILE_FLAC;
			else
			{
				fprintf(stderr, "sfconvert: Unknown format %s.\n", argv[i+1]);
				exit(EXIT_FAILURE);
			}

			// Increment for argument.
			i++;
		}
		else if (!strcmp(argv[i], "channels"))
		{
			if (i + 1 >= argc)
				usageerror();

			outChannelCount = atoi(argv[i+1]);
			if (outChannelCount < 1)
				usageerror();

			// Increment for argument.
			i++;
		}
		else if (!strcmp(argv[i], "float"))
		{
			if (i + 1 >= argc)
				usageerror();

			outSampleFormat = AF_SAMPFMT_FLOAT;
			outSampleWidth = 32;
			outMaxAmp = atof(argv[i+1]);

			// outMaxAmp is currently unused.
			(void) outMaxAmp;

			// Increment for argument.
			i++;
		}
		else if (!strcmp(argv[i], "integer"))
		{
			if (i + 2 >= argc)
				usageerror();

			outSampleWidth = atoi(argv[i+1]);
			if (outSampleWidth < 1 || outSampleWidth > 32)
				usageerror();

			if (!strcmp(argv[i+2], "2scomp"))
				outSampleFormat = AF_SAMPFMT_TWOSCOMP;
			else if (!strcmp(argv[i+2], "unsigned"))
				outSampleFormat = AF_SAMPFMT_UNSIGNED;
			else
				usageerror();

			// Increment for arguments.
			i += 2;
		}
		else if (!strcmp(argv[i], "compression"))
		{
			if (i + 1 >= argc)
				usageerror();

			if (!strcmp(argv[i+1], "none"))
				outCompression = AF_COMPRESSION_NONE;
			else if (!strcmp(argv[i+1], "ulaw"))
				outCompression = AF_COMPRESSION_G711_ULAW;
			else if (!strcmp(argv[i+1], "alaw"))
				outCompression = AF_COMPRESSION_G711_ALAW;
			else if (!strcmp(argv[i+1], "ima"))
				outCompression = AF_COMPRESSION_IMA;
			else if (!strcmp(argv[i+1], "msadpcm"))
				outCompression = AF_COMPRESSION_MS_ADPCM;
			else if (!strcmp(argv[i+1], "flac"))
				outCompression = AF_COMPRESSION_FLAC;
			else if (!strcmp(argv[i+1], "alac"))
				outCompression = AF_COMPRESSION_ALAC;
			else
			{
				fprintf(stderr, "sfconvert: Unknown compression format %s.\n", argv[i+1]);
				exit(EXIT_FAILURE);
			}

			i++;
		}
		else
		{
			printf("Unrecognized command %s\n", argv[i]);
		}

		i++;
	}

	AFfilehandle inFile = afOpenFile(inFileName, "r", AF_NULL_FILESETUP);
	if (!inFile)
	{
		printf("Could not open file '%s' for reading.\n", inFileName);
		return EXIT_FAILURE;
	}

	// Get audio format parameters from input file.
	int fileFormat = afGetFileFormat(inFile, NULL);
	int channelCount = afGetChannels(inFile, AF_DEFAULT_TRACK);
	double sampleRate = afGetRate(inFile, AF_DEFAULT_TRACK);
	int sampleFormat, sampleWidth;
	afGetSampleFormat(inFile, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);

	// Initialize output audio format parameters.
	AFfilesetup outFileSetup = afNewFileSetup();

	if (outFileFormat == -1)
		outFileFormat = fileFormat;

	if (outSampleFormat == -1 || outSampleWidth == -1)
	{
		outSampleFormat = sampleFormat;
		outSampleWidth = sampleWidth;
	}

	if (outChannelCount == -1)
		outChannelCount = channelCount;

	afInitFileFormat(outFileSetup, outFileFormat);
	afInitCompression(outFileSetup, AF_DEFAULT_TRACK, outCompression);
	afInitSampleFormat(outFileSetup, AF_DEFAULT_TRACK, outSampleFormat,
		outSampleWidth);
	afInitChannels(outFileSetup, AF_DEFAULT_TRACK, outChannelCount);
	afInitRate(outFileSetup, AF_DEFAULT_TRACK, sampleRate);

	AFfilehandle outFile = afOpenFile(outFileName, "w", outFileSetup);
	if (!outFile)
	{
		printf("Could not open file '%s' for writing.\n", outFileName);
		return EXIT_FAILURE;
	}

	afFreeFileSetup(outFileSetup);

	/*
		Set the output file's virtual audio format parameters
		to match the audio format parameters of the input file.
	*/
	afSetVirtualChannels(outFile, AF_DEFAULT_TRACK, channelCount);
	afSetVirtualSampleFormat(outFile, AF_DEFAULT_TRACK, sampleFormat,
		sampleWidth);

	bool success = copyaudiodata(inFile, outFile, AF_DEFAULT_TRACK);

	afCloseFile(inFile);
	afCloseFile(outFile);

	if (!success)
	{
		unlink(outFileName);
		return EXIT_FAILURE;
	}

	printfileinfo(inFileName);
	putchar('\n');
	printfileinfo(outFileName);

	return EXIT_SUCCESS;
}

void printusage (void)
{
	printf("usage: sfconvert infile outfile [ options ... ] [ output keywords ... ]\n");
	printf("\n");

	printf("Where keywords specify format of input or output soundfile:\n");
	printf("    format f       file format f (see below)\n");
	printf("    compression c  compression format c (see below)\n");
	printf("    byteorder e    endian (e is big or little)\n");
	printf("    channels n     n-channel file (1 or 2)\n");
	printf("    integer n s    n-bit integer file, where s is one of\n");
	printf("                       2scomp: 2's complement signed data\n");
	printf("                       unsigned: unsigned data\n");
	printf("    float m        floating point file, maxamp m (usually 1.0)\n");
	printf("\n");

	printf("Currently supported file formats are:\n");
	printf("\n");
	printf("    aiff    Audio Interchange File Format\n");
	printf("    aifc    AIFF-C File Format\n");
	printf("    next    NeXT/Sun Format\n");
	printf("    wave    MS RIFF WAVE Format\n");
	printf("    bics    Berkeley/IRCAM/CARL Sound File Format\n");
	printf("    smp     Sample Vision Format\n");
	printf("    voc     Creative Voice File\n");
	printf("    nist    NIST SPHERE Format\n");
	printf("    caf     Core Audio Format\n");
	printf("\n");

	printf("Currently supported compression formats are:\n");
	printf("\n");
	printf("    ulaw    G.711 u-law\n");
	printf("    alaw    G.711 A-law\n");
	printf("    ima     IMA ADPCM\n");
	printf("    msadpcm MS ADPCM\n");
	printf("    flac    FLAC\n");
	printf("    alac    Apple Lossless Audio Codec\n");
	printf("\n");
}

void usageerror (void)
{
	printusage();
	exit(EXIT_FAILURE);
}

void printversion (void)
{
	printf("sfconvert: Audio File Library version %s\n", VERSION);
}

/*
	Copy audio data from one file to another.  This function
	assumes that the virtual sample formats of the two files
	match.
*/
bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid)
{
	int frameSize = afGetVirtualFrameSize(infile, trackid, 1);

	const int kBufferFrameCount = 65536;
	void *buffer = malloc(kBufferFrameCount * frameSize);

	AFframecount totalFrames = afGetFrameCount(infile, AF_DEFAULT_TRACK);
	AFframecount totalFramesWritten = 0;

	bool success = true;

	while (totalFramesWritten < totalFrames)
	{
		AFframecount framesToRead = totalFrames - totalFramesWritten;
		if (framesToRead > kBufferFrameCount)
			framesToRead = kBufferFrameCount;

		AFframecount framesRead = afReadFrames(infile, trackid, buffer,
			framesToRead);

		if (framesRead < framesToRead)
		{
			fprintf(stderr, "Bad read of audio track data.\n");
			success = false;
			break;
		}

		AFframecount framesWritten = afWriteFrames(outfile, trackid, buffer,
			framesRead);

		if (framesWritten < framesRead)
		{
			fprintf(stderr, "Bad write of audio track data.\n");
			success = false;
			break;
		}

		totalFramesWritten += framesWritten;
	}

	free(buffer);

	return success;
}
/*
	Audio File Library

	Copyright 1998, 2011, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	sfinfo.c

	This program displays information about audio files.
*/

#include "config.h"

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "printinfo.h"

bool reportError = false;

void errorHandler(long error, const char *message)
{
	if (reportError)
		fprintf(stderr, "sfinfo: %s [error %ld]\n", message, error);
}

void printusage()
{
	printf("usage: sfinfo [options...] soundfiles...\n");
	printf("options:\n");
	printf("  -s, --short        Print information in short format\n");
	printf("  -r, --reporterror  Report errors when reading sound files\n");
	printf("  -h, --help         Print this help message\n");
	printf("  -v, --version      Print version\n");
}

void printversion()
{
	printf("sfinfo: Audio File Library version %s\n", VERSION);
}

int main(int argc, char **argv)
{
	bool brief = false;

	afSetErrorHandler(errorHandler);

	if (argc == 1)
	{
		printusage();
		return 0;
	}

	static struct option long_options[] =
	{
		{"short", 0, 0, 's'},
		{"reporterror", 0, 0, 'r'},
		{"help", 0, 0, 'h'},
		{"version", 0, 0, 'v'},
		{0, 0, 0, 0}
	};

	int result;
	int option_index = 1;
	while ((result = getopt_long(argc, argv, "srhv", long_options,
		&option_index)) != -1)
	{
		switch (result)
		{
			case 's':
				brief = true;
				break;
			case 'r':
				reportError = true;
				break;
			case 'h':
				printusage();
				exit(EXIT_SUCCESS);
			case 'v':
				printversion();
				exit(EXIT_SUCCESS);
		}
	}

	int i = optind;
	while (i < argc)
	{
		bool processed = brief ? printshortinfo(argv[i]) :
			printfileinfo(argv[i]);
		i++;
		if (!brief && processed && i < argc)
			putchar('\n');
	}

	return 0;
}
ADPCM
AES
ALAC
ChannelMatrix
Error
FLAC
FloatToInt
FormatWithChannels
Identify
Instrument
IntToFloat
InvalidCompressionFormat
InvalidSampleFormat
Large
Loop
Marker
Miscellaneous
NeXT
PCMData
PCMMapping
Pipe
Query
SampleFormat
Seek
Sign
VirtualFile
coverage
floatto24
instparamtest
instparamwrite
printmarkers
query2
sixteen-to-eight
testaupv
testchannelmatrix
testdouble
testfloat
testmarkers
twentyfour
twentyfour2
writealaw
writeraw
writeulaw
/*
	Audio File Library

	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdio.h>
#include <cstdlib>
#include <unistd.h>

#include "TestUtilities.h"

static const int kIMABytesPerPacketQT = 34;
static const int kIMABytesPerPacketWAVE = 256;

static const int kIMAFramesPerPacketQT = 64;
static const int kIMAFramesPerPacketWAVE = 505;

static const int kIMAThresholdQT = 128;
static const int kIMAThresholdWAVE = 16;

static const int kMSADPCMBytesPerPacket = 256;
static const int kMSADPCMFramesPerPacket = 500;
static const int kMSADPCMThreshold = 16;

static void testADPCM(int fileFormat, int compressionFormat, int channelCount,
	int bytesPerPacket, int framesPerPacket, int frameCount, int threshold)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("ADPCM", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);
	afFreeFileSetup(setup);

	int16_t *data = new int16_t[frameCount * channelCount];
	for (int i=0; i<frameCount; i++)
		for (int c=0; c<channelCount; c++)
			data[i*channelCount + c] = i * ((c&1) ? -1 : 1);
	
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);

	ASSERT_EQ(afCloseFile(file), 0);

	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
	ASSERT_TRUE(file);
	ASSERT_EQ(afGetCompression(file, AF_DEFAULT_TRACK), compressionFormat);
	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);
	ASSERT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
		(bytesPerPacket * frameCount) / framesPerPacket);

	int16_t *readData = new int16_t[frameCount * channelCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);

	for (int i=0; i<frameCount; i++)
		for (int c=0; c<channelCount; c++)
			EXPECT_LE(std::abs(data[i*channelCount + c] - readData[i*channelCount + c]), threshold);

	int16_t *offsetReadData = new int16_t[frameCount * channelCount];

	// Read entire file with a seek before each read operation.
	for (AFframecount offset = 0; offset < frameCount; offset += framesPerPacket + 3)
	{
		ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, offset), offset);

		AFframecount framesToRead = 1091;
		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, offsetReadData, framesToRead);
		ASSERT_EQ(framesRead, std::min(framesToRead, frameCount - offset));

		for (int i=0; i<framesRead; i++)
			for (int c=0; c<channelCount; c++)
				EXPECT_EQ(readData[(i+offset)*channelCount + c],
					offsetReadData[i*channelCount + c]);
	}

	// Read entire file sequentially in multiple read operations.
	ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);

	AFframecount framesToRead = 1087;
	for (AFframecount offset = 0; offset < frameCount; offset += framesToRead)
	{
		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, offsetReadData, framesToRead);
		ASSERT_EQ(framesRead, std::min(framesToRead, frameCount - offset));

		for (int i=0; i<framesRead; i++)
			for (int c=0; c<channelCount; c++)
				EXPECT_EQ(readData[(i+offset)*channelCount + c],
					offsetReadData[i*channelCount + c]);
	}

	ASSERT_EQ(afCloseFile(file), 0);

	delete [] data;
	delete [] readData;
	delete [] offsetReadData;

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(IMA, CAF)
{
	for (int channelCount=1; channelCount<=2; channelCount++)
		testADPCM(AF_FILE_CAF, AF_COMPRESSION_IMA, channelCount,
			channelCount * kIMABytesPerPacketQT, kIMAFramesPerPacketQT,
			500 * kIMAFramesPerPacketQT, kIMAThresholdQT);
}

TEST(IMA, AIFFC)
{
	for (int channelCount=1; channelCount<=2; channelCount++)
		testADPCM(AF_FILE_AIFFC, AF_COMPRESSION_IMA, channelCount,
			channelCount * kIMABytesPerPacketQT, kIMAFramesPerPacketQT,
			500 * kIMAFramesPerPacketQT, kIMAThresholdQT);
}

TEST(IMA, WAVE)
{
	for (int channelCount=1; channelCount<=2; channelCount++)
		testADPCM(AF_FILE_WAVE, AF_COMPRESSION_IMA, channelCount,
			channelCount * kIMABytesPerPacketWAVE, kIMAFramesPerPacketWAVE,
			50 * kIMAFramesPerPacketWAVE, kIMAThresholdWAVE);
}

TEST(MSADPCM, WAVE)
{
	for (int channelCount=1; channelCount<=2; channelCount++)
		testADPCM(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, channelCount,
			channelCount * kMSADPCMBytesPerPacket, kMSADPCMFramesPerPacket,
			50 * kMSADPCMFramesPerPacket, kMSADPCMThreshold);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "TestUtilities.h"

static void testAESSupported(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("AES", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitAESChannelDataTo(setup, AF_DEFAULT_TRACK, true);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);

	afFreeFileSetup(setup);

	unsigned char aesData[24];
	for (int i=0; i<24; i++)
		aesData[i] = 3*i + 1;
	afSetAESChannelData(file, AF_DEFAULT_TRACK, aesData);

	afCloseFile(file);

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file);

	unsigned char readAESData[24];
	EXPECT_TRUE(afGetAESChannelData(file, AF_DEFAULT_TRACK, readAESData));
	EXPECT_TRUE(!memcmp(aesData, readAESData, 24));

	afCloseFile(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(AES_Supported, AIFFC) { testAESSupported(AF_FILE_AIFFC); }
TEST(AES_Supported, AIFF) { testAESSupported(AF_FILE_AIFF); }

static void testAESUnsupported(int fileFormat)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("AES", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitAESChannelDataTo(setup, AF_DEFAULT_TRACK, true);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);

	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(AES_Unsupported, Raw) { testAESUnsupported(AF_FILE_RAWDATA); }
TEST(AES_Unsupported, NeXT) { testAESUnsupported(AF_FILE_NEXTSND); }
TEST(AES_Unsupported, WAVE) { testAESUnsupported(AF_FILE_WAVE); }
TEST(AES_Unsupported, IRCAM) { testAESUnsupported(AF_FILE_IRCAM); }
TEST(AES_Unsupported, AVR) { testAESUnsupported(AF_FILE_AVR); }
TEST(AES_Unsupported, IFF) { testAESUnsupported(AF_FILE_IFF_8SVX); }
TEST(AES_Unsupported, SampleVision) { testAESUnsupported(AF_FILE_SAMPLEVISION); }
TEST(AES_Unsupported, VOC) { testAESUnsupported(AF_FILE_VOC); }
TEST(AES_Unsupported, NIST) { testAESUnsupported(AF_FILE_NIST_SPHERE); }
TEST(AES_Unsupported, CAF) { testAESUnsupported(AF_FILE_CAF); }
TEST(AES_Unsupported, FLAC) { testAESUnsupported(AF_FILE_FLAC); }

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>

#include <functional>
#include <stdint.h>
#include <unistd.h>

#include "Lossless.h"
#include "TestUtilities.h"

template <typename SampleType>
static void testALAC(int fileFormat, int channelCount, int sampleWidth, int frameCount)
{
	testLossless<SampleType>("ALAC", fileFormat, AF_COMPRESSION_ALAC,
		channelCount, sampleWidth, frameCount);
}

TEST(ALAC, ALAC_16)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testALAC<int16_t>(AF_FILE_CAF, channelCount, 16, 82421);
}

TEST(ALAC, ALAC_20)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testALAC<int32_t>(AF_FILE_CAF, channelCount, 20, 82421);
}

TEST(ALAC, ALAC_24)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testALAC<int32_t>(AF_FILE_CAF, channelCount, 24, 82421);
}

TEST(ALAC, ALAC_32)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testALAC<int32_t>(AF_FILE_CAF, channelCount, 32, 82421);
}

static void testInvalidSampleFormat(int sampleFormat, int sampleWidth)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("ALAC", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_CAF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_ALAC);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(ALAC, InvalidSampleWidths)
{
	IgnoreErrors ignoreErrors;

	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
	{
		if (sampleWidth == 16 ||
			sampleWidth == 20 ||
			sampleWidth == 24 ||
			sampleWidth == 32)
			continue;

		testInvalidSampleFormat(AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}
}

TEST(ALAC, InvalidSampleFormats)
{
	IgnoreErrors ignoreErrors;

	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
		testInvalidSampleFormat(AF_SAMPFMT_UNSIGNED, sampleWidth);

	testInvalidSampleFormat(AF_SAMPFMT_FLOAT, 32);
	testInvalidSampleFormat(AF_SAMPFMT_DOUBLE, 64);
}

TEST(ALAC, InvalidChannels)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("ALAC", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_CAF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 9);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_ALAC);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <string>

#include "TestUtilities.h"

template <typename T>
void testChannelMatrixReading(int sampleFormat, int sampleWidth)
{
	// Create test file.
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));

	const int channelCount = 2;
	const int frameCount = 10;
	const T samples[channelCount * frameCount] =
	{
		2, 3, 5, 7, 11,
		13, 17, 19, 23, 29,
		31, 37, 41, 43, 47,
		53, 59, 61, 67, 71
	};
	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFFC);
	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	afFreeFileSetup(setup);
	EXPECT_TRUE(file);

	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK,
		samples, frameCount);
	EXPECT_EQ(framesWritten, frameCount);

	EXPECT_EQ(afCloseFile(file), 0);

	// Open file for reading and read data using different channel matrices.
	file = afOpenFile(testFileName.c_str(), "r", NULL);
	EXPECT_TRUE(file);

	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 2);
	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);

	afSetVirtualChannels(file, AF_DEFAULT_TRACK, 1);

	for (int c=0; c<2; c++)
	{
		double channelMatrix[2] = { 0, 0 };
		channelMatrix[c] = 1;
		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);

		EXPECT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);

		T *readSamples = new T[frameCount]; 
		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
			readSamples, frameCount);
		EXPECT_EQ(framesRead, frameCount);

		for (int i=0; i<frameCount; i++)
			EXPECT_EQ(readSamples[i], samples[2*i + c]);

		delete [] readSamples;
	}

	EXPECT_EQ(afCloseFile(file), 0);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(ChannelMatrix, ReadInt8)
{
	testChannelMatrixReading<int8_t>(AF_SAMPFMT_TWOSCOMP, 8);
}

TEST(ChannelMatrix, ReadInt16)
{
	testChannelMatrixReading<int16_t>(AF_SAMPFMT_TWOSCOMP, 16);
}

TEST(ChannelMatrix, ReadInt24)
{
	testChannelMatrixReading<int32_t>(AF_SAMPFMT_TWOSCOMP, 24);
}

TEST(ChannelMatrix, ReadInt32)
{
	testChannelMatrixReading<int32_t>(AF_SAMPFMT_TWOSCOMP, 32);
}

TEST(ChannelMatrix, ReadFloat)
{
	testChannelMatrixReading<float>(AF_SAMPFMT_FLOAT, 32);
}

TEST(ChannelMatrix, ReadDouble)
{
	testChannelMatrixReading<double>(AF_SAMPFMT_DOUBLE, 64);
}

template <typename T>
void testChannelMatrixWriting(int sampleFormat, int sampleWidth)
{
	const int channelCount = 2;
	const int frameCount = 10;
	const T samples[channelCount * frameCount] =
	{
		2, 3, 5, 7, 11,
		13, 17, 19, 23, 29,
		31, 37, 41, 43, 47,
		53, 59, 61, 67, 71
	};

	for (int c=0; c<2; c++)
	{
		// Create test file.
		std::string testFileName;
		ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));

		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
		AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
		afFreeFileSetup(setup);
		EXPECT_TRUE(file);

		afSetVirtualChannels(file, AF_DEFAULT_TRACK, 2);

		double channelMatrix[2] = { 0, 0 };
		channelMatrix[c] = 1;
		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);

		AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK,
			samples, frameCount);
		EXPECT_EQ(framesWritten, frameCount);

		EXPECT_EQ(afCloseFile(file), 0);

		// Open file for reading.
		file = afOpenFile(testFileName.c_str(), "r", NULL);
		EXPECT_TRUE(file);

		EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
		EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount);

		T *readSamples = new T[frameCount]; 
		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK,
			readSamples, frameCount);
		EXPECT_EQ(framesRead, frameCount);

		for (int i=0; i<frameCount; i++)
			EXPECT_EQ(readSamples[i], samples[2*i + c]);

		delete [] readSamples;

		EXPECT_EQ(afCloseFile(file), 0);

		ASSERT_EQ(::unlink(testFileName.c_str()), 0);
	}
}

TEST(ChannelMatrix, WriteInt8)
{
	testChannelMatrixWriting<int8_t>(AF_SAMPFMT_TWOSCOMP, 8);
}

TEST(ChannelMatrix, WriteInt16)
{
	testChannelMatrixWriting<int16_t>(AF_SAMPFMT_TWOSCOMP, 16);
}

TEST(ChannelMatrix, WriteInt24)
{
	testChannelMatrixWriting<int32_t>(AF_SAMPFMT_TWOSCOMP, 24);
}

TEST(ChannelMatrix, WriteInt32)
{
	testChannelMatrixWriting<int32_t>(AF_SAMPFMT_TWOSCOMP, 32);
}

TEST(ChannelMatrix, WriteFloat)
{
	testChannelMatrixWriting<float>(AF_SAMPFMT_FLOAT, 32);
}

TEST(ChannelMatrix, WriteDouble)
{
	testChannelMatrixWriting<double>(AF_SAMPFMT_DOUBLE, 64);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <stdio.h>
#include <gtest/gtest.h>

struct ErrorListener *g_listener;

struct ErrorListener
{
	ErrorListener(long expectedError) :
		m_expectedError(expectedError),
		m_receivedError(-1),
		m_oldErrorFunction(0)
	{
		g_listener = this;
		m_oldErrorFunction = afSetErrorHandler(errorHandlerHelper);
	}
	~ErrorListener()
	{
		g_listener = 0;
		EXPECT_EQ(m_expectedError, m_receivedError);
		afSetErrorHandler(m_oldErrorFunction);
	}

	long m_expectedError;
	long m_receivedError;
	AFerrfunc m_oldErrorFunction;

	static void errorHandlerHelper(long error, const char *description)
	{
		g_listener->errorHandler(error, description);
	}
	void errorHandler(long error, const char *description)
	{
		m_receivedError = error;
		EXPECT_EQ(m_expectedError, m_receivedError);
	}
};

#define TEST_ERROR(ExpectedError, Message, TestBody) \
	{ \
		SCOPED_TRACE(Message); \
		ErrorListener el(ExpectedError); \
		TestBody; \
	}

TEST(Data, Null)
{
	TEST_ERROR(AF_BAD_FILEHANDLE, "closing null file handle",
		afCloseFile(AF_NULL_FILEHANDLE));

	TEST_ERROR(AF_BAD_FILEHANDLE, "reading from null file handle",
		afReadFrames(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, 0));

	TEST_ERROR(AF_BAD_FILEHANDLE, "writing to null file handle",
		afWriteFrames(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, 0));

	TEST_ERROR(AF_BAD_FILEHANDLE, "setting position on null file handle",
		afSeekFrame(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, 0));

	TEST_ERROR(AF_BAD_FILEHANDLE, "retrieving position on null file handle",
		afTellFrame(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
}

TEST(Channels, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "initializing channels of null file setup",
		afInitChannels(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 1));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting channels of null file handle",
		afGetChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting virtual channels of null file handle",
		afGetVirtualChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));

	TEST_ERROR(AF_BAD_FILEHANDLE, "setting virtual channels of null file handle",
		afSetVirtualChannels(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, 1));

	TEST_ERROR(AF_BAD_FILEHANDLE, "setting channel matrix of null file handle",
		afSetChannelMatrix(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));
}

TEST(Rate, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "initializing rate of null file setup",
		afInitRate(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 44100));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting rate of null file handle",
		afGetRate(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
}

TEST(Compression, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "initializing compression of null file setup",
		afInitCompression(AF_NULL_FILESETUP, AF_DEFAULT_TRACK,
			AF_COMPRESSION_NONE));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting compression of null file handle",
		afGetCompression(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
}

TEST(SampleFormat, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP,
		"initializing sample format of null file setup",
		afInitSampleFormat(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"getting sample format of null file handle",
		afGetSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, NULL));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"getting virtual sample format of null file handle",
		afGetVirtualSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL, NULL));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"setting virtual sample format of null file handle",
		afSetVirtualSampleFormat(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16));
}

TEST(ByteOrder, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP,
		"initializing byte order of null file setup",
		afInitByteOrder(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"getting byte order of null file handle",
		afGetByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"getting virtual byte order of null file handle",
		afGetVirtualByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"setting virtual byte order of null file handle",
		afSetVirtualByteOrder(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN));
}

TEST(DataOffset, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "initializing data offset of null file setup",
		afInitDataOffset(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 0));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting data offset of null file handle",
		afGetDataOffset(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
}

TEST(FrameCount, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "initializing frame count of null file setup",
		afInitFrameCount(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 0));

	TEST_ERROR(AF_BAD_FILEHANDLE, "getting frame count of null file handle",
		afGetFrameCount(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK));
}

TEST(AES, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP,
		"initializing AES channel data of null file setup",
		afInitAESChannelData(AF_NULL_FILESETUP, AF_DEFAULT_TRACK));

	TEST_ERROR(AF_BAD_FILESETUP,
		"initializing AES channel data of null file setup",
		afInitAESChannelDataTo(AF_NULL_FILESETUP, AF_DEFAULT_TRACK, 1));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"getting AES channel data of null file handle",
		afGetAESChannelData(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));

	TEST_ERROR(AF_BAD_FILEHANDLE,
		"setting AES channel data of null file handle",
		afSetAESChannelData(AF_NULL_FILEHANDLE, AF_DEFAULT_TRACK, NULL));
}

TEST(Setup, Null)
{
	TEST_ERROR(AF_BAD_FILESETUP, "freeing null file setup",
		afFreeFileSetup(AF_NULL_FILESETUP));
}

TEST(File, Bad)
{
	TEST_ERROR(AF_BAD_OPEN, "opening nonexistent file for reading",
		afOpenFile("sldkjflsdkfjalksdjflaksdjflsakfdj", "r", NULL));

	TEST_ERROR(AF_BAD_ACCMODE, "opening file with null access mode",
		afOpenFile("", NULL, NULL));

	TEST_ERROR(AF_BAD_ACCMODE, "opening file with invalid access mode",
		afOpenFile("", "x", NULL));

	TEST_ERROR(AF_BAD_FILEFMT, "initializing file format to invalid value",
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, 91094);
		afFreeFileSetup(setup));

	TEST_ERROR(AF_BAD_SAMPFMT,
		"initializing sample format and sample width to invalid values",
		AFfilesetup setup = afNewFileSetup();
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, 3992, 3932);
		afFreeFileSetup(setup));
}

TEST(Query, Bad)
{
	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
		afQueryLong(AF_QUERYTYPE_INST, 9999, 9999, 9999, 9999));

	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
		afQueryLong(AF_QUERYTYPE_INSTPARAM, 9999, 9999, 9999, 9999));

	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
		afQueryLong(AF_QUERYTYPE_FILEFMT, 9999, 9999, 9999, 9999));

	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
		afQueryLong(AF_QUERYTYPE_COMPRESSION, 9999, 9999, 9999, 9999));

	TEST_ERROR(AF_BAD_QUERY, "querying on bad selectors",
		afQueryLong(AF_QUERYTYPE_MARK, 9999, 9999, 9999, 9999));

	TEST_ERROR(AF_BAD_QUERYTYPE, "querying using bad query type",
		afQueryLong(9999, 9999, 9999, 9999, 9999));
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <unistd.h>

#include "Lossless.h"
#include "TestUtilities.h"

template <typename SampleType>
static void testFLAC(int channelCount, int sampleWidth, int frameCount)
{
	testLossless<SampleType>("FLAC", AF_FILE_FLAC, AF_COMPRESSION_FLAC,
		channelCount, sampleWidth, frameCount);
}

TEST(FLAC, FLAC_16)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testFLAC<int16_t>(channelCount, 16, 82421);
}

TEST(FLAC, FLAC_24)
{
	for (int channelCount=1; channelCount<=8; channelCount++)
		testFLAC<int32_t>(channelCount, 24, 82421);
}

static void testInvalidSampleFormat(int sampleFormat, int sampleWidth)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("FLAC", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_FLAC);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_FLAC);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(FLAC, InvalidSampleWidths)
{
	IgnoreErrors ignoreErrors;

	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
	{
		if (sampleWidth == 16 || sampleWidth == 24)
			continue;

		testInvalidSampleFormat(AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}
}

TEST(FLAC, InvalidSampleFormats)
{
	IgnoreErrors ignoreErrors;

	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
		testInvalidSampleFormat(AF_SAMPFMT_UNSIGNED, sampleWidth);

	testInvalidSampleFormat(AF_SAMPFMT_FLOAT, 32);
	testInvalidSampleFormat(AF_SAMPFMT_DOUBLE, 64);
}

TEST(FLAC, InvalidChannels)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("FLAC", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_FLAC);
	afInitChannels(setup, AF_DEFAULT_TRACK, 9);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_FLAC);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <limits>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>

#include "TestUtilities.h"

class FloatToIntTest : public testing::Test
{
protected:
	virtual void SetUp()
	{
		ASSERT_TRUE(createTemporaryFile("FloatToInt", &m_testFileName));
	}
	virtual void TearDown()
	{
		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
	}

	AFfilehandle createTestFile(int sampleWidth)
	{
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
		afFreeFileSetup(setup);
		return file;
	}
	AFfilehandle openTestFile(int sampleWidth)
	{
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		return file;
	}

private:
	std::string m_testFileName;
};

static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();

TEST_F(FloatToIntTest, Int8)
{
	AFfilehandle file = createTestFile(8);
	const float data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(8);
	ASSERT_TRUE(file != NULL);
	int8_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const int8_t expectedData[] = { kMinInt8, 0, kMaxInt8 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();

TEST_F(FloatToIntTest, Int16)
{
	AFfilehandle file = createTestFile(16);
	const float data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(16);
	ASSERT_TRUE(file != NULL);
	int16_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const int16_t expectedData[] = { kMinInt16, 0, kMaxInt16 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt24 = -1<<23;
static const int32_t kMaxInt24 = (1<<23) - 1;

TEST_F(FloatToIntTest, Int24)
{
	AFfilehandle file = createTestFile(24);
	const float data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(24);
	ASSERT_TRUE(file != NULL);
	int32_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const int32_t expectedData[] = { kMinInt24, 0, kMaxInt24 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();

TEST_F(FloatToIntTest, Int32)
{
	AFfilehandle file = createTestFile(32);
	const float data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(32);
	ASSERT_TRUE(file != NULL);
	int32_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const int32_t expectedData[] = { kMinInt32, 0, kMaxInt32 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2016, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	Validate conversion when changing both sample format and channel count.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <algorithm>
#include <climits>
#include <limits>

#include "TestUtilities.h"

class FormatWithChannels : public testing::Test
{
protected:
	virtual void SetUp()
	{
		ASSERT_TRUE(createTemporaryFile("FormatWithChannels", &m_testFileName));
	}
	virtual void TearDown()
	{
		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
	}

	AFfilehandle createTestFile(int sampleWidth, int channelCount)
	{
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
		afFreeFileSetup(setup);
		return file;
	}
	AFfilehandle openTestFile(int sampleWidth, int channelCount)
	{
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		afSetVirtualChannels(file, AF_DEFAULT_TRACK, channelCount);
		int fileChannels = afGetChannels(file, AF_DEFAULT_TRACK);

		double channelMatrix[fileChannels * channelCount];
		for (int i = 0; i < fileChannels; i++)
			for (int j = 0; j < channelCount; j++)
				channelMatrix[j * fileChannels + i] = (i == j) ? 1 : 0;
		afSetChannelMatrix(file, AF_DEFAULT_TRACK, channelMatrix);
		return file;
	}

private:
	std::string m_testFileName;
};

const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();

TEST_F(FormatWithChannels, Int16ToInt8)
{
	for (int fileChannels = 1; fileChannels <= 4; fileChannels++)
	{
		AFfilehandle file = createTestFile(16, fileChannels);
		const int frameCount = 3;
		int16_t data[frameCount * fileChannels];
		std::fill(data, data + frameCount * fileChannels, 0);
		data[0] = kMinInt16;
		data[2 * fileChannels] = kMaxInt16;

		AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
		ASSERT_EQ(framesWritten, frameCount);
		afCloseFile(file);

		file = openTestFile(8, 1);
		ASSERT_TRUE(file != NULL);
		int8_t readData[frameCount];
		AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
		ASSERT_EQ(framesRead, frameCount);
		afCloseFile(file);
		EXPECT_EQ(readData[0], kMinInt8);
		EXPECT_EQ(readData[1], 0);
		EXPECT_EQ(readData[2], kMaxInt8);
	}
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2014, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>

#include "TestUtilities.h"

const uint8_t kNeXTData[] =
{
	'.', 's', 'n', 'd',
	0, 0, 0, 24, // offset of 24 bytes
	0, 0, 0, 2, // unspecified length
	0, 0, 0, 3, // 16-bit linear
	0, 0, 172, 68, // 44100 Hz
	0, 0, 0, 1, // 1 channel
	0, 0
};

TEST(Identify, NeXT)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Identify", &testFileName));
	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
	ASSERT_GT(fd, -1);
	ASSERT_EQ(::write(fd, kNeXTData, sizeof (kNeXTData)), sizeof (kNeXTData));

	EXPECT_TRUE(AF_FILE_NEXTSND == afIdentifyFD(fd));

	int implemented = -1;
	EXPECT_TRUE(AF_FILE_NEXTSND == afIdentifyNamedFD(fd, testFileName.c_str(), &implemented));
	EXPECT_EQ(implemented, 1);

	ASSERT_EQ(::close(fd), 0);
	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(Identify, Empty)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Identify", &testFileName));
	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
	ASSERT_GT(fd, -1);

	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyFD(fd));

	int implemented = -1;
	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyNamedFD(fd, testFileName.c_str(), &implemented));
	EXPECT_EQ(implemented, 0);

	ASSERT_EQ(::close(fd), 0);
	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(Identify, NonSeekable)
{
	int pipefd[2];
	ASSERT_GE(::pipe(pipefd), 0);

	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyFD(pipefd[0]));
	EXPECT_TRUE(AF_FILE_UNKNOWN == afIdentifyNamedFD(pipefd[0], "", NULL));

	ASSERT_EQ(::close(pipefd[0]), 0);
	ASSERT_EQ(::close(pipefd[1]), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <stdlib.h>

#include "TestUtilities.h"

static void testInstrumentParameters(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Instrument", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	int instrumentIDs[] = {AF_DEFAULT_INST};
	int numInstruments = sizeof (instrumentIDs) / sizeof (int);
	afInitInstIDs(setup, instrumentIDs, numInstruments);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);

	afFreeFileSetup(setup);

	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE, 50);
	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE, -30);
	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY, 22);
	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY, 111);

	ASSERT_EQ(0, afCloseFile(file));

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file);
	ASSERT_EQ(fileFormat, afGetFileFormat(file, NULL));

	ASSERT_EQ(1, afGetInstIDs(file, NULL));
	int readInstrumentIDs[1] = {0};
	ASSERT_EQ(1, afGetInstIDs(file, readInstrumentIDs));
	ASSERT_TRUE(AF_DEFAULT_INST == readInstrumentIDs[0]);

	EXPECT_EQ(50,
		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE));
	EXPECT_EQ(-30,
		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE));
	EXPECT_EQ(22,
		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY));
	EXPECT_EQ(111,
		afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY));

	ASSERT_EQ(0, afCloseFile(file));
	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
}

TEST(Instrument, AIFF) { testInstrumentParameters(AF_FILE_AIFF); }
TEST(Instrument, AIFFC) { testInstrumentParameters(AF_FILE_AIFFC); }

static void testInstrumentUnsupported(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Instrument", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	int instrumentIDs[] = {AF_DEFAULT_INST};
	int numInstruments = sizeof (instrumentIDs) / sizeof (int);
	afInitInstIDs(setup, instrumentIDs, numInstruments);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);

	afFreeFileSetup(setup);

	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
}

TEST(Instrument, Raw) { testInstrumentUnsupported(AF_FILE_RAWDATA); }
TEST(Instrument, NeXT) { testInstrumentUnsupported(AF_FILE_NEXTSND); }
TEST(Instrument, IRCAM) { testInstrumentUnsupported(AF_FILE_IRCAM); }
TEST(Instrument, AVR) { testInstrumentUnsupported(AF_FILE_AVR); }
TEST(Instrument, IFF_8SVX) { testInstrumentUnsupported(AF_FILE_IFF_8SVX); }
TEST(Instrument, SampleVision) { testInstrumentUnsupported(AF_FILE_SAMPLEVISION); }
TEST(Instrument, VOC) { testInstrumentUnsupported(AF_FILE_VOC); }
TEST(Instrument, NIST) { testInstrumentUnsupported(AF_FILE_NIST_SPHERE); }
TEST(Instrument, CAF) { testInstrumentUnsupported(AF_FILE_CAF); }
TEST(Instrument, FLAC) { testInstrumentUnsupported(AF_FILE_FLAC); }

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits>
#include <string>

#include "TestUtilities.h"

class IntToFloatTest : public testing::Test
{
protected:
	virtual void SetUp()
	{
		ASSERT_TRUE(createTemporaryFile("IntToFloat", &m_testFileName));
	}
	virtual void TearDown()
	{
		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
	}

	static char kTestFileName[];

	AFfilehandle createTestFile(int sampleWidth)
	{
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
		afFreeFileSetup(setup);
		return file;
	}
	AFfilehandle openTestFile()
	{
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
		return file;
	}

private:
	std::string m_testFileName;
};

static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();

TEST_F(IntToFloatTest, Int8)
{
	AFfilehandle file = createTestFile(8);
	const int8_t data[] = { kMinInt8, 0, kMaxInt8 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	float readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<7) };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();

TEST_F(IntToFloatTest, Int16)
{
	AFfilehandle file = createTestFile(16);
	const int16_t data[] = { kMinInt16, 0, kMaxInt16 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	float readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<15) };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt24 = -1<<23;
static const int32_t kMaxInt24 = (1<<23) - 1;

TEST_F(IntToFloatTest, Int24)
{
	AFfilehandle file = createTestFile(24);
	const int32_t data[] = { kMinInt24, 0, kMaxInt24 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	float readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<23) };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();

TEST_F(IntToFloatTest, Int32)
{
	AFfilehandle file = createTestFile(32);
	const int32_t data[] = { kMinInt32, 0, kMaxInt32 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	float readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const float expectedData[] = { -1, 0, 1 - 1.0 / (1<<31) };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2012-2013, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "config.h"

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

static const int kNativeByteOrder =
#ifdef WORDS_BIGENDIAN
	AF_BYTEORDER_BIGENDIAN;
#else
	AF_BYTEORDER_LITTLEENDIAN;
#endif

static const int kNonNativeByteOrder =
#if WORDS_BIGENDIAN
	AF_BYTEORDER_LITTLEENDIAN;
#else
	AF_BYTEORDER_BIGENDIAN;
#endif

static void runTest(int fileFormat, int compressionFormat, int channelCount = 1,
	int sampleFormat = AF_SAMPFMT_TWOSCOMP, int sampleWidth = 16,
	int byteOrder = kNativeByteOrder)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("InvalidCompressionFormat", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
	afInitByteOrder(setup, AF_DEFAULT_TRACK, byteOrder);
	ASSERT_TRUE(afOpenFile(testFileName.c_str(), "w", setup) == AF_NULL_FILEHANDLE);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(AIFF, mulaw) { runTest(AF_FILE_AIFF, AF_COMPRESSION_G711_ULAW); }
TEST(AIFF, Alaw) { runTest(AF_FILE_AIFF, AF_COMPRESSION_G711_ALAW); }
TEST(AIFF, IMA) { runTest(AF_FILE_AIFF, AF_COMPRESSION_IMA); }
TEST(AIFF, MSADPCM) { runTest(AF_FILE_AIFF, AF_COMPRESSION_MS_ADPCM); }

TEST(AIFFC, MSADPCM) { runTest(AF_FILE_AIFFC, AF_COMPRESSION_MS_ADPCM); }

TEST(NeXT, IMA) { runTest(AF_FILE_NEXTSND, AF_COMPRESSION_IMA); }
TEST(NeXT, MSADPCM) { runTest(AF_FILE_NEXTSND, AF_COMPRESSION_MS_ADPCM); }

TEST(IRCAM, IMA) { runTest(AF_FILE_BICSF, AF_COMPRESSION_IMA); }
TEST(IRCAM, MSADPCM) { runTest(AF_FILE_BICSF, AF_COMPRESSION_MS_ADPCM); }

TEST(AVR, mulaw) { runTest(AF_FILE_AVR, AF_COMPRESSION_G711_ULAW); }
TEST(AVR, Alaw) { runTest(AF_FILE_AVR, AF_COMPRESSION_G711_ALAW); }
TEST(AVR, IMA) { runTest(AF_FILE_AVR, AF_COMPRESSION_IMA); }
TEST(AVR, MSADPCM) { runTest(AF_FILE_AVR, AF_COMPRESSION_MS_ADPCM); }

TEST(IFF, mulaw) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_G711_ULAW); }
TEST(IFF, Alaw) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_G711_ALAW); }
TEST(IFF, IMA) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_IMA); }
TEST(IFF, MSADPCM) { runTest(AF_FILE_IFF_8SVX, AF_COMPRESSION_MS_ADPCM); }

TEST(SampleVision, mulaw) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_G711_ULAW); }
TEST(SampleVision, Alaw) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_G711_ALAW); }
TEST(SampleVision, IMA) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_IMA); }
TEST(SampleVision, MSADPCM) { runTest(AF_FILE_SAMPLEVISION, AF_COMPRESSION_MS_ADPCM); }

TEST(VOC, IMA) { runTest(AF_FILE_VOC, AF_COMPRESSION_IMA); }
TEST(VOC, MSADPCM) { runTest(AF_FILE_VOC, AF_COMPRESSION_MS_ADPCM); }

TEST(NIST, IMA) { runTest(AF_FILE_NIST_SPHERE, AF_COMPRESSION_IMA); }
TEST(NIST, MSADPCM) { runTest(AF_FILE_NIST_SPHERE, AF_COMPRESSION_MS_ADPCM); }

TEST(CAF, MSADPCM) { runTest(AF_FILE_CAF, AF_COMPRESSION_MS_ADPCM); }

/*
	Test that opening an audio file with an invalid number of channels
	results in failure.
*/

TEST(AIFFC, IMA) { runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 3); }

TEST(WAVE, IMA) { runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 3); }
TEST(WAVE, MSADPCM) { runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 3); }

TEST(CAF, IMA) { runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 3); }

/*
	Test that opening an audio file with an invalid sample format results
	in failure.
*/

TEST(Mulaw, Signed)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
	{
		if (sampleWidth==16)
			continue;
		runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}
}

TEST(Mulaw, Unsigned)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
		runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
}

TEST(Mulaw, Float)
{
	runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_FLOAT, 32);
}

TEST(Mulaw, Double)
{
	runTest(AF_FILE_AIFFC, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_DOUBLE, 64);
}

TEST(IMA, Signed)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
	{
		if (sampleWidth==16)
			continue;
		runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
	}
}

TEST(IMA, Unsigned)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
	{
		runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
		runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
		runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
	}
}

TEST(IMA, Float)
{
	runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
	runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_FLOAT, 32);
}

TEST(IMA, Double)
{
	runTest(AF_FILE_AIFFC, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
	runTest(AF_FILE_CAF, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_DOUBLE, 64);
}

TEST(MSADPCM, Signed)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
		if (sampleWidth!=16)
			runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_TWOSCOMP, sampleWidth);
}

TEST(MSADPCM, Unsigned)
{
	for (int sampleWidth=1; sampleWidth<=32; sampleWidth++)
		runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_UNSIGNED, sampleWidth);
}

TEST(MSADPCM, Float)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_FLOAT, 32);
}

TEST(MSADPCM, Double)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_DOUBLE, 64);
}

TEST(Mulaw, InvalidByteOrder)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_G711_ULAW, 1, AF_SAMPFMT_TWOSCOMP, 16,
		kNonNativeByteOrder);
}

TEST(Alaw, InvalidByteOrder)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_G711_ALAW, 1, AF_SAMPFMT_TWOSCOMP, 16,
		kNonNativeByteOrder);
}

TEST(IMA, InvalidByteOrder)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_IMA, 1, AF_SAMPFMT_TWOSCOMP, 16,
		kNonNativeByteOrder);
}

TEST(MSADPCM, InvalidByteOrder)
{
	runTest(AF_FILE_WAVE, AF_COMPRESSION_MS_ADPCM, 1, AF_SAMPFMT_TWOSCOMP, 16,
		kNonNativeByteOrder);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2012, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

void runTest(int fileFormat, int sampleFormat, int sampleWidth)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("InvalidSampleFormat", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	ASSERT_TRUE(afOpenFile(testFileName.c_str(), "w", setup) == AF_NULL_FILEHANDLE);
	afFreeFileSetup(setup);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

void testInt8(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 8);
}

void testUInt8(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 8);
}

void testInt16(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 16);
}

void testUInt16(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 16);
}

void testInt24(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 24);
}

void testUInt24(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 24);
}

void testInt32(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_TWOSCOMP, 32);
}

void testUInt32(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_UNSIGNED, 32);
}

void testFloat32(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_FLOAT, 32);
}

void testFloat64(int fileFormat)
{
	runTest(fileFormat, AF_SAMPFMT_DOUBLE, 64);
}

TEST(AIFF, Float) { testFloat32(AF_FILE_AIFF); }
TEST(AIFF, Double) { testFloat64(AF_FILE_AIFF); }

TEST(IFF, Int16) { testInt16(AF_FILE_IFF_8SVX); }
TEST(IFF, Int24) { testInt24(AF_FILE_IFF_8SVX); }
TEST(IFF, Int32) { testInt32(AF_FILE_IFF_8SVX); }
TEST(IFF, Float) { testFloat32(AF_FILE_IFF_8SVX); }
TEST(IFF, Double) { testFloat64(AF_FILE_IFF_8SVX); }

TEST(AVR, Int24) { testInt24(AF_FILE_AVR); }
TEST(AVR, Int32) { testInt32(AF_FILE_AVR); }
TEST(AVR, Float) { testFloat32(AF_FILE_AVR); }
TEST(AVR, Double) { testFloat64(AF_FILE_AVR); }

TEST(SampleVision, Int8) { testInt8(AF_FILE_SAMPLEVISION); }
TEST(SampleVision, Int24) { testInt24(AF_FILE_SAMPLEVISION); }
TEST(SampleVision, Int32) { testInt32(AF_FILE_SAMPLEVISION); }
TEST(SampleVision, Float) { testFloat32(AF_FILE_SAMPLEVISION); }
TEST(SampleVision, Double) { testFloat64(AF_FILE_SAMPLEVISION); }

TEST(VOC, Int24) { testInt24(AF_FILE_VOC); }
TEST(VOC, Int32) { testInt32(AF_FILE_VOC); }
TEST(VOC, Float) { testFloat32(AF_FILE_VOC); }
TEST(VOC, Double) { testFloat64(AF_FILE_VOC); }

TEST(NIST, Int24) { testInt24(AF_FILE_NIST_SPHERE); }
TEST(NIST, Int32) { testInt32(AF_FILE_NIST_SPHERE); }
TEST(NIST, Float) { testFloat32(AF_FILE_NIST_SPHERE); }
TEST(NIST, Double) { testFloat64(AF_FILE_NIST_SPHERE); }

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2010-2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	This program tests writing and reading audio files with more
	than 2^24 frames.

	This program serves as a regression test for a bug in which
	writing certain audio file formats with more than 2^24 frames
	would produce files with incorrect sizes.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>

#include "TestUtilities.h"

void testLargeFile(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("ChannelMatrix", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	afFreeFileSetup(setup);
	ASSERT_TRUE(file) << "Could not open file for writing";

	const int bufferFrameCount = 32768;
	int16_t *data = new int16_t[bufferFrameCount];
	const AFframecount frameCount = 0x1000007;
	AFframecount framesWritten = 0;
	while (framesWritten < frameCount)
	{
		AFframecount framesToWrite = bufferFrameCount;
		if (framesToWrite > frameCount - framesWritten)
			framesToWrite = frameCount - framesWritten;
		int dataValue = framesWritten % 32749;
		for (int i=0; i<bufferFrameCount; i++, dataValue++)
			data[i] = dataValue % 32749;
		ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, data, framesToWrite),
			framesToWrite);
		framesWritten += framesToWrite;
	}
	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount) <<
		"Incorrect frame count for file";
	afCloseFile(file);

	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
	ASSERT_TRUE(file) << "Could not open file for reading";
	ASSERT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), frameCount) <<
		"Incorrect frame count for file opened for reading";
	ASSERT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
		frameCount * sizeof (int16_t)) <<
		"Incorrect byte size in file opened for reading";

	AFframecount framesRead = 0;
	while (framesRead < frameCount)
	{
		AFframecount framesToRead = bufferFrameCount;
		if (framesToRead > frameCount - framesRead)
			framesToRead = frameCount - framesRead;
		afReadFrames(file, AF_DEFAULT_TRACK, data, framesToRead);
		bool valid = true;
		int dataValue = framesRead % 32749;
		for (int i=0; i<framesToRead; i++, dataValue++)
			if (data[i] != dataValue % 32749)
			{
				valid = false;
				break;
			}
		ASSERT_TRUE(valid) << "Data read does not match data written";
		framesRead += framesToRead;
	}
	delete [] data;
	afCloseFile(file);
	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(Large, AIFF)
{
	testLargeFile(AF_FILE_AIFF);
}

TEST(Large, AIFFC)
{
	testLargeFile(AF_FILE_AIFFC);
}

TEST(Large, NeXT)
{
	testLargeFile(AF_FILE_NEXTSND);
}

TEST(Large, WAVE)
{
	testLargeFile(AF_FILE_WAVE);
}

TEST(Large, IRCAM)
{
	testLargeFile(AF_FILE_IRCAM);
}

TEST(Large, AVR)
{
	testLargeFile(AF_FILE_AVR);
}

TEST(Large, CAF)
{
	testLargeFile(AF_FILE_CAF);
}

int main (int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	Test that loops can be written to and read from an audio file.
*/

#include <audiofile.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>

#include "TestUtilities.h"

TEST(Loop, AIFF)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Loop", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	int markerIDs[] = { 1, 2, 3, 4 };
	const int numMarkers = sizeof (markerIDs) / sizeof (int);
	const char * const markerNames[numMarkers] =
	{
		"sustain loop start",
		"sustain loop end",
		"release loop start",
		"release loop end"
	};
	const int markerPositions[] = { 0, 2, 4, 5 };
	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, 4);
	for (int i=0; i<numMarkers; i++)
		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);

	int loopIDs[] = {1, 2};
	afInitLoopIDs(setup, AF_DEFAULT_INST, loopIDs, 2);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file) << "Could not open test file for writing";
	afFreeFileSetup(setup);

	const int frameCount = 5;
	int16_t frames[frameCount] = {0};

	EXPECT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, frames, frameCount),
		frameCount);

	for (int i=0; i<numMarkers; i++)
		afSetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i], markerPositions[i]);

	afSetLoopStart(file, AF_DEFAULT_INST, 1, 1);
	afSetLoopEnd(file, AF_DEFAULT_INST, 1, 2);
	afSetLoopStart(file, AF_DEFAULT_INST, 2, 3);
	afSetLoopEnd(file, AF_DEFAULT_INST, 2, 4);

	afCloseFile(file);

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file) << "Could not open test file for reading";

	ASSERT_EQ(afGetLoopIDs(file, AF_DEFAULT_INST, NULL), 2);
	int readLoopIDs[2];
	afGetLoopIDs(file, AF_DEFAULT_INST, readLoopIDs);
	for (int i=0; i<2; i++)
		ASSERT_EQ(loopIDs[i], readLoopIDs[i]);

	ASSERT_EQ(afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL), numMarkers);
	int readMarkerIDs[numMarkers];
	afGetMarkIDs(file, AF_DEFAULT_TRACK, readMarkerIDs);
	for (int i=0; i<numMarkers; i++)
		ASSERT_EQ(markerIDs[i], readMarkerIDs[i]);
	
	for (int i=0; i<numMarkers; i++)
		ASSERT_TRUE(!strcmp(afGetMarkName(file, AF_DEFAULT_TRACK, markerIDs[i]),
			markerNames[i]));

	for (int i=0; i<numMarkers; i++)
		ASSERT_EQ(afGetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i]),
			markerPositions[i]);

	ASSERT_EQ(afGetLoopStart(file, AF_DEFAULT_INST, 1), 1);
	ASSERT_EQ(afGetLoopEnd(file, AF_DEFAULT_INST, 1), 2);
	ASSERT_EQ(afGetLoopStart(file, AF_DEFAULT_INST, 2), 3);
	ASSERT_EQ(afGetLoopEnd(file, AF_DEFAULT_INST, 2), 4);

	ASSERT_TRUE(afGetLoopTrack(file, AF_DEFAULT_INST, 1) == AF_DEFAULT_TRACK);
	ASSERT_TRUE(afGetLoopTrack(file, AF_DEFAULT_INST, 2) == AF_DEFAULT_TRACK);

	ASSERT_EQ(afGetLoopStartFrame(file, AF_DEFAULT_INST, 1),
		markerPositions[0]);
	ASSERT_EQ(afGetLoopEndFrame(file, AF_DEFAULT_INST, 1),
		markerPositions[1]);
	ASSERT_EQ(afGetLoopStartFrame(file, AF_DEFAULT_INST, 2),
		markerPositions[2]);
	ASSERT_EQ(afGetLoopEndFrame(file, AF_DEFAULT_INST, 2),
		markerPositions[3]);

	afCloseFile(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2013 Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef Lossless_h
#define Lossless_h

#include <audiofile.h>
#include <gtest/gtest.h>

#include <stdint.h>
#include <unistd.h>

#include "TestUtilities.h"

struct NaturalGenerator
{
	NaturalGenerator() : m_n(0)
	{
	}
	int32_t operator() () { return ++m_n; }

private:
	int32_t m_n;
};

struct LinearCongruentialGenerator
{
	LinearCongruentialGenerator() : m_n(0)
	{
	}
	int32_t operator() ()
	{
		m_n = 1664525 * m_n + 1013904223;
		return static_cast<int32_t>(m_n);
	}

private:
	uint32_t m_n;
};

static inline int32_t trim(int32_t n, int sampleWidth)
{
	unsigned shift = (((sampleWidth + 7) >> 3) << 3) - sampleWidth;
	unsigned maskShift = 32 - sampleWidth;
	n <<= shift;
	return (n << maskShift) >> maskShift;
}

template <typename SampleType, typename Generator>
static void testLossless(const char *prefix, int fileFormat,
	int compressionFormat, int channelCount, int sampleWidth, int frameCount)
{
	SCOPED_TRACE(channelCount);
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile(prefix, &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
	afInitCompression(setup, AF_DEFAULT_TRACK, compressionFormat);
	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);
	afFreeFileSetup(setup);

	Generator g;
	SampleType *data = new SampleType[frameCount * channelCount];
	for (int i=0; i<frameCount; i++)
		for (int c=0; c<channelCount; c++)
			data[i*channelCount + c] = trim(g(), sampleWidth) * ((c&1) ? -1 : 1);

	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(frameCount, framesWritten);

	ASSERT_EQ(afCloseFile(file), 0);

	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
	ASSERT_TRUE(file);
	ASSERT_EQ(compressionFormat, afGetCompression(file, AF_DEFAULT_TRACK));
	int readSampleFormat, readSampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &readSampleFormat, &readSampleWidth);
	ASSERT_TRUE(AF_SAMPFMT_TWOSCOMP == readSampleFormat);
	ASSERT_EQ(sampleWidth, readSampleWidth);
	ASSERT_EQ(frameCount, afGetFrameCount(file, AF_DEFAULT_TRACK));

	SampleType *readData = new SampleType[frameCount * channelCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(frameCount, framesRead);

	for (int i=0; i<frameCount; i++)
		for (int c=0; c<channelCount; c++)
			EXPECT_EQ(data[i*channelCount + c], readData[i*channelCount + c]) <<
				"failed at " << i;

	// Read entire file with a seek before each read operation.
	for (AFframecount offset = 0; offset < frameCount; offset += 373)
	{
		ASSERT_EQ(offset, afSeekFrame(file, AF_DEFAULT_TRACK, offset));

		AFframecount framesToRead = 1091;
		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, framesToRead);
		ASSERT_EQ(std::min(framesToRead, frameCount - offset), framesRead);

		for (int i=0; i<framesRead; i++)
			for (int c=0; c<channelCount; c++)
				EXPECT_EQ(data[(i+offset)*channelCount + c],
					readData[i*channelCount + c]) << "failed at " << i;
	}

	// Read entire file sequentially in multiple read operations.
	ASSERT_EQ(afSeekFrame(file, AF_DEFAULT_TRACK, 0), 0);

	AFframecount framesToRead = 1087;
	for (AFframecount offset = 0; offset < frameCount; offset += framesToRead)
	{
		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, framesToRead);
		ASSERT_EQ(std::min(framesToRead, frameCount - offset), framesRead);

		for (int i=0; i<framesRead; i++)
			for (int c=0; c<channelCount; c++)
				EXPECT_EQ(data[(i+offset)*channelCount + c],
					readData[i*channelCount + c]) << "failed at " << i;
	}

	ASSERT_EQ(0, afCloseFile(file));

	delete [] data;
	delete [] readData;

	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
}

template <typename SampleType>
static void testLossless(const char *prefix, int fileFormat,
	int compressionFormat, int channelCount, int sampleWidth, int frameCount)
{
	{
		SCOPED_TRACE("Sequential");
		testLossless<SampleType, NaturalGenerator>(prefix, fileFormat, compressionFormat, channelCount, sampleWidth, frameCount);
	}
	{
		SCOPED_TRACE("Pseudo-random");
		testLossless<SampleType, LinearCongruentialGenerator>(prefix, fileFormat, compressionFormat, channelCount, sampleWidth, frameCount);
	}
}

#endif
AM_CPPFLAGS = -I$(top_srcdir)/libaudiofile -I$(top_srcdir)

TESTS = \
	ADPCM \
	AES \
	ALAC \
	ChannelMatrix \
	Error \
	FloatToInt \
	FormatWithChannels \
	Identify \
	Instrument \
	IntToFloat \
	InvalidCompressionFormat \
	InvalidSampleFormat \
	Large \
	Loop \
	Marker \
	Miscellaneous \
	NeXT \
	PCMData \
	PCMMapping \
	Pipe \
	Query \
	SampleFormat \
	Seek \
	Sign \
	VirtualFile \
	floatto24 \
	query2 \
	sixteen-to-eight \
	testchannelmatrix \
	testdouble \
	testfloat \
	testmarkers \
	twentyfour \
	twentyfour2 \
	writealaw \
	writeraw \
	writeulaw

if ENABLE_FLAC
TESTS += FLAC
endif

check_PROGRAMS = \
	$(TESTS) \
	instparamtest \
	instparamwrite \
	printmarkers \
	testaupv

if ENABLE_VALGRIND
VALGRIND_FLAGS = --quiet --leak-check=full --show-reachable=yes --error-exitcode=1
TESTS_ENVIRONMENT = $(top_builddir)/libtool --mode=execute $(VALGRIND) $(VALGRIND_FLAGS)
endif

LIBAUDIOFILE = $(top_builddir)/libaudiofile/libaudiofile.la

LDADD = $(LIBAUDIOFILE)

DEPENDENCIES = $(LIBAUDIOFILE)

LIBGTEST = ../gtest/libgtest.la

ADPCM_SOURCES = ADPCM.cpp TestUtilities.cpp TestUtilities.h
ADPCM_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

AES_SOURCES = AES.cpp TestUtilities.cpp TestUtilities.h
AES_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

ALAC_SOURCES = ALAC.cpp Lossless.h TestUtilities.cpp TestUtilities.h
ALAC_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

ChannelMatrix_SOURCES = ChannelMatrix.cpp TestUtilities.cpp TestUtilities.h
ChannelMatrix_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Error_SOURCES = Error.cpp TestUtilities.cpp TestUtilities.h
Error_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

FLAC_SOURCES = FLAC.cpp Lossless.h TestUtilities.cpp TestUtilities.h
FLAC_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

FloatToInt_SOURCES = FloatToInt.cpp TestUtilities.cpp TestUtilities.h
FloatToInt_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Identify_SOURCES = Identify.cpp TestUtilities.cpp TestUtilities.h
Identify_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Instrument_SOURCES = Instrument.cpp TestUtilities.cpp TestUtilities.h
Instrument_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

IntToFloat_SOURCES = IntToFloat.cpp TestUtilities.cpp TestUtilities.h
IntToFloat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

FormatWithChannels_SOURCES = FormatWithChannels.cpp TestUtilities.cpp TestUtilities.h
FormatWithChannels_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

InvalidCompressionFormat_SOURCES = InvalidCompressionFormat.cpp TestUtilities.cpp TestUtilities.h
InvalidCompressionFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

InvalidSampleFormat_SOURCES = InvalidSampleFormat.cpp TestUtilities.cpp TestUtilities.h
InvalidSampleFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Large_SOURCES = Large.cpp TestUtilities.cpp TestUtilities.h
Large_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Loop_SOURCES = Loop.cpp TestUtilities.cpp TestUtilities.h
Loop_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Marker_SOURCES = Marker.cpp TestUtilities.cpp TestUtilities.h
Marker_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Miscellaneous_SOURCES = Miscellaneous.cpp TestUtilities.cpp TestUtilities.h
Miscellaneous_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

NeXT_SOURCES = NeXT.cpp TestUtilities.cpp TestUtilities.h
NeXT_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

PCMData_SOURCES = PCMData.cpp TestUtilities.cpp TestUtilities.h
PCMData_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

PCMMapping_SOURCES = PCMMapping.cpp TestUtilities.cpp TestUtilities.h
PCMMapping_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Pipe_SOURCES = Pipe.cpp TestUtilities.cpp TestUtilities.h
Pipe_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Query_SOURCES = Query.cpp TestUtilities.cpp TestUtilities.h
Query_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

SampleFormat_SOURCES = SampleFormat.cpp TestUtilities.cpp TestUtilities.h
SampleFormat_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Seek_SOURCES = Seek.cpp TestUtilities.cpp TestUtilities.h
Seek_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

Sign_SOURCES = Sign.cpp TestUtilities.cpp TestUtilities.h
Sign_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

VirtualFile_SOURCES = VirtualFile.cpp TestUtilities.cpp TestUtilities.h
VirtualFile_LDADD = $(LIBGTEST) $(LIBAUDIOFILE)

floatto24_SOURCES = floatto24.c TestUtilities.cpp TestUtilities.h

printmarkers_SOURCES = printmarkers.c
printmarkers_LDADD = $(LIBAUDIOFILE) -lm

sixteen_to_eight_SOURCES = sixteen-to-eight.c TestUtilities.cpp TestUtilities.h

testchannelmatrix_SOURCES = testchannelmatrix.c TestUtilities.cpp TestUtilities.h

testdouble_SOURCES = testdouble.c TestUtilities.cpp TestUtilities.h

testfloat_SOURCES = testfloat.c TestUtilities.cpp TestUtilities.h

testmarkers_SOURCES = testmarkers.c TestUtilities.cpp TestUtilities.h

twentyfour_SOURCES = twentyfour.c TestUtilities.cpp TestUtilities.h

twentyfour2_SOURCES = twentyfour2.c TestUtilities.cpp TestUtilities.h

writealaw_SOURCES = writealaw.c TestUtilities.cpp TestUtilities.h

writeraw_SOURCES = writeraw.c TestUtilities.cpp TestUtilities.h

writeulaw_SOURCES = writeulaw.c TestUtilities.cpp TestUtilities.h

AM_CXXFLAGS = -fno-rtti -fno-exceptions -DGTEST_HAS_RTTI=0 -DGTEST_HAS_EXCEPTIONS=0
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <unistd.h>

#include "TestUtilities.h"

static void testMarkers(int fileFormat, bool supportsComments)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Marker", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	const int markerIDs[] = { 1, 2, 3, 5, 8 };
	const int numMarkers = sizeof (markerIDs) / sizeof (int);
	const char * const markerNames[numMarkers] =
	{
		"one",
		"two",
		"three",
		"five",
		"eight"
	};
	const char * const markerComments[numMarkers] =
	{
		"comment one",
		"comment two",
		"comment three",
		"comment five",
		"comment eight"
	};
	const int markerPositions[numMarkers] = { 1, 2, 3, 5, 8 };
	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, numMarkers);
	for (int i=0; i<numMarkers; i++)
		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);

	for (int i=0; i<numMarkers; i++)
		afInitMarkComment(setup, AF_DEFAULT_TRACK, markerIDs[i], markerComments[i]);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file) << "Could not open test file for writing";
	afFreeFileSetup(setup);

	const int frameCount = 10;
	int16_t frames[frameCount] = {0};

	EXPECT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, frames, frameCount),
		frameCount);

	for (int i=0; i<numMarkers; i++)
		afSetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i], markerPositions[i]);

	ASSERT_EQ(afCloseFile(file), 0);

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file) << "Could not open test file for reading";
	EXPECT_EQ(afGetFileFormat(file, NULL), fileFormat);

	ASSERT_EQ(afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL), numMarkers);
	int readMarkerIDs[numMarkers];
	afGetMarkIDs(file, AF_DEFAULT_TRACK, readMarkerIDs);
	for (int i=0; i<numMarkers; i++)
		EXPECT_EQ(markerIDs[i], readMarkerIDs[i]);
	
	for (int i=0; i<numMarkers; i++)
		EXPECT_TRUE(!strcmp(afGetMarkName(file, AF_DEFAULT_TRACK, markerIDs[i]),
			markerNames[i]));

	for (int i=0; i<numMarkers; i++)
	{
		const char *comment = afGetMarkComment(file, AF_DEFAULT_TRACK,
			markerIDs[i]);
		if (supportsComments)
			EXPECT_TRUE(!strcmp(comment, markerComments[i]));
	}

	for (int i=0; i<numMarkers; i++)
		EXPECT_EQ(afGetMarkPosition(file, AF_DEFAULT_TRACK, markerIDs[i]),
			markerPositions[i]);

	ASSERT_EQ(afCloseFile(file), 0);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(Marker, AIFF)
{
	testMarkers(AF_FILE_AIFF, false);
}

TEST(Marker, AIFC)
{
	testMarkers(AF_FILE_AIFFC, false);
}

TEST(Marker, WAVE)
{
	testMarkers(AF_FILE_WAVE, true);
}

static void testUnsupported(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Marker", &testFileName));

	AFerrfunc errorHandler = afSetErrorHandler(NULL);

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);

	const int markerIDs[] = { 1 };
	const int numMarkers = sizeof (markerIDs) / sizeof (int);
	const char * const markerNames[numMarkers] = { "name" };
	const char * const markerComments[numMarkers] = { "comment" };
	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markerIDs, numMarkers);
	for (int i=0; i<numMarkers; i++)
		afInitMarkName(setup, AF_DEFAULT_TRACK, markerIDs[i], markerNames[i]);

	for (int i=0; i<numMarkers; i++)
		afInitMarkComment(setup, AF_DEFAULT_TRACK, markerIDs[i], markerComments[i]);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file) << "Did not expect opening test file for writing to succeed";
	afFreeFileSetup(setup);

	afSetErrorHandler(errorHandler);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(Unsupported, Raw) { testUnsupported(AF_FILE_RAWDATA); }
TEST(Unsupported, NeXT) { testUnsupported(AF_FILE_NEXTSND); }
TEST(Unsupported, IRCAM) { testUnsupported(AF_FILE_IRCAM); }
TEST(Unsupported, AVR) { testUnsupported(AF_FILE_AVR); }
TEST(Unsupported, IFF) { testUnsupported(AF_FILE_IFF_8SVX); }
TEST(Unsupported, SampleVision) { testUnsupported(AF_FILE_SAMPLEVISION); }
TEST(Unsupported, VOC) { testUnsupported(AF_FILE_VOC); }
TEST(Unsupported, NIST) { testUnsupported(AF_FILE_NIST_SPHERE); }
TEST(Unsupported, CAF) { testUnsupported(AF_FILE_CAF); }
TEST(Unsupported, FLAC) { testUnsupported(AF_FILE_FLAC); }

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011-2014, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <gtest/gtest.h>
#include <audiofile.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "TestUtilities.h"

struct Miscellaneous
{
	int id;
	int type;
	const char *data;
};

const Miscellaneous kMiscellaneous[] =
{
	{ 1, AF_MISC_COPY, "1806 Ludwig van Beethoven" },
	{ 2, AF_MISC_NAME, "Violin Concerto in D major" }
};

const int kNumMiscellaneous = sizeof (kMiscellaneous) / sizeof (Miscellaneous);

void writeMiscellaneous(int fileFormat, const std::string &testFileName)
{
	AFfilesetup setup = afNewFileSetup();
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitFileFormat(setup, fileFormat);
	int *miscIDs = new int[kNumMiscellaneous];
	for (int i=0; i<kNumMiscellaneous; i++)
		miscIDs[i] = kMiscellaneous[i].id;
	afInitMiscIDs(setup, miscIDs, kNumMiscellaneous);
	delete [] miscIDs;
	for (int i=0; i<kNumMiscellaneous; i++)
	{
		afInitMiscType(setup, kMiscellaneous[i].id, kMiscellaneous[i].type);
		afInitMiscSize(setup, kMiscellaneous[i].id, strlen(kMiscellaneous[i].data));
	}

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);
	afFreeFileSetup(setup);
	for (int i=0; i<kNumMiscellaneous; i++)
	{
		int result = afWriteMisc(file, kMiscellaneous[i].id,
			kMiscellaneous[i].data,
			strlen(kMiscellaneous[i].data));
		EXPECT_EQ(strlen(kMiscellaneous[i].data), result);
	}

	const int16_t samples[] = { 1, 2, 3, 4 };
	const int sampleCount = sizeof (samples) / sizeof (samples[0]);
	EXPECT_EQ(sampleCount, afWriteFrames(file, AF_DEFAULT_TRACK, samples, sampleCount));
	ASSERT_EQ(0, afCloseFile(file));
}

void readMiscellaneous(const std::string &testFileName)
{
	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file);
	int count = afGetMiscIDs(file, NULL);
	EXPECT_EQ(count, kNumMiscellaneous);
	int miscIDs[kNumMiscellaneous];
	afGetMiscIDs(file, miscIDs);
	for (int i=0; i<kNumMiscellaneous; i++)
		EXPECT_EQ(miscIDs[i], kMiscellaneous[i].id);
	for (int i=0; i<kNumMiscellaneous; i++)
	{
		int misctype = afGetMiscType(file, miscIDs[i]);
		EXPECT_EQ(misctype, kMiscellaneous[i].type);

		int datasize = afGetMiscSize(file, miscIDs[i]);
		EXPECT_EQ(datasize, strlen(kMiscellaneous[i].data));

		char *data = new char[datasize];
		EXPECT_EQ(datasize, afReadMisc(file, miscIDs[i], data, datasize));

		EXPECT_TRUE(!memcmp(data, kMiscellaneous[i].data, datasize));

		delete [] data;
	}
	ASSERT_EQ(0, afCloseFile(file));
}

void testMiscellaneous(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Miscellaneous", &testFileName));
	writeMiscellaneous(fileFormat, testFileName);
	readMiscellaneous(testFileName);
	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
}

TEST(Miscellaneous, AIFF) { testMiscellaneous(AF_FILE_AIFF); }
TEST(Miscellaneous, AIFFC) { testMiscellaneous(AF_FILE_AIFFC); }
TEST(Miscellaneous, WAVE) { testMiscellaneous(AF_FILE_WAVE); }
TEST(Miscellaneous, IFF_8SVX) { testMiscellaneous(AF_FILE_IFF_8SVX); }

void testMiscellaneousUnsupported(int fileFormat)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Miscellaneous", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitFileFormat(setup, fileFormat);
	int *miscIDs = new int[kNumMiscellaneous];
	for (int i=0; i<kNumMiscellaneous; i++)
		miscIDs[i] = kMiscellaneous[i].id;
	afInitMiscIDs(setup, miscIDs, kNumMiscellaneous);
	delete [] miscIDs;
	for (int i=0; i<kNumMiscellaneous; i++)
	{
		afInitMiscType(setup, kMiscellaneous[i].id, kMiscellaneous[i].type);
		afInitMiscSize(setup, kMiscellaneous[i].id, strlen(kMiscellaneous[i].data));
	}

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_FALSE(file);
	afFreeFileSetup(setup);

	ASSERT_EQ(0, ::unlink(testFileName.c_str()));
}

TEST(Miscellaneous, Raw) { testMiscellaneousUnsupported(AF_FILE_RAWDATA); }
TEST(Miscellaneous, NeXT) { testMiscellaneousUnsupported(AF_FILE_NEXTSND); }
TEST(Miscellaneous, IRCAM) { testMiscellaneousUnsupported(AF_FILE_IRCAM); }
TEST(Miscellaneous, AVR) { testMiscellaneousUnsupported(AF_FILE_AVR); }
TEST(Miscellaneous, SampleVision) { testMiscellaneousUnsupported(AF_FILE_SAMPLEVISION); }
TEST(Miscellaneous, VOC) { testMiscellaneousUnsupported(AF_FILE_VOC); }
TEST(Miscellaneous, NIST) { testMiscellaneousUnsupported(AF_FILE_NIST_SPHERE); }
TEST(Miscellaneous, CAF) { testMiscellaneousUnsupported(AF_FILE_CAF); }
TEST(Miscellaneous, FLAC) { testMiscellaneousUnsupported(AF_FILE_FLAC); }

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>

#include "TestUtilities.h"

const uint8_t kDataUnspecifiedLength[] =
{
	'.', 's', 'n', 'd',
	0, 0, 0, 24, // offset of 24 bytes
	0xff, 0xff, 0xff, 0xff, // unspecified length
	0, 0, 0, 3, // 16-bit linear
	0, 0, 172, 68, // 44100 Hz
	0, 0, 0, 1, // 1 channel
	0, 1,
	0, 1,
	0, 2,
	0, 3,
	0, 5,
	0, 8,
	0, 13,
	0, 21,
	0, 34,
	0, 55
};

const uint8_t kDataTruncated[] =
{
	'.', 's', 'n', 'd',
	0, 0, 0, 24, // offset of 24 bytes
	0, 0, 0, 20, // length of 20 bytes
	0, 0, 0, 3, // 16-bit linear
	0, 0, 172, 68, // 44100 Hz
	0, 0, 0, 1, // 1 channel
	0, 1,
	0, 1,
	0, 2,
	0, 3,
	0, 5,
	0, 8,
	0, 13,
	0, 21,
	0, 34,
	0, 55
};

const int16_t kFrames[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
const int kFrameCount = sizeof (kFrames) / sizeof (kFrames[0]);

TEST(NeXT, UnspecifiedLength)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));

	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
	ASSERT_GT(fd, -1);
	ASSERT_EQ(::write(fd, kDataUnspecifiedLength, sizeof (kDataUnspecifiedLength)), sizeof (kDataUnspecifiedLength));
	::close(fd);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
	EXPECT_TRUE(file);

	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	EXPECT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	EXPECT_EQ(sampleWidth, 16);
	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
	EXPECT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
		kFrameCount * sizeof (int16_t));
	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), kFrameCount);

	int16_t *data = new int16_t[kFrameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, data,
		kFrameCount);
	EXPECT_EQ(framesRead, kFrameCount);
	for (int i=0; i<kFrameCount; i++)
		EXPECT_EQ(data[i], kFrames[i]);
	delete [] data;

	afCloseFile(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(NeXT, Truncated)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));

	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
	ASSERT_GT(fd, -1);
	const size_t truncatedSize = sizeof (kDataTruncated) - 4;
	const int truncatedFrameCount = kFrameCount - 2;
	ASSERT_EQ(::write(fd, kDataTruncated, truncatedSize), truncatedSize);
	::close(fd);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
	EXPECT_TRUE(file);

	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	EXPECT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	EXPECT_EQ(sampleWidth, 16);
	EXPECT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), 1);
	EXPECT_EQ(afGetTrackBytes(file, AF_DEFAULT_TRACK),
		truncatedFrameCount * sizeof (int16_t));
	EXPECT_EQ(afGetFrameCount(file, AF_DEFAULT_TRACK), truncatedFrameCount);

	int16_t *data = new int16_t[truncatedFrameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, data,
		truncatedFrameCount);
	EXPECT_EQ(framesRead, truncatedFrameCount);
	for (int i=0; i<truncatedFrameCount; i++)
		EXPECT_EQ(data[i], kFrames[i]);
	delete [] data;

	afCloseFile(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

const uint8_t kDataZeroChannels[] =
{
	'.', 's', 'n', 'd',
	0, 0, 0, 24, // offset of 24 bytes
	0, 0, 0, 2, // 2 bytes
	0, 0, 0, 3, // 16-bit linear
	0, 0, 172, 68, // 44100 Hz
	0, 0, 0, 0, // 0 channels
	0, 1
};

TEST(NeXT, ZeroChannels)
{
	IgnoreErrors ignoreErrors;

	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("NeXT", &testFileName));

	int fd = ::open(testFileName.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
	ASSERT_GT(fd, -1);
	ASSERT_EQ(::write(fd, kDataZeroChannels, sizeof (kDataZeroChannels)), sizeof (kDataZeroChannels));
	::close(fd);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "r", NULL);
	EXPECT_FALSE(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2011-2013 Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	For each supported file format, test reading and writing audio
	files with all applicable PCM audio data formats.
*/

#include <audiofile.h>
#include <climits>
#include <cmath>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>

#include "TestUtilities.h"

struct PCMMapping
{
	double slope, intercept, minClip, maxClip;
};

void getDefaultPCMMapping(int sampleFormat, int bitsPerSample, PCMMapping &m)
{
	switch (sampleFormat)
	{
		case AF_SAMPFMT_TWOSCOMP:
		{
			double s = std::pow(2.0, bitsPerSample - 1);
			m.slope = s;
			m.intercept = 0;
			m.minClip = -s;
			m.maxClip = s - 1;
			break;
		}
		case AF_SAMPFMT_UNSIGNED:
		{
			double s = std::pow(2.0, bitsPerSample - 1);
			m.slope = s;
			m.intercept = s;
			m.minClip = 0;
			m.maxClip = 2 * s - 1;
			break;
		}
		case AF_SAMPFMT_FLOAT:
		case AF_SAMPFMT_DOUBLE:
			m.slope = 1;
			m.intercept = 0;
			m.minClip = 0;
			m.maxClip = 0;
			break;
	}
}

template <typename T, int kSampleFormat, int kBitsPerSample>
void runTestWithChannels(int fileFormat, int channelCount)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("PCMData", &testFileName));

	const int numFrames = 20;
	const int numSamples = numFrames * channelCount;
	T samples[numSamples];
	for (int i=0; i<numFrames; i++)
		for (int c=0; c<channelCount; c++)
			samples[i*channelCount + c] = static_cast<T>(i*i + 3*c + 1);

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, channelCount);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, kSampleFormat, kBitsPerSample);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file) << "Could not open file for writing";

	afFreeFileSetup(setup);

	PCMMapping mapping, defaultMapping;
	getDefaultPCMMapping(kSampleFormat, kBitsPerSample, defaultMapping);

	afGetPCMMapping(file, AF_DEFAULT_TRACK,
		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
	ASSERT_EQ(mapping.slope, defaultMapping.slope);
	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);

	afGetVirtualPCMMapping(file, AF_DEFAULT_TRACK,
		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
	ASSERT_EQ(mapping.slope, defaultMapping.slope);
	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);

	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numFrames),
		numFrames) <<
		"Number of frames written does not match number of frames requested";

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file) << "Could not open file for reading";

	ASSERT_EQ(afGetFileFormat(file, NULL), fileFormat) <<
		"Incorrect file format";

	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ASSERT_EQ(sampleFormat, kSampleFormat) << "Incorrect sample format";
	ASSERT_EQ(sampleWidth, kBitsPerSample) << "Incorrect sample width";

	ASSERT_EQ(afGetChannels(file, AF_DEFAULT_TRACK), channelCount) <<
		"Incorrect number of channels";

	afGetPCMMapping(file, AF_DEFAULT_TRACK,
		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
	ASSERT_EQ(mapping.slope, defaultMapping.slope);
	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);

	afGetVirtualPCMMapping(file, AF_DEFAULT_TRACK,
		&mapping.slope, &mapping.intercept, &mapping.minClip, &mapping.maxClip);
	ASSERT_EQ(mapping.slope, defaultMapping.slope);
	ASSERT_EQ(mapping.intercept, defaultMapping.intercept);
	ASSERT_EQ(mapping.minClip, defaultMapping.minClip);
	ASSERT_EQ(mapping.maxClip, defaultMapping.maxClip);

	T *samplesRead = new T[numSamples];
	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, samplesRead, numFrames),
		numFrames) <<
		"Number of frames read does not match number of frames requested";

	for (int i=0; i<numSamples; i++)
		ASSERT_EQ(samplesRead[i], samples[i]) <<
			"Data read from file does not match data written";

	delete [] samplesRead;

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

template <typename T, int kSampleFormat, int kBitsPerSample>
void runTest(int fileFormat)
{
	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 1);
	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 2);
	runTestWithChannels<T, kSampleFormat, kBitsPerSample>(fileFormat, 4);
}

void testInt8(int fileFormat)
{
	runTest<int8_t, AF_SAMPFMT_TWOSCOMP, 8>(fileFormat);
}

void testInt8MonoOnly(int fileFormat)
{
	runTestWithChannels<int8_t, AF_SAMPFMT_TWOSCOMP, 8>(fileFormat, 1);
}

void testUInt8(int fileFormat)
{
	runTest<uint8_t, AF_SAMPFMT_UNSIGNED, 8>(fileFormat);
}

void testInt16(int fileFormat)
{
	runTest<int16_t, AF_SAMPFMT_TWOSCOMP, 16>(fileFormat);
}

void testInt16MonoOnly(int fileFormat)
{
	runTestWithChannels<int16_t, AF_SAMPFMT_TWOSCOMP, 16>(fileFormat, 1);
}

void testInt24(int fileFormat)
{
	runTest<int32_t, AF_SAMPFMT_TWOSCOMP, 24>(fileFormat);
}

void testInt32(int fileFormat)
{
	runTest<int32_t, AF_SAMPFMT_TWOSCOMP, 32>(fileFormat);
}

void testFloat32(int fileFormat)
{
	runTest<float, AF_SAMPFMT_FLOAT, 32>(fileFormat);
}

void testFloat64(int fileFormat)
{
	runTest<double, AF_SAMPFMT_DOUBLE, 64>(fileFormat);
}

TEST(AIFF, Int8) { testInt8(AF_FILE_AIFF); }
TEST(AIFF, Int16) { testInt16(AF_FILE_AIFF); }
TEST(AIFF, Int24) { testInt24(AF_FILE_AIFF); }
TEST(AIFF, Int32) { testInt32(AF_FILE_AIFF); }

TEST(AIFFC, Int8) { testInt8(AF_FILE_AIFFC); }
TEST(AIFFC, Int16) { testInt16(AF_FILE_AIFFC); }
TEST(AIFFC, Int24) { testInt24(AF_FILE_AIFFC); }
TEST(AIFFC, Int32) { testInt32(AF_FILE_AIFFC); }
TEST(AIFFC, Float) { testFloat32(AF_FILE_AIFFC); }
TEST(AIFFC, Double) { testFloat64(AF_FILE_AIFFC); }

TEST(WAVE, UInt8) { testUInt8(AF_FILE_WAVE); }
TEST(WAVE, Int16) { testInt16(AF_FILE_WAVE); }
TEST(WAVE, Int24) { testInt24(AF_FILE_WAVE); }
TEST(WAVE, Int32) { testInt32(AF_FILE_WAVE); }
TEST(WAVE, Float) { testFloat32(AF_FILE_WAVE); }
TEST(WAVE, Double) { testFloat64(AF_FILE_WAVE); }

TEST(NeXT, Int8) { testInt8(AF_FILE_NEXTSND); }
TEST(NeXT, Int16) { testInt16(AF_FILE_NEXTSND); }
TEST(NeXT, Int24) { testInt24(AF_FILE_NEXTSND); }
TEST(NeXT, Int32) { testInt32(AF_FILE_NEXTSND); }
TEST(NeXT, Float) { testFloat32(AF_FILE_NEXTSND); }
TEST(NeXT, Double) { testFloat64(AF_FILE_NEXTSND); }

TEST(IRCAM, Int8) { testInt8(AF_FILE_IRCAM); }
TEST(IRCAM, Int16) { testInt16(AF_FILE_IRCAM); }
TEST(IRCAM, Int24) { testInt24(AF_FILE_IRCAM); }
TEST(IRCAM, Int32) { testInt32(AF_FILE_IRCAM); }
TEST(IRCAM, Float) { testFloat32(AF_FILE_IRCAM); }
TEST(IRCAM, Double) { testFloat64(AF_FILE_IRCAM); }

TEST(IFF, Int8) { testInt8MonoOnly(AF_FILE_IFF_8SVX); }

TEST(AVR, Int8) { testInt8MonoOnly(AF_FILE_AVR); }
TEST(AVR, Int16) { testInt16MonoOnly(AF_FILE_AVR); }

TEST(SampleVision, Int16) { testInt16MonoOnly(AF_FILE_SAMPLEVISION); }

TEST(VOC, UInt8) { testUInt8(AF_FILE_VOC); }
TEST(VOC, Int16) { testInt16(AF_FILE_VOC); }

TEST(NIST, Int16) { testInt16(AF_FILE_NIST_SPHERE); }

TEST(CAF, Int8) { testInt8(AF_FILE_CAF); }
TEST(CAF, Int16) { testInt16(AF_FILE_CAF); }
TEST(CAF, Int24) { testInt24(AF_FILE_CAF); }
TEST(CAF, Int32) { testInt32(AF_FILE_CAF); }
TEST(CAF, Float) { testFloat32(AF_FILE_CAF); }
TEST(CAF, Double) { testFloat64(AF_FILE_CAF); }

int main (int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <limits>
#include <stdint.h>
#include <unistd.h>

#include "TestUtilities.h"

class PCMMappingTest : public testing::Test
{
protected:
	virtual void SetUp()
	{
		ASSERT_TRUE(createTemporaryFile("PCMMapping", &m_testFileName));
	}
	virtual void TearDown()
	{
		::unlink(m_testFileName.c_str());
	}

	AFfilehandle createTestFile(int sampleFormat, int sampleWidth)
	{
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, sampleFormat, sampleWidth);
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
		afFreeFileSetup(setup);
		return file;
	}
	AFfilehandle openTestFile()
	{
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
		return file;
	}

private:
	std::string m_testFileName;
};

TEST_F(PCMMappingTest, Float)
{
	AFfilehandle file = createTestFile(AF_SAMPFMT_FLOAT, 32);
	const float data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	double slope = 2, intercept = 2, minClip = 0, maxClip = 4;
	afSetVirtualPCMMapping(file, AF_DEFAULT_TRACK, slope, intercept, minClip, maxClip);
	float readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const float expectedData[] = { 0, 2, 4 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

TEST_F(PCMMappingTest, Double)
{
	AFfilehandle file = createTestFile(AF_SAMPFMT_DOUBLE, 64);
	const double data[] = { -1, 0, 1 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile();
	ASSERT_TRUE(file != NULL);
	double slope = 2, intercept = 2, minClip = 0, maxClip = 4;
	afSetVirtualPCMMapping(file, AF_DEFAULT_TRACK, slope, intercept, minClip, maxClip);
	double readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const double expectedData[] = { 0, 2, 4 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2012, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdlib.h>
#include <unistd.h>

#include <gtest/gtest.h>
#include <audiofile.h>

TEST(Pipe, Pipe)
{
	const int kFrameCount = 500;
	const int kSampleCount = 2 * kFrameCount;

	int16_t data[kSampleCount];
	int16_t readData[kSampleCount];

	for (int i=0; i<kSampleCount; i++)
		data[i] = 3*i + 2;

	AFfilesetup setup = afNewFileSetup();
	ASSERT_TRUE(setup);

	afInitFileFormat(setup, AF_FILE_RAWDATA);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
	afInitChannels(setup, AF_DEFAULT_TRACK, 2);
	afInitRate(setup, AF_DEFAULT_TRACK, 44100);

	int pipefd[2];
	ASSERT_GE(::pipe(pipefd), 0);

	AFfilehandle handle;

	// Write into pipe.
	handle = afOpenFD(pipefd[1], "w", setup);
	ASSERT_TRUE(handle);
	AFframecount framesWritten;
	framesWritten = afWriteFrames(handle, AF_DEFAULT_TRACK, data, kFrameCount);
	ASSERT_EQ(framesWritten, kFrameCount);
	ASSERT_EQ(afCloseFile(handle), 0);

	// Read from pipe.
	handle = afOpenFD(pipefd[0], "r", setup);
	ASSERT_TRUE(handle);
	AFframecount framesRead;
	framesRead = afReadFrames(handle, AF_DEFAULT_TRACK, readData, kFrameCount);
	ASSERT_EQ(framesRead, kFrameCount);
	ASSERT_TRUE(!::memcmp(readData, data, kFrameCount * sizeof (int16_t))) <<
		"Data read does not match data written";
	ASSERT_EQ(afCloseFile(handle), 0);

	afFreeFileSetup(setup);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <unistd.h>

#include "TestUtilities.h"

TEST(Query, FileFormats)
{
	IgnoreErrors ignoreErrors;

	int fileFormats[] =
	{
		AF_FILE_UNKNOWN,
		AF_FILE_RAWDATA,
		AF_FILE_AIFFC,
		AF_FILE_AIFF,
		AF_FILE_NEXTSND,
		AF_FILE_WAVE,
		AF_FILE_BICSF,
		AF_FILE_MPEG1BITSTREAM,
		AF_FILE_SOUNDDESIGNER1,
		AF_FILE_SOUNDDESIGNER2,
		AF_FILE_AVR,
		AF_FILE_IFF_8SVX,
		AF_FILE_SAMPLEVISION,
		AF_FILE_VOC,
		AF_FILE_NIST_SPHERE,
		AF_FILE_SOUNDFONT2,
		AF_FILE_CAF
	};
	int numFileFormats = sizeof (fileFormats) / sizeof (int);
	for (int i=0; i<numFileFormats; i++)
	{
		long implemented = afQueryLong(AF_QUERYTYPE_FILEFMT,
			AF_QUERY_IMPLEMENTED, fileFormats[i], 0, 0);
		const char *label =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
				AF_QUERY_LABEL, fileFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(label);
		const char *name =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
				AF_QUERY_NAME, fileFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(name);
		const char *description =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_FILEFMT,
				AF_QUERY_DESC, fileFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(description);
	}
}

TEST(Query, CompressionFormats)
{
	IgnoreErrors ignoreErrors;

	int compressionFormats[] =
	{
		AF_COMPRESSION_NONE,
		AF_COMPRESSION_G711_ULAW,
		AF_COMPRESSION_G711_ALAW,
		AF_COMPRESSION_IMA,
		AF_COMPRESSION_MS_ADPCM,
		AF_COMPRESSION_G722,
		AF_COMPRESSION_APPLE_ACE2,
		AF_COMPRESSION_APPLE_ACE8,
		AF_COMPRESSION_APPLE_MAC3,
		AF_COMPRESSION_APPLE_MAC6
	};
	int numCompressionFormats = sizeof (compressionFormats) / sizeof (int);
	for (int i=0; i<numCompressionFormats; i++)
	{
		long implemented = afQueryLong(AF_QUERYTYPE_COMPRESSION,
			AF_QUERY_IMPLEMENTED, compressionFormats[i], 0, 0);
		long nativeSampleFormat = afQueryLong(AF_QUERYTYPE_COMPRESSION,
			AF_QUERY_NATIVE_SAMPFMT, compressionFormats[i], 0, 0);
		if (implemented)
			EXPECT_TRUE(nativeSampleFormat == AF_SAMPFMT_TWOSCOMP ||
				nativeSampleFormat == AF_SAMPFMT_UNSIGNED ||
				nativeSampleFormat == AF_SAMPFMT_FLOAT ||
				nativeSampleFormat == AF_SAMPFMT_DOUBLE);
		long nativeSampleWidth = afQueryLong(AF_QUERYTYPE_COMPRESSION,
			AF_QUERY_NATIVE_SAMPWIDTH, compressionFormats[i], 0, 0);
		if (implemented)
		{
			EXPECT_GE(nativeSampleWidth, 1);
			EXPECT_LE(nativeSampleWidth, 64);
		}
		const char *label =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
				AF_QUERY_LABEL, compressionFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(label);
		const char *name =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
				AF_QUERY_NAME, compressionFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(name);
		const char *description =
			static_cast<const char *>(afQueryPointer(AF_QUERYTYPE_COMPRESSION,
				AF_QUERY_DESC, compressionFormats[i], 0, 0));
		if (implemented)
			EXPECT_TRUE(description);
	}
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2013, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

TEST(SampleFormat, NullArguments)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("SampleFormat", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFFC);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file);
	afFreeFileSetup(setup);

	int sampleFormat, sampleWidth;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	ASSERT_EQ(sampleWidth, 16);

	sampleFormat = -1;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, NULL, &sampleWidth);
	ASSERT_EQ(sampleFormat, -1);
	ASSERT_EQ(sampleWidth, 16);

	sampleWidth = -1;
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, NULL);
	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	ASSERT_EQ(sampleWidth, -1);

	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	ASSERT_EQ(sampleWidth, 16);

	sampleFormat = -1;
	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, NULL, &sampleWidth);
	ASSERT_EQ(sampleFormat, -1);
	ASSERT_EQ(sampleWidth, 16);

	sampleWidth = -1;
	afGetVirtualSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, NULL);
	ASSERT_TRUE(sampleFormat == AF_SAMPFMT_TWOSCOMP);
	ASSERT_EQ(sampleWidth, -1);

	ASSERT_EQ(afCloseFile(file), 0);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2003, 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
	This program tests seeking within an audio file.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>

#include "TestUtilities.h"

TEST(Seek, Seek)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("Seek", &testFileName));

	const int kFrameCount = 2000;
	const int kPadFrameCount = kFrameCount + 5;
	const int kDataLength = kFrameCount * sizeof (int16_t);

	int16_t data[kFrameCount];
	int16_t readData[kPadFrameCount];

	AFfilesetup setup = afNewFileSetup();
	ASSERT_TRUE(setup);

	afInitFileFormat(setup, AF_FILE_AIFF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file) << "could not open file for writing";

	afFreeFileSetup(setup);

	/* Initialize data to a nontrivial test pattern. */
	for (int i=0; i<kFrameCount; i++)
	{
		if ((i%2) != 0)
			data[i] = i;
		else
			data[i] = -i;
	}

	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, data, kFrameCount),
		kFrameCount);

	afCloseFile(file);

	file = afOpenFile(testFileName.c_str(), "r", AF_NULL_FILESETUP);
	ASSERT_TRUE(file) << "Could not open file for reading";

	/*
		For each position in the file, seek to that position and
		read to the end of the file, checking that the data read
		matches the data written.
	*/
	for (int i=0; i<kFrameCount; i++)
	{
		memset(readData, 0, kDataLength);

		AFfileoffset currentposition = afSeekFrame(file, AF_DEFAULT_TRACK, i);
		ASSERT_EQ(currentposition, i) << "Incorrect seek position";

		AFframecount framesread = afReadFrames(file, AF_DEFAULT_TRACK,
			readData + i, kPadFrameCount);
		ASSERT_EQ(framesread, kFrameCount - i) <<
			"Incorrect number of frames read";

		ASSERT_TRUE(!memcmp(data + i, readData + i,
			framesread * sizeof (int16_t))) <<
			"Error in data read";
	}

	afCloseFile(file);

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main (int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Copyright (C) 2010, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <audiofile.h>
#include <gtest/gtest.h>
#include <limits>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>

#include "TestUtilities.h"

class SignConversionTest : public testing::Test
{
protected:
	virtual void SetUp()
	{
		ASSERT_TRUE(createTemporaryFile("Sign", &m_testFileName));
	}
	virtual void TearDown()
	{
		ASSERT_EQ(::unlink(m_testFileName.c_str()), 0);
	}

	AFfilehandle createTestFile(int sampleWidth)
	{
		AFfilesetup setup = afNewFileSetup();
		afInitFileFormat(setup, AF_FILE_AIFFC);
		afInitChannels(setup, AF_DEFAULT_TRACK, 1);
		afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, sampleWidth);
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "w", setup);
		afFreeFileSetup(setup);
		return file;
	}
	AFfilehandle openTestFile(int sampleWidth)
	{
		AFfilehandle file = afOpenFile(m_testFileName.c_str(), "r", AF_NULL_FILESETUP);
		afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_UNSIGNED, sampleWidth);
		return file;
	}

private:
	std::string m_testFileName;
};

static const int8_t kMinInt8 = std::numeric_limits<int8_t>::min();
static const int8_t kMaxInt8 = std::numeric_limits<int8_t>::max();
static const uint8_t kMaxUInt8 = std::numeric_limits<uint8_t>::max();

TEST_F(SignConversionTest, Int8)
{
	AFfilehandle file = createTestFile(8);
	const int8_t data[] = { kMinInt8, 0, kMaxInt8 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(8);
	ASSERT_TRUE(file != NULL);
	uint8_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const uint8_t expectedData[] = { 0, -kMinInt8, kMaxUInt8 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int16_t kMinInt16 = std::numeric_limits<int16_t>::min();
static const int16_t kMaxInt16 = std::numeric_limits<int16_t>::max();
static const uint16_t kMaxUInt16 = std::numeric_limits<uint16_t>::max();

TEST_F(SignConversionTest, Int16)
{
	AFfilehandle file = createTestFile(16);
	const int16_t data[] = { kMinInt16, 0, kMaxInt16 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(16);
	ASSERT_TRUE(file != NULL);
	uint16_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const uint16_t expectedData[] = { 0, -kMinInt16, kMaxUInt16 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt24 = -1<<23;
static const int32_t kMaxInt24 = (1<<23) - 1;
static const uint32_t kMaxUInt24 = (1<<24) - 1;

TEST_F(SignConversionTest, Int24)
{
	AFfilehandle file = createTestFile(24);
	const int32_t data[] = { kMinInt24, 0, kMaxInt24 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(24);
	ASSERT_TRUE(file != NULL);
	uint32_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const uint32_t expectedData[] = { 0, -kMinInt24, kMaxUInt24 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

static const int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
static const int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
static const uint32_t kMaxUInt32 = std::numeric_limits<uint32_t>::max();

TEST_F(SignConversionTest, Int32)
{
	AFfilehandle file = createTestFile(32);
	const int32_t data[] = { kMinInt32, 0, kMaxInt32 };
	const int frameCount = sizeof (data) / sizeof (data[0]);
	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, data, frameCount);
	ASSERT_EQ(framesWritten, frameCount);
	afCloseFile(file);
	file = openTestFile(32);
	ASSERT_TRUE(file != NULL);
	uint32_t readData[frameCount];
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readData, frameCount);
	ASSERT_EQ(framesRead, frameCount);
	afCloseFile(file);
	const uint32_t expectedData[] = { 0, -kMinInt32, kMaxUInt32 };
	for (int i=0; i<frameCount; i++)
		EXPECT_EQ(readData[i], expectedData[i]);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#include "TestUtilities.h"

#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

bool createTemporaryFile(const std::string &prefix, std::string *path)
{
	*path = "/tmp/" + prefix + "-XXXXXX";
	int fd = ::mkstemp(const_cast<char *>(path->c_str()));
	if (fd < 0)
		return false;
	::close(fd);
	return true;
}

bool createTemporaryFile(const char *prefix, char **path)
{
	*path = NULL;
	std::string pathString;
	bool result = createTemporaryFile(prefix, &pathString);
	if (result)
		*path = ::strdup(pathString.c_str());
	return result;
}
/*
	Audio File Library
	Copyright (C) 2012, Michael Pruett <michael@68k.org>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the
	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
	Boston, MA  02110-1301  USA
*/

#ifndef TEST_UTILITIES_H
#define TEST_UTILITIES_H

#include <audiofile.h>

#ifdef __cplusplus

#include <string>

bool createTemporaryFile(const std::string &prefix, std::string *path);

class IgnoreErrors
{
public:
	IgnoreErrors()
	{
		m_oldErrorHandler = afSetErrorHandler(NULL);
	}
	~IgnoreErrors()
	{
		afSetErrorHandler(m_oldErrorHandler);
	}

private:
	AFerrfunc m_oldErrorHandler;
};

#endif

#ifdef __cplusplus
extern "C" {
#endif

#include <stdbool.h>

bool createTemporaryFile(const char *prefix, char **path);

#ifdef __cplusplus
}
#endif

#endif
/*
	Copyright (C) 2011, Michael Pruett. All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	notice, this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	notice, this list of conditions and the following disclaimer in the
	documentation and/or other materials provided with the distribution.

	3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"

#include <af_vfs.h>
#include <audiofile.h>
#include <gtest/gtest.h>
#include <limits>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

TEST(VirtualFile, Basic)
{
	ASSERT_GE(sizeof (off_t), 8) << "Size of off_t must be at least 8 bytes.";
}

static ssize_t vf_read(AFvirtualfile *vf, void *data, size_t nbytes)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	return fread(data, 1, nbytes, fp);
}

static AFfileoffset vf_length(AFvirtualfile *vf)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	off_t current = ftello(fp);
	fseeko(fp, 0, SEEK_END);
	off_t length = ftello(fp);
	fseeko(fp, current, SEEK_SET);
	return length;
}

static ssize_t vf_write(AFvirtualfile *vf, const void *data, size_t nbytes)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	return fwrite(data, 1, nbytes, fp);
}

static void vf_close(AFvirtualfile *vf)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	fclose(fp);
}

static AFfileoffset vf_seek(AFvirtualfile *vf, AFfileoffset offset, int is_relative)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	fseeko(fp, offset, is_relative ? SEEK_CUR : SEEK_SET);
	return ftello(fp);
}

static AFfileoffset vf_tell(AFvirtualfile *vf)
{
	FILE *fp = static_cast<FILE *>(vf->closure);
	return ftello(fp);
}

static AFvirtualfile *vf_create(FILE *fp)
{
	AFvirtualfile *vf = af_virtual_file_new();
	vf->read = vf_read;
	vf->length = vf_length;
	vf->write = vf_write;
	vf->destroy = vf_close;
	vf->seek = vf_seek;
	vf->tell = vf_tell;
	vf->closure = fp;
	return vf;
}

TEST(VirtualFile, ReadVirtual)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("VirtualFile", &testFileName));

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	AFfilehandle file = afOpenFile(testFileName.c_str(), "w", setup);
	ASSERT_TRUE(file) << "Could not open virtual file";

	afFreeFileSetup(setup);

	const int16_t samples[] = { 1, 1, 2, 3, 5, 8, 13 };
	const int numSamples = sizeof (samples) / sizeof (int16_t);
	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numSamples),
		numSamples) << "Incorrect number of samples written";

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing virtual file";

	FILE *fp = fopen(testFileName.c_str(), "r");
	AFvirtualfile *vf = vf_create(fp);

	file = afOpenVirtualFile(vf, "r", NULL);
	ASSERT_TRUE(file) << "Could not open file";

	int16_t readSamples[numSamples];
	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, readSamples, numSamples),
		numSamples) << "Incorrect number of samples read";

	for (int i=0; i<numSamples; i++)
		ASSERT_EQ(samples[i], readSamples[i]);

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

TEST(VirtualFile, WriteVirtual)
{
	std::string testFileName;
	ASSERT_TRUE(createTemporaryFile("VirtualFile", &testFileName));

	FILE *fp = fopen(testFileName.c_str(), "w");
	AFvirtualfile *vf = vf_create(fp);

	AFfilesetup setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFF);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	AFfilehandle file = afOpenVirtualFile(vf, "w", setup);
	ASSERT_TRUE(file) << "Could not open virtual file";

	afFreeFileSetup(setup);

	const int16_t samples[] = { 1, 1, 2, 3, 5, 8, 13 };
	const int numSamples = sizeof (samples) / sizeof (int16_t);
	ASSERT_EQ(afWriteFrames(file, AF_DEFAULT_TRACK, samples, numSamples),
		numSamples) << "Incorrect number of samples written";

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing virtual file";

	file = afOpenFile(testFileName.c_str(), "r", NULL);
	ASSERT_TRUE(file) << "Could not open file";

	int16_t readSamples[numSamples];
	ASSERT_EQ(afReadFrames(file, AF_DEFAULT_TRACK, readSamples, numSamples),
		numSamples) << "Incorrect number of samples read";

	for (int i=0; i<numSamples; i++)
		ASSERT_EQ(samples[i], readSamples[i]);

	ASSERT_EQ(afCloseFile(file), 0) << "Error closing file";

	ASSERT_EQ(::unlink(testFileName.c_str()), 0);
}

int main(int argc, char **argv)
{
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
/*
	Audio File Library

	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	floatto24.c

	This program creates a BICSF floating-point sound file and then
	reads the sample data back as 24-bit data (i.e. 32-bit integers
	with the high 8 bits equal to the sign extension of the lower
	24 bits).
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <audiofile.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>

#include "TestUtilities.h"

/*
	When converted to samples with width 24 bits, the samples
	should have the following values:
*/

const float samples[] =
{
	0,
	0.5,
	-0.5,
	1,
	-1,
	-0.25,
	0.25,
	0.75,
	-0.75
};

const int referenceConvertedSamples[] =
{
	0,
	4194304,	// = 2^23 * 0.5
	-4194304,	// = 2^23 * -0.5
	8388607,	// = 2^23 - 1
	-8388608,	// = 2^23 * -1
	-2097152,	// = 2^23 * -0.25
	2097152,	// = 2^23 * 0.25
	6291456,	// = 2^23 * 0.75
	-6291456	// = 2^23 * -0.75
};

const int frameCount = sizeof (samples) / sizeof (samples[0]);

int main (int argc, char **argv)
{
	AFfilesetup	setup;
	if ((setup = afNewFileSetup()) == AF_NULL_FILESETUP)
	{
		fprintf(stderr, "Could not allocate file setup.\n");
		exit(EXIT_FAILURE);
	}

	afInitFileFormat(setup, AF_FILE_IRCAM);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);

	char *testFileName;
	if (!createTemporaryFile("floatto24", &testFileName))
	{
		fprintf(stderr, "Could not create temporary file.\n");
		exit(EXIT_FAILURE);
	}

	AFfilehandle file = afOpenFile(testFileName, "w", setup);
	if (file == AF_NULL_FILEHANDLE)
	{
		printf("could not open file for writing\n");
		exit(EXIT_FAILURE);
	}

	afFreeFileSetup(setup);

	AFframecount framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		frameCount);

	if (framesWritten != frameCount)
	{
		fprintf(stderr, "Wrong number of frames read.\n");
		exit(EXIT_FAILURE);
	}

	if (afCloseFile(file) != 0)
	{
		fprintf(stderr, "Closing file returned non-zero status.\n");
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "Could not open file for writing.\n");
		exit(EXIT_FAILURE);
	}

	if (afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
		AF_SAMPFMT_TWOSCOMP, 24) != 0)
	{
		fprintf(stderr, "afSetVirtualSampleFormat returned non-zero status.\n");
		exit(EXIT_FAILURE);
	}

	int readSamples[frameCount];
	for (int i=0; i<frameCount; i++)
		readSamples[i] = -1000 - i;
	AFframecount framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readSamples,
		frameCount);

	if (framesRead != frameCount)
	{
		fprintf(stderr, "Wrong number of frames read.\n");
		exit(EXIT_FAILURE);
	}

	for (int i=0; i<framesRead; i++)
	{
#ifdef DEBUG
		printf("[%d] = %d\n", i, readSamples[i]);
#endif

		if (readSamples[i] == -1000 - i)
		{
			fprintf(stderr, "Data in destination array untouched.\n");
			exit(EXIT_FAILURE);
		}

		/*
			Ensure that the high-order 8 bits represent
			sign extension: only 0x00 (+) or 0xff (-) is
			valid.
		*/
		if ((readSamples[i] & 0xff000000) != 0x000000 &&
			(readSamples[i] & 0xff000000) != 0xff000000)
		{
			fprintf(stderr, "Data is not within range of "
				"{-2^23, ..., 2^23-1}.\n");
			exit(EXIT_FAILURE);
		}

		if (readSamples[i] != referenceConvertedSamples[i])
		{
			fprintf(stderr, "Data doesn't match reference data.\n");
			exit(EXIT_FAILURE);
		}
	}

	if (afCloseFile(file) != 0)
	{
		fprintf(stderr, "Closing file returned non-zero status.\n");
		exit(EXIT_FAILURE);
	}

	unlink(testFileName);
	free(testFileName);

	exit(EXIT_SUCCESS);
}
/*
	Audio File Library

	Copyright 1998, Michael Pruett <michael@68k.org>
	Copyright 2000, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <audiofile.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char **argv)
{
	AFfilehandle	file;
	long		result;
	int		count, instids;

	if (argc != 2)
	{
		fprintf(stderr, "usage: %s filename\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(argv[1], "r", NULL);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file '%s'\n", argv[1]);
		exit(EXIT_FAILURE);
	}

	count = afGetInstIDs(file, &instids);
	printf("%ld instruments in file '%s'\n", count, argv[1]);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
	printf("MIDI base note: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
	printf("detune in cents: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
	printf("MIDI low note: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
	printf("MIDI high note: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
	printf("MIDI low velocity: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
	printf("MIDI high velocity: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
	printf("gain in decibels: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_SUSLOOPID);
	printf("sustain loop id: %ld\n", result);

	result = afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_RELLOOPID);
	printf("release loop id: %ld\n", result);

	afCloseFile(file);

	return 0;
}
/*
	Audio File Library

	Copyright 2000, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>

#include <audiofile.h>

int main (int argc, char **argv)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	AUpvlist	list;

	if (argc != 2)
	{
		fprintf(stderr, "usage: instparamwrite filename\n");
	}

	setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_AIFFC);

	file = afOpenFile(argv[1], "w", setup);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file %s for writing", argv[1]);
	}

	afFreeFileSetup(setup);

	/* Set the base note to a 'D.' */
	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE, 50);

	/* Detune down by 30 cents. */
	afSetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE, -30);

	afCloseFile(file);

	return 0;
}
/*
	Audio File Library

	Copyright (C) 2002, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	printmarkers

	This program lists the markers in an audio file.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include <audiofile.h>

void printtime (AFframecount position, double rate)
{
	double	time_in_seconds;

	time_in_seconds = (double) position / rate;

	/* Handle hours. */
	if (time_in_seconds > 3600)
	{
		printf("%d:", (int) (time_in_seconds / 3600));
		time_in_seconds = fmod(time_in_seconds, 3600);
	}

	/* Handle minutes. */
	if (time_in_seconds > 60)
	{
		printf("%02d:", (int) (time_in_seconds / 60));
		time_in_seconds = fmod(time_in_seconds, 60);
	}

	/* Handle seconds and milliseconds. */
	printf("%02.3f", time_in_seconds);
}

int main (int argc, char **argv)
{
	AFfilehandle	file;
	double		rate;
	int		markcount;
	int		*markids;
	int		i;

	if (argc != 2)
	{
		fprintf(stderr, "usage: %s filename\n", argv[0]);
		fprintf(stderr, "where filename is the name of an audio file containing markers\n");
		exit(0);
	}

	file = afOpenFile(argv[1], "r", NULL);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "Could not open file '%s' for reading.", argv[1]);
		exit(0);
	}

	markcount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
	if (markcount <= 0)
	{
		fprintf(stderr, "The file '%s' does not contain any markers.", argv[1]);
		exit(0);
	}

	markids = calloc(markcount, sizeof (int));
	if (markids == NULL)
	{
		fprintf(stderr, "Could not allocate enough memory for markers.");
		exit(0);
	}

	afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);

	rate = afGetRate(file, AF_DEFAULT_TRACK);

	for (i=0; i<markcount; i++)
	{
		AFframecount	position;
		const char	*name, *comment;

		position = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]);

		name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
		comment = afGetMarkComment(file, AF_DEFAULT_TRACK, markids[i]);

		printf("marker %d, position %lld, time ", markids[i], position);

		printtime(position, rate);

		printf("\n");

		if (name != NULL)
			printf("\tname: %s\n", name);
		if (comment != NULL)
			printf("\tcomment: %s\n", comment);
	}

	afCloseFile(file);

	return EXIT_SUCCESS;
}
/*
	Audio File Library

	Copyright 1998-2000, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#include <dmedia/audioutil.h>
#else
#include <audiofile.h>
#include <aupvlist.h>
#endif

#include <stdio.h>
#include <stdlib.h>

const char *paramtypename (int paramtype);
void printinstparams (int format);

#define DEBUG

#ifdef DEBUG
#define DEBG printf
#else
#define DEBG
#endif

int main (int ac, char **av)
{
	AUpvlist	formatlist;
	int		*flist;
	long		lvalue;
	int		i, formatcount;

	formatlist = afQuery(AF_QUERYTYPE_FILEFMT, AF_QUERY_IDS, 0, 0, 0);
	formatcount = afQueryLong(AF_QUERYTYPE_FILEFMT, AF_QUERY_ID_COUNT, 0, 0, 0);

	DEBG("formatcount = %d\n", formatcount);

	AUpvgetval(formatlist, 0, &flist);
	AUpvfree(formatlist);

	for (i=0; i<formatcount; i++)
	{
		int	format;
		char	*formatstring;

		format = flist[i];
		DEBG("format = %d\n", format);
		formatstring = afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_NAME,
			format, 0, 0);
		DEBG("format = %s\n", formatstring);

		lvalue = afQueryLong(AF_QUERYTYPE_INST, AF_QUERY_SUPPORTED,
			format, 0, 0);
		DEBG("instrument query: supported: %ld\n", lvalue);

		lvalue = afQueryLong(AF_QUERYTYPE_INST, AF_QUERY_MAX_NUMBER,
			format, 0, 0);
		DEBG("instrument query: maximum number: %ld\n", lvalue);

		lvalue = afQueryLong(AF_QUERYTYPE_INSTPARAM, AF_QUERY_SUPPORTED,
			format, 0, 0);
		DEBG("instrument parameter query: supported: %ld\n", lvalue);

		/*
			Print instrument parameter information only if
			instrument parameters are supported.
		*/
		if (lvalue)
			printinstparams(format);
	}
	free(flist);

	return 0;
}

void printinstparams (int format)
{
	int	i, *iarray;
	long	instParamCount;

	instParamCount = afQueryLong(AF_QUERYTYPE_INSTPARAM, AF_QUERY_ID_COUNT,
		format, 0, 0);
	DEBG("instrument parameter query: id count: %ld\n", instParamCount);

	iarray = afQueryPointer(AF_QUERYTYPE_INSTPARAM, AF_QUERY_IDS,
		format, 0, 0);

	if (iarray == NULL)
		printf("AF_QUERYTYPE_INSTPARAM failed for format %d\n", format);

	for (i=0; i<instParamCount; i++)
	{
		int		paramType;
		AUpvlist	defaultValue;

		DEBG("instrument parameter query: id: %d\n", iarray[i]);
		paramType = afQueryLong(AF_QUERYTYPE_INSTPARAM,
			AF_QUERY_TYPE, format, iarray[i], 0);

		DEBG("\ttype of parameter: %s\n", paramtypename(paramType));
		DEBG("\tname of parameter: %s\n",
			(char *) afQueryPointer(AF_QUERYTYPE_INSTPARAM,
				AF_QUERY_NAME, format, iarray[i], 0));

		defaultValue = afQuery(AF_QUERYTYPE_INSTPARAM, AF_QUERY_DEFAULT,
			format, iarray[i], 0);

		if (paramType == AU_PVTYPE_LONG)
		{
			long	ldefault;
			AUpvgetval(defaultValue, 0, &ldefault);
			DEBG("\tdefault value: %ld\n", ldefault);
		}
		else if (paramType == AU_PVTYPE_DOUBLE)
		{
			double	ddefault;
			AUpvgetval(defaultValue, 0, &ddefault);
			DEBG("\tdefault value: %f\n", ddefault);
		}
		else if (paramType == AU_PVTYPE_PTR)
		{
			void	*vdefault;
			AUpvgetval(defaultValue, 0, &vdefault);
			DEBG("\tdefault value: %p\n", vdefault);
		}

		AUpvfree(defaultValue);
	}

	free(iarray);
}

const char *paramtypename (int paramtype)
{
	static const char	*longname = "long";
	static const char	*doublename = "double";
	static const char	*pointername = "pointer";

	switch (paramtype)
	{
		case AU_PVTYPE_LONG:
			return longname;
		case AU_PVTYPE_DOUBLE:
			return doublename;
		case AU_PVTYPE_PTR:
			return pointername;
	}

	return NULL;
}
/*
	Audio File Library

	Copyright 2000, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	sixteen-to-eight.c

	This program tests the conversion from 16-bit integers to 8-bit
	integers.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

#include <audiofile.h>

#include "TestUtilities.h"

int main (int argc, char **argv)
{
	AFfilehandle file;
	AFfilesetup setup;
	int16_t frames16[] = {14298, 392, 3923, -683, 958, -1921};
	int8_t frames8[] = {55, 1, 15, -3, 3, -8};
	int i, frameCount = 6;
	int8_t byte;
	AFframecount result;

	setup = afNewFileSetup();

	afInitFileFormat(setup, AF_FILE_WAVE);

	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_UNSIGNED, 8);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	char *testFileName;
	if (!createTemporaryFile("sixteen-to-eight", &testFileName))
	{
		fprintf(stderr, "Could not create temporary file.\n");
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(testFileName, "w", setup);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file for writing\n");
		exit(EXIT_FAILURE);
	}

	afFreeFileSetup(setup);

	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	afWriteFrames(file, AF_DEFAULT_TRACK, frames16, frameCount);

	afCloseFile(file);

	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file for reading\n");
		exit(EXIT_FAILURE);
	}

	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 8);

	for (i=0; i<frameCount; i++)
	{
		/* Read one frame. */
		result = afReadFrames(file, AF_DEFAULT_TRACK, &byte, 1);

		if (result != 1)
			break;

		/* Compare the byte read with its precalculated value. */
		if (memcmp(&byte, &frames8[i], 1) != 0)
		{
			printf("error\n");
			printf("expected %d, got %d\n", frames8[i], byte);
			exit(EXIT_FAILURE);
		}
		else
		{
#ifdef DEBUG
			printf("got what was expected: %d\n", byte);
#endif
		}
	}

	afCloseFile(file);
	unlink(testFileName);
	free(testFileName);

	exit(EXIT_SUCCESS);
}
/*
	Audio File Library

	Copyright 1998, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	testaupv.c

	This is a program to test the AUpvlist commands.
*/

#ifdef __USE_SGI_HEADERS__
#include <dmedia/dm_audioutil.h>
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#include <aupvlist.h>
#endif

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char **argv)
{
	AUpvlist		list;
	int				size;
	AFfilehandle	file;

	long	fuck = 99;

	if (argc != 2)
	{
		fprintf(stderr, "usage: testaupv filename\n");
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(argv[1], "r", NULL);

	list = AUpvnew(4);
	size = AUpvgetmaxitems(list);

	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 0, AF_INST_MIDI_BASENOTE));
	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 1, AF_INST_MIDI_LONOTE));
	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 2, AF_INST_SUSLOOPID));
	printf("AUpvsetparam: %d\n", AUpvsetparam(list, 3, AF_INST_RELLOOPID));

	afGetInstParams(file, AF_DEFAULT_INST, list, 4);

	AUpvgetval(list, 0, &fuck);
	printf("AUpvgetval: %ld\n", fuck);

	AUpvgetval(list, 1, &fuck);
	printf("AUpvgetval: %ld\n", fuck);

	AUpvgetval(list, 2, &fuck);
	printf("AUpvgetval: %ld\n", fuck);

	AUpvgetval(list, 3, &fuck);
	printf("AUpvgetval: %ld\n", fuck);

	afCloseFile(file);

	return 0;
}
/*
	Audio File Library

	Copyright (C) 2003, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	testchannelmatrix.c

	This program tests the channel matrix functionality of virtual
	sample format conversion in the Audio File Library.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

static char *sTestFileName;

const short samples[] = {300, -300, 515, -515, 2315, -2315, 9154, -9154};
#define SAMPLE_COUNT (sizeof (samples) / sizeof (short))
#define CHANNEL_COUNT 2

void cleanup (void)
{
	if (sTestFileName)
	{
		unlink(sTestFileName);
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (void)
{
	AFfilesetup	setup;
	AFfilehandle	file;
	int		framesWritten, framesRead;
	const int 	frameCount = SAMPLE_COUNT / CHANNEL_COUNT;
	short		readsamples[SAMPLE_COUNT];
	int		i;
	int		sampleFormat, sampleWidth;

	setup = afNewFileSetup();

	afInitChannels(setup, AF_DEFAULT_TRACK, CHANNEL_COUNT);
	afInitFileFormat(setup, AF_FILE_AIFFC);

	/* Write stereo data to test file. */
	ensure(createTemporaryFile("testchannelmatrix", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");

	afFreeFileSetup(setup);

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		frameCount);
	ensure(framesWritten == frameCount,
		"number of frames written doesn't match "
		"number of frames requested");

	ensure(afCloseFile(file) == 0, "error closing file");

	/*
		Open the test file and read stereo data mixed down to a
		single channel.  The default channel matrix for one
		file channel and two virtual channels is {0.5, 0.5},
		and since each odd sample is the inverse of the
		corresponding even sample, the data read should be all
		zeros.
	*/
	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
		"file doesn't have exactly two channels");
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ensure(sampleFormat == AF_SAMPFMT_TWOSCOMP && sampleWidth == 16,
		"file doesn't contain 16-bit two's complement data");
	ensure(afGetFileFormat(file, NULL) == AF_FILE_AIFFC,
		"file format doesn't match format requested");

	afSetVirtualChannels(file, AF_DEFAULT_TRACK, 1);

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
		frameCount);
	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");

	for (i=0; i<SAMPLE_COUNT/CHANNEL_COUNT; i++)
	{
		ensure(readsamples[i] == 0,
			"data written to file is not as expected");
	}

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();
	exit(EXIT_SUCCESS);
}
/*
	Audio File Library

	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	testdouble.c

	This program tests double-precision floating-point reading and
	writing for the AIFF-C, WAVE, and NeXT .snd file formats.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

static char *sTestFileName;

const double samples[] =
	{1.0, 0.6, -0.3, 0.95, 0.2, -0.6, 0.9, 0.4, -0.22, 0.125, 0.1, -0.4};
const int SAMPLE_COUNT = sizeof (samples) / sizeof (samples[0]);

void testdouble (int fileFormat);

void cleanup (void)
{
	if (sTestFileName)
	{
		unlink(sTestFileName);
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (int argc, char **argv)
{
	/* These file formats support double-precision floating-point audio data. */
	const int fileFormats[] =
		{ AF_FILE_AIFFC, AF_FILE_WAVE, AF_FILE_NEXTSND };
	const int fileFormatCount = sizeof (fileFormats) / sizeof (fileFormats[0]);
	int	i;

	for (i=0; i<fileFormatCount; i++)
	{
		printf("testdouble: testing %s\n",
			(char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_NAME, fileFormats[i], 0, 0));
		testdouble(fileFormats[i]);
	}

	printf("testdouble passed\n");
	exit(EXIT_SUCCESS);
}

void testdouble (int fileFormat)
{
	AFfilesetup	setup;
	AFfilehandle	file;
	int		framesWritten, framesRead;
	const int 	frameCount = SAMPLE_COUNT/2;
	double		readsamples[SAMPLE_COUNT];
	int		i;
	int		sampleFormat, sampleWidth;

	setup = afNewFileSetup();

	afInitFileFormat(setup, fileFormat);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_DOUBLE, 64);
	afInitChannels(setup, AF_DEFAULT_TRACK, 2);

	ensure(createTemporaryFile("testdouble", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");

	afFreeFileSetup(setup);

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		frameCount);
	ensure(framesWritten == frameCount, "number of frames written does not match number of frames requested");

	ensure(afCloseFile(file) == 0, "error closing file");

	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
		"file doesn't have exactly two channels");
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ensure(sampleFormat == AF_SAMPFMT_DOUBLE && sampleWidth == 64,
		"file doesn't contain 64-bit floating-point data");
	ensure(afGetFileFormat(file, NULL) == fileFormat,
		"file format doesn't match format requested");

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
		frameCount);
	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");

	for (i=0; i<SAMPLE_COUNT; i++)
	{
		ensure(readsamples[i] == samples[i],
			"data written to file doesn't match data read");
	}

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();
}
/*
	Audio File Library

	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	testfloat.c

	This program tests floating-point reading and writing for
	the AIFF-C, WAVE, NeXT .snd, and IRCAM file formats.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

static char *sTestFileName;

const float samples[] =
	{1.0, 0.6, -0.3, 0.95, 0.2, -0.6, 0.9, 0.4, -0.22, 0.125, 0.1, -0.4};
#define SAMPLE_COUNT (sizeof (samples) / sizeof (float))

void testfloat (int fileFormat);

void cleanup (void)
{
	if (sTestFileName)
	{
		unlink(sTestFileName);
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (int argc, char **argv)
{
	/* These file formats support floating-point audio data. */
	int	fileFormatCount = 4;
	int	fileFormats[] =
		{AF_FILE_AIFFC, AF_FILE_WAVE, AF_FILE_NEXTSND, AF_FILE_IRCAM};
	char	*formatNames[] = {"AIFF-C", "WAVE", "NeXT .snd", "IRCAM"};
	int	i;

	for (i=0; i<fileFormatCount; i++)
	{
		printf("testfloat: testing %s\n", formatNames[i]);
		testfloat(fileFormats[i]);
	}

	printf("testfloat passed\n");
	exit(EXIT_SUCCESS);
}

void testfloat (int fileFormat)
{
	AFfilesetup	setup;
	AFfilehandle	file;
	int		framesWritten, framesRead;
	const int 	frameCount = SAMPLE_COUNT/2;
	float		readsamples[SAMPLE_COUNT];
	int		i;
	int		sampleFormat, sampleWidth;

	setup = afNewFileSetup();

	afInitFileFormat(setup, fileFormat);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_FLOAT, 32);
	afInitChannels(setup, AF_DEFAULT_TRACK, 2);

	ensure(createTemporaryFile("testfloat", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for writing");

	afFreeFileSetup(setup);

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		frameCount);
	ensure(framesWritten == frameCount, "number of frames written does not match number of frames requested");

	ensure(afCloseFile(file) == 0, "error closing file");

	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
	ensure(file != AF_NULL_FILEHANDLE, "could not open file for reading");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 2,
		"file doesn't have exactly two channels");
	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ensure(sampleFormat == AF_SAMPFMT_FLOAT && sampleWidth == 32,
		"file doesn't contain 32-bit floating-point data");
	ensure(afGetFileFormat(file, NULL) == fileFormat,
		"file format doesn't match format requested");

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
		frameCount);
	ensure(framesRead == frameCount, "number of frames read does not match number of frames requested");

	for (i=0; i<SAMPLE_COUNT; i++)
	{
		ensure(readsamples[i] == samples[i],
			"data written to file doesn't match data read");
	}

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();
}
/*
	Audio File Library

	Copyright (C) 2002, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

static char *sTestFileName;

#define FRAME_COUNT 200

void cleanup (void)
{
	if (sTestFileName)
	{
#ifndef DEBUG
		unlink(sTestFileName);
#endif
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int testmarkers (int fileformat)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	int		markids[] = {1, 2, 3, 4};
	AFframecount	markpositions[] = {14, 54, 23, 101};
	const char	*marknames[] = {"one", "two", "three", "four"};
	short		frames[FRAME_COUNT * 2] = {0};
	int		readmarkcount;
	int		readmarkids[4];
	AFframecount	frameswritten;

	setup = afNewFileSetup();
	ensure(setup != AF_NULL_FILESETUP, "Could not create file setup");

	afInitFileFormat(setup, fileformat);
	afInitChannels(setup, AF_DEFAULT_TRACK, 2);

	afInitMarkIDs(setup, AF_DEFAULT_TRACK, markids, 4);

	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[0], marknames[0]);
	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[1], marknames[1]);
	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[2], marknames[2]);
	afInitMarkName(setup, AF_DEFAULT_TRACK, markids[3], marknames[3]);

	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != AF_NULL_FILEHANDLE, "Could not open file for writing");

	afFreeFileSetup(setup);

	frameswritten = afWriteFrames(file, AF_DEFAULT_TRACK, frames, FRAME_COUNT);
	ensure(frameswritten == FRAME_COUNT, "Error writing audio data");

	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[0], markpositions[0]);
	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[1], markpositions[1]);
	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[2], markpositions[2]);
	afSetMarkPosition(file, AF_DEFAULT_TRACK, markids[3], markpositions[3]);

	afCloseFile(file);

	file = afOpenFile(sTestFileName, "r", NULL);
	ensure(file != AF_NULL_FILEHANDLE, "Could not open file for reading");

	readmarkcount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
	ensure(readmarkcount == 4, "Number of markers is not correct");

	afGetMarkIDs(file, AF_DEFAULT_TRACK, readmarkids);

	for (int i=0; i<readmarkcount; i++)
		ensure(readmarkids[i] = markids[i],
			"Marker identification numbers do not match");

	for (int i=0; i<readmarkcount; i++)
	{
		AFframecount	readmarkposition;
		const char	*readmarkname;

		readmarkposition = afGetMarkPosition(file, AF_DEFAULT_TRACK, readmarkids[i]);

		readmarkname = afGetMarkName(file, AF_DEFAULT_TRACK, readmarkids[i]);

		ensure(readmarkposition == markpositions[i],
			"Marker positions do not match");
		ensure(strcmp(readmarkname, marknames[i]) == 0,
			"Marker names do not match");
	}

	afCloseFile(file);

	return EXIT_SUCCESS;
}

int main (void)
{
	ensure(createTemporaryFile("testmarkers", &sTestFileName),
		"could not create temporary file");

	testmarkers(AF_FILE_AIFF);
	testmarkers(AF_FILE_AIFFC);
	testmarkers(AF_FILE_WAVE);

	cleanup();

	return EXIT_SUCCESS;
}
/*
	Audio File Library

	Copyright (C) 2001, Silicon Graphics, Inc.
	Michael Pruett <mpruett@sgi.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	twentyfour.c

	This program tests the conversion between 24-bit signed integer
	data in a file and 32-bit signed integer data in memory.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

#define FRAME_COUNT 6

int main (int argc, char **argv)
{
	AFfilehandle file;
	AFfilesetup setup;
	/* All elements in frames32 must be in the range -2^23 to 2^23 - 1. */
	const int32_t frames32[FRAME_COUNT] =
		{4314298, -49392, 3923, -143683, 43, -992129};
	const uint8_t frames24[FRAME_COUNT*3] =
		{
			0x41, 0xd4, 0xba,	/* 4314298 */
			0xff, 0x3f, 0x10,	/* -49392 */
			0x00, 0x0f, 0x53,	/* 3923 */
			0xfd, 0xce, 0xbd,	/* -143683 */
			0x00, 0x00, 0x2b,	/* 43 */
			0xf0, 0xdc, 0x7f	/* -992129 */
		};
	int32_t readframes32[FRAME_COUNT];
	int i;

	setup = afNewFileSetup();
	assert(setup);

	afInitFileFormat(setup, AF_FILE_AIFF);

	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	char *testFileName;
	if (!createTemporaryFile("twentyfour", &testFileName))
	{
		fprintf(stderr, "could not create temporary file\n");
		exit(EXIT_FAILURE);
	}

	file = afOpenFile(testFileName, "w", setup);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file for writing\n");
		exit(EXIT_FAILURE);
	}

	afFreeFileSetup(setup);

	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);
	afWriteFrames(file, AF_DEFAULT_TRACK, frames32, FRAME_COUNT);

	afCloseFile(file);

	file = afOpenFile(testFileName, "r", AF_NULL_FILESETUP);
	if (file == AF_NULL_FILEHANDLE)
	{
		fprintf(stderr, "could not open file for reading\n");
		exit(EXIT_FAILURE);
	}

	/* Test virtual sample width of 24 bits. */
#ifdef DEBUG
	fprintf(stderr, "Testing virtual sample width of 24 bits.\n");
#endif
	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);

	for (i=0; i<FRAME_COUNT; i++)
	{
		uint8_t	x[4];
		uint8_t	y[4];
		uint8_t	z[4];

		if ((frames32[i] & 0x800000) != 0)
			x[0] = 0xff;
		else
			x[0] = 0;
		x[1] = (frames32[i] >> 16) & 0xff;
		x[2] = (frames32[i] >> 8) & 0xff;
		x[3] = (frames32[i]) & 0xff;

		/*
			Check to see that the precomputed values match
			what we've just computed.
		*/
		if (x[1] != frames24[3*i] ||
			x[2] != frames24[3*i + 1] ||
			x[3] != frames24[3*i + 2])
		{
			fprintf(stderr, "Data doesn't match pre-computed values.\n");
			exit(EXIT_FAILURE);
		}

		if (afReadFrames(file, AF_DEFAULT_TRACK, y, 1) != 1)
		{
			fprintf(stderr, "Could not read from test file.\n");
			exit(EXIT_FAILURE);
		}

		/*
			x is in big-endian byte order; make z a
			native-endian copy of x.
		*/
#ifdef WORDS_BIGENDIAN
		memcpy(z, x, 4);
#else
		z[0] = x[3];
		z[1] = x[2];
		z[2] = x[1];
		z[3] = x[0];
#endif

#ifdef DEBUG
		printf("x = %02x %02x %02x %02x\n", x[0], x[1], x[2], x[3]);
		printf("y = %02x %02x %02x %02x\n", y[0], y[1], y[2], y[3]);
		printf("z = %02x %02x %02x %02x\n", z[0], z[1], z[2], z[3]);
#endif

		/*
			Check to see that the data read from the file
			matches computed value.
		*/
		if (memcmp(y, z, 4) != 0)
		{
			fprintf(stderr, "Data read from file is incorrect.\n");
			exit(EXIT_FAILURE);
		}
	}

	/* Test virtual sample width of 32 bits. */
#ifdef DEBUG
	fprintf(stderr, "Testing virtual sample width of 32 bits.\n");
#endif
	afSeekFrame(file, AF_DEFAULT_TRACK, 0);
	afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 32);

	for (i=0; i<FRAME_COUNT; i++)
	{
		uint8_t	x[4];
		uint8_t	y[4];
		uint8_t	z[4];

		x[0] = (frames32[i] >> 16) & 0xff;
		x[1] = (frames32[i] >> 8) & 0xff;
		x[2] = (frames32[i]) & 0xff;
		x[3] = 0;

		/*
			Check to see that the precomputed values match
			what we've just computed.
		*/
		if (x[0] != frames24[3*i] ||
			x[1] != frames24[3*i + 1] ||
			x[2] != frames24[3*i + 2])
		{
			fprintf(stderr, "Data doesn't match pre-computed values.\n");
			exit(EXIT_FAILURE);
		}

		if (afReadFrames(file, AF_DEFAULT_TRACK, y, 1) != 1)
		{
			fprintf(stderr, "Could not read from test file.\n");
			exit(EXIT_FAILURE);
		}

		/*
			x is in big-endian byte order; make z a
			native-endian copy of x.
		*/
#ifdef WORDS_BIGENDIAN
		memcpy(z, x, 4);
#else
		z[0] = x[3];
		z[1] = x[2];
		z[2] = x[1];
		z[3] = x[0];
#endif

#ifdef DEBUG
		printf("x = %02x %02x %02x %02x\n", x[0], x[1], x[2], x[3]);
		printf("y = %02x %02x %02x %02x\n", y[0], y[1], y[2], y[3]);
		printf("z = %02x %02x %02x %02x\n", z[0], z[1], z[2], z[3]);
#endif

		/*
			Check to see that the data read from the file
			matches computed value.
		*/
		if (memcmp(y, z, 4) != 0)
		{
			fprintf(stderr, "Data read from file is incorrect.\n");
			exit(EXIT_FAILURE);
		}
	}

	if (afCloseFile(file) != 0)
	{
		fprintf(stderr, "Error closing file.\n");
		exit(EXIT_FAILURE);
	}
	unlink(testFileName);
	free(testFileName);

	exit(EXIT_SUCCESS);
}
/*
	Audio File Library

	Copyright (C) 2003, Michael Pruett <michael@68k.org>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	twentyfour2.c

	This program checks reading and writing a large amount of 24-bit
	audio data to an AIFF file.

	This program serves as a regression test for a bug in the Audio
	File Library in which requesting more than _AF_ATOMIC_NVFRAMES
	(1024 frames) from afReadFrames when reading a 24-bit audio file
	would result in corrupted audio data.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <audiofile.h>

#include "TestUtilities.h"

static char *sTestFileName;

#define FRAME_COUNT 10000

void cleanup (void)
{
	if (sTestFileName)
	{
#ifndef DEBUG
		unlink(sTestFileName);
#endif
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (void)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	int32_t		*buffer, *readbuffer;
	int		i;
	AFframecount	frameswritten, framesread;

	setup = afNewFileSetup();
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 24);

	ensure(createTemporaryFile("twentyfour2", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != NULL, "could not open test file for writing");

	afFreeFileSetup(setup);

	buffer = malloc(sizeof (int32_t) * FRAME_COUNT);
	ensure(buffer != NULL, "could not allocate buffer for audio data");

	readbuffer = malloc(sizeof (int32_t) * FRAME_COUNT);
	ensure(readbuffer != NULL, "could not allocate buffer for audio data");

	for (i=0; i<FRAME_COUNT; i++)
	{
		if ((i%3) == 0)
			buffer[i] = -i;
		else
			buffer[i] = i;
	}

	frameswritten = afWriteFrames(file, AF_DEFAULT_TRACK, buffer, FRAME_COUNT);
	ensure(frameswritten == FRAME_COUNT, "incorrect number of frames written");

	afCloseFile(file);

	/*
		Now open file for reading and ensure that the data read
		is equal to the data written.
	*/
	file = afOpenFile(sTestFileName, "r", AF_NULL_FILESETUP);
	ensure(file != NULL, "could not open test file for reading");

	framesread = afReadFrames(file, AF_DEFAULT_TRACK, readbuffer, FRAME_COUNT);
	ensure(framesread == FRAME_COUNT, "incorrect number of frames read");

#ifdef DEBUG
	for (i=0; i<FRAME_COUNT; i++)
	{
		if (buffer[i] != readbuffer[i])
		{
			printf("buffer[%d] = %d, readbuffer[%d] = %d\n",
				i, buffer[i], i, readbuffer[i]);
		}
	}
#endif

	ensure(!memcmp(buffer, readbuffer, sizeof (int32_t) * FRAME_COUNT),
		"data read does not match data written");

	afCloseFile(file);

	free(buffer);
	free(readbuffer);

	cleanup();
	return 0;
}
/*
	Audio File Library

	Copyright (C) 2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	writealaw.c

	The writealaw program performs sanity testing on the Audio File
	Library's G.711 A-law compression by writing and then reading
	back known data to a file to make sure the two sets of data agree.

	This program writes a set of data which is invariant under G.711
	A-law compression to a file and then reads that set of data back.

	The data read from that file should match the data written
	exactly.

	If this test fails, something in the Audio File Library is broken.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

static char *sTestFileName;

#define FRAME_COUNT 16
#define SAMPLE_COUNT FRAME_COUNT

void testalaw (int fileFormat);

void cleanup (void)
{
	if (sTestFileName)
	{
#ifndef DEBUG
		unlink(sTestFileName);
#endif
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (int argc, char **argv)
{
	printf("writealaw: testing NeXT .snd.\n");
	testalaw(AF_FILE_NEXTSND);
	printf("writealaw: testing AIFF-C.\n");
	testalaw(AF_FILE_AIFFC);
	printf("writealaw: testing WAVE.\n");
	testalaw(AF_FILE_WAVE);
	printf("writealaw: testing IRCAM.\n");
	testalaw(AF_FILE_IRCAM);
	printf("writealaw: testing VOC.\n");
	testalaw(AF_FILE_VOC);
	printf("writealaw: testing CAF.\n");
	testalaw(AF_FILE_CAF);

	printf("writealaw test passed.\n");

	exit(0);
}

void testalaw (int fileFormat)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	uint16_t	samples[] = {8, 24, 88, 120, 184, 784, 912, 976,
                        1120, 1440, 1888, 8960, 9984, 16128, 19968, 32256};
	uint16_t	readsamples[SAMPLE_COUNT];
	AFframecount	framesWritten, framesRead;
	int		i;

	setup = afNewFileSetup();

	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_G711_ALAW);
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	ensure(createTemporaryFile("writealaw", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	afFreeFileSetup(setup);

	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
		AF_COMPRESSION_G711_ALAW,
		"test file not created with G.711 A-law compression");

	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		FRAME_COUNT);

	ensure(framesWritten == FRAME_COUNT,
		"number of frames requested does not match number of frames written");
	afCloseFile(file);

	/* Open the file for reading and verify the data. */
	file = afOpenFile(sTestFileName, "r", NULL);
	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");

	ensure(afGetFileFormat(file, NULL) == fileFormat,
		"test file format incorrect");

	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
		AF_COMPRESSION_G711_ALAW,
		"test file not opened with G.711 A-law compression");

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
		FRAME_COUNT);

	ensure(framesRead == FRAME_COUNT,
		"number of frames read does not match number of frames requested");

#ifdef DEBUG
	for (i=0; i<SAMPLE_COUNT; i++)
		printf("readsamples[%d]: %d\n", i, readsamples[i]);
	for (i=0; i<SAMPLE_COUNT; i++)
		printf("samples[%d]: %d\n", i, samples[i]);
#endif

	for (i=0; i<SAMPLE_COUNT; i++)
	{
		ensure(samples[i] == readsamples[i],
			"data written does not match data read");
	}

	/* G.711 compression uses one byte per sample. */
	ensure(afGetTrackBytes(file, AF_DEFAULT_TRACK) == SAMPLE_COUNT,
		"track byte count is incorrect");

	ensure(afGetFrameCount(file, AF_DEFAULT_TRACK) == FRAME_COUNT,
		"frame count is incorrect");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
		"channel count is incorrect");

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();
}
/*
	Audio File Library

	Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
	Copyright (C) 2002, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	writeraw.c

	This program tests the validity of the AIFF file reading and writing
	code.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

static char *sTestFileName;

void cleanup (void)
{
	if (sTestFileName)
	{
#ifndef DEBUG
		unlink(sTestFileName);
#endif
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (int argc, char **argv)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	uint16_t	samples[] = {11, 51, 101, 501, 1001, 5001, 10001, 50001};
	int		i;
	int		sampleFormat, sampleWidth;
	int		framesRead, framesWritten;
	int		nativeByteOrder;

#ifdef WORDS_BIGENDIAN
	nativeByteOrder = AF_BYTEORDER_BIGENDIAN;
#else
	nativeByteOrder = AF_BYTEORDER_LITTLEENDIAN;
#endif

	setup = afNewFileSetup();
	afInitFileFormat(setup, AF_FILE_RAWDATA);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);
	afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);

	ensure(createTemporaryFile("writeraw", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples, 8);
	ensure(framesWritten == 8,
		"number of frames written does not match number of frames requested");

	ensure(afCloseFile(file) == 0, "error closing file");

	file = afOpenFile(sTestFileName, "r", setup);
	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");
	afFreeFileSetup(setup);

	ensure(afGetFileFormat(file, NULL) == AF_FILE_RAWDATA,
		"test file not created as raw audio data file");

	afGetSampleFormat(file, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
	ensure(sampleFormat == AF_SAMPFMT_TWOSCOMP,
		"test file not two's complement");
	ensure(sampleWidth == 16,
		"test file sample format is not 16-bit");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
		"test file doesn't have exactly one channel");

	ensure(afGetByteOrder(file, AF_DEFAULT_TRACK) == nativeByteOrder,
		"test file not in native byte order");

	for (i=0; i<8; i++)
	{
		uint16_t	temporary;

		framesRead = afReadFrames(file, AF_DEFAULT_TRACK, &temporary, 1);
		ensure(framesRead == 1,
			"number of frames read does not match number of frames requested");

		ensure(temporary == samples[i],
			"data written to file doesn't match data read from file");
	}

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();

	printf("writeraw test passed.\n");

	exit(EXIT_SUCCESS);
}
/*
	Audio File Library

	Copyright (C) 2000, Michael Pruett <michael@68k.org>
	Copyright (C) 2001, Silicon Graphics, Inc.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
	writeulaw.c

	The writeulaw program performs sanity testing on the Audio File
	Library's G.711 u-law compression by writing and then reading
	back known data to a file to make sure the two sets of data agree.

	This program writes a set of data which is invariant under G.711
	u-law compression to a file and then reads that set of data back.

	The data read from that file should match the data written
	exactly.

	If this test fails, something in the Audio File Library is broken.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef __USE_SGI_HEADERS__
#include <dmedia/audiofile.h>
#else
#include <audiofile.h>
#endif

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "TestUtilities.h"

static char *sTestFileName;

#define FRAME_COUNT 16
#define SAMPLE_COUNT FRAME_COUNT

void testulaw (int fileFormat);

void cleanup (void)
{
	if (sTestFileName)
	{
#ifndef DEBUG
		unlink(sTestFileName);
#endif
		free(sTestFileName);
	}
}

void ensure (int condition, const char *message)
{
	if (!condition)
	{
		printf("%s.\n", message);
		cleanup();
		exit(EXIT_FAILURE);
	}
}

int main (int argc, char **argv)
{
	printf("writeulaw: testing NeXT .snd.\n");
	testulaw(AF_FILE_NEXTSND);
	printf("writeulaw: testing AIFF-C.\n");
	testulaw(AF_FILE_AIFFC);
	printf("writeulaw: testing WAVE.\n");
	testulaw(AF_FILE_WAVE);
	printf("writeulaw: testing IRCAM.\n");
	testulaw(AF_FILE_IRCAM);
	printf("writeulaw: testing VOC.\n");
	testulaw(AF_FILE_VOC);
	printf("writeulaw: testing CAF.\n");
	testulaw(AF_FILE_CAF);

	printf("writeulaw test passed.\n");

	exit(0);
}

void testulaw (int fileFormat)
{
	AFfilehandle	file;
	AFfilesetup	setup;
	uint16_t	samples[] = {8, 16, 80, 120, 180, 780, 924, 988,
			1116, 1436, 1884, 8828, 9852, 15996, 19836, 32124};
	uint16_t	readsamples[SAMPLE_COUNT];
	AFframecount	framesWritten, framesRead;
	int		i;

	setup = afNewFileSetup();

	afInitCompression(setup, AF_DEFAULT_TRACK, AF_COMPRESSION_G711_ULAW);
	afInitFileFormat(setup, fileFormat);
	afInitChannels(setup, AF_DEFAULT_TRACK, 1);

	ensure(createTemporaryFile("writeulaw", &sTestFileName),
		"could not create temporary file");
	file = afOpenFile(sTestFileName, "w", setup);
	afFreeFileSetup(setup);

	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
		AF_COMPRESSION_G711_ULAW,
		"test file not created with G.711 u-law compression");

	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for writing");

	framesWritten = afWriteFrames(file, AF_DEFAULT_TRACK, samples,
		FRAME_COUNT);

	ensure(framesWritten == FRAME_COUNT,
		"number of frames requested does not match number of frames written");
	afCloseFile(file);

	/* Open the file for reading and verify the data. */
	file = afOpenFile(sTestFileName, "r", NULL);
	ensure(file != AF_NULL_FILEHANDLE, "unable to open file for reading");

	ensure(afGetFileFormat(file, NULL) == fileFormat,
		"test file format incorrect");

	ensure(afGetCompression(file, AF_DEFAULT_TRACK) ==
		AF_COMPRESSION_G711_ULAW,
		"test file not opened with G.711 u-law compression");

	framesRead = afReadFrames(file, AF_DEFAULT_TRACK, readsamples,
		FRAME_COUNT);

	ensure(framesRead == FRAME_COUNT,
		"number of frames read does not match number of frames requested");

#ifdef DEBUG
	for (i=0; i<SAMPLE_COUNT; i++)
		printf("readsamples[%d]: %d\n", i, readsamples[i]);
	for (i=0; i<SAMPLE_COUNT; i++)
		printf("samples[%d]: %d\n", i, samples[i]);
#endif

	for (i=0; i<SAMPLE_COUNT; i++)
	{
		ensure(samples[i] == readsamples[i],
			"data written does not match data read");
	}

	/* G.711 compression uses one byte per sample. */
	ensure(afGetTrackBytes(file, AF_DEFAULT_TRACK) == SAMPLE_COUNT,
		"track byte count is incorrect");

	ensure(afGetFrameCount(file, AF_DEFAULT_TRACK) == FRAME_COUNT,
		"frame count is incorrect");

	ensure(afGetChannels(file, AF_DEFAULT_TRACK) == 1,
		"channel count is incorrect");

	ensure(afCloseFile(file) == 0, "error closing file");

	cleanup();
}