Initial commit

This commit is contained in:
Jonathan Ervine 2020-12-14 13:35:27 +08:00
parent 464d2aceed
commit 62b2a5c57c
34 changed files with 27932 additions and 2 deletions

90
CMakeLists.txt Normal file
View File

@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.17)
project(AtomicParsley)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
find_program(GIT git)
if(GIT)
execute_process(
COMMAND "${GIT}" "show" "-s" "--format=%H;%cd" "--date=format:%Y%m%d.%H%M%S.0"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE git_result
OUTPUT_VARIABLE git_data
ERROR_VARIABLE git_err
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(git_result EQUAL 0)
list(GET git_data 0 BUILD_INFO)
list(GET git_data 1 PACKAGE_VERSION)
endif()
endif()
include(CheckSymbolExists)
check_symbol_exists(strsep "string.h" HAVE_STRSEP)
if(HAVE_STRSEP)
add_definitions(-DHAVE_STRSEP)
endif()
add_definitions(
-DPACKAGE_VERSION="${PACKAGE_VERSION}"
-DBUILD_INFO="${BUILD_INFO}"
-D_FILE_OFFSET_BITS=64
)
find_package(ZLIB)
if(ZLIB_FOUND)
include_directories(${ZLIB_INCLUDE_DIRS})
add_definitions(-DHAVE_ZLIB_H)
endif()
list(APPEND sources
src/CDtoc.cpp
src/arrays.cpp
src/compress.cpp
src/extracts.cpp
src/iconv.cpp
src/id3v2.cpp
src/main.cpp
src/metalist.cpp
src/parsley.cpp
src/sha1.cpp
src/util.cpp
src/uuid.cpp
)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list(APPEND sources
src/nsfile.mm
src/nsimage.mm
)
endif()
if(WIN32)
list(APPEND sources
src/extras/getopt.c
src/extras/getopt1.c
)
endif()
add_executable(
AtomicParsley
${sources}
)
if(ZLIB_FOUND)
target_link_libraries(
AtomicParsley
${ZLIB_LIBRARIES}
)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_link_libraries(
AtomicParsley
"-framework Cocoa"
"-framework Foundation"
"-framework IOKit"
)
endif()

280
COPYING Normal file
View File

@ -0,0 +1,280 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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

48
CREDITS Normal file
View File

@ -0,0 +1,48 @@
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C) 2005-2007, puck_lock
Copyright (C) 2009-2012, Wez Furlong
Copyright (C) 2010-2012, Oleg Oshmyan
Copyright (C) 2009, 2011, Santino Fuentes
Copyright (C) 2011, John D Pell
Copyright (C) 2010, Edriss Mirzadeh
Copyright (C) 2009, Josh Aune
Copyright (C) 2014, Paul Foose
Miscellaneous Contributions made at unknown (to the current maintainers) times,
except that the changes are presumably circa 2005-2007:
* Mellow_Flow
* Mike Brancato
* Brian Story
* Lowell Stewart
* SLarew
Contains code derived from code that is:
Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
(See iconv.cpp for license)
Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" <duerst@w3.org>
Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
Authors: Scott G. Miller, Robert Klep <robert@ilse.nl>
(See sha1.cpp)
Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
Digital Equipment Corporation, Maynard, Mass.
Copyright (c) 1998 Microsoft.
(See uuid.cpp)

536
Changes.txt Normal file
View File

@ -0,0 +1,536 @@
v0.1 10/05/2005
Parsing of atoms
intial Tree printout
extraction of all "covr.data" atoms out
to files
v0.2 11/10/2005
AtomicInfo.NextAtomNumber introduced to facilitate dynamic atom tree
reorganization
CreateSparseAtom added
v0.5 11/22/2005
Writes artist properly of variable lengths properly into an iTMS m4p file
properly (other files don't fare well due to the stsd atom non-standard
nature)
a number of code-uglifying workarounds were employed to get get that
far;
v0.6 11/25/2005
Added genre string/numerical support, support for genre's dual-atom ©gen/gnre
nature, genre string->integer
bug fixes to APar_LocateAtomInsertionPoint when
an atom is missing
APar_CreateSparseAtom for ordinary non-data atoms are now
type -1 (which means they aren't of any interest to us besides length & name);
implemnted the Integer data class
char4short
verified iTunes standard genres
only go up to "Hard Rock"
added jpg/png artwork embedding into "covr" atoms;
slight bugfix for APar_FindAtom (created spurious trailing "covr" atoms).
v0.6 GPL'ed at sourceforge.net
v0.65 11/25/2005
bugfixes to newly introduced bugs in APar_FindAtom
metaEnema to remove all
metadata (safe even for m4p drm files)
year implemented properly (tagtime
moved onto non-standard 'tdtg' atom ala id3v2.4 - because I like that tag);
added setting compilation "cpil" tag (an annoying 5byte tag)
added advisory
setting (maybe it'll give me a kick one cold winter day-do a "Get Info" in
iTunes & in the main "Summary" tab view will be a new little icon next to
artwork)
v0.7 11/26/2005
added a writeBack flag to for a less beta-like future
integrated NSImage
resizing of artwork
environmental preferences for artwork modifications
build
system mods for Mac-specific compiling
v0.7.1 11/27/2005
modified parsing & writing to support Apple Lossless (alac) mp4 files. The
lovely "alac.alac" non-standard atoms (parents & carry data) caused unplayable
files to be written. Only QT ISMA files get screwed now (no idea about Nero)
v0.7.2 11/29/2005
creates iTunes-required meta.hdlr
all the tags now get spit back when reading
them (--textdata)
slight fix to how atoms are parsed
all known m4a files now
tag properly: iTunes (m4a, m4b, chapterized, alac), Quicktime (ISMA & mpeg4 -
change filename ext to .m4a to see art
all QT products require the meta.hdlr
addition), faac, Helix Producer & Nero
slight change to how PrintDataAtoms
called FindParentAtom
added tag time on "©ed1" (edit date-might only really
belong directly under udta)
added "©url" to hold url
fixes to
APar_RemoveAtom
added cli ability to remove all artwork
v0.7.3 12/02/2005
handles stsd (and child) atoms better
modifies all stco offsets when needed
(not just the first)
new oddball iTMS video "drmi" atom handling
new "stik"
atom support (sets iTunes GetInfo->options:Movie,TV Show, Music Video)
writes
iTMS video drm TV shows well now
diffs in a hex editor are moov atom length,
and then into stco, so all is well
v0.7.4 12/03/2005
"desc", "tvnn", "tvsh", "tven" & "tves" setting
v0.7.5b 12/09/2005
forced 'mdat' into being childless (chapterized mpeg4 files have atoms
scattered througout mdat, but they aren't children)
fixed issues with ffmpeg
created mpeg4 files (that have mdat as 2nd atom
moov & chilren as last atoms);
moved ffmpeg mdat atoms around to end
better atom adding at the end
subbed
getopt_long_only to getopt_long for pre-10.4 users
added progressbar
v0.7.5c 12/10/2005
funnguy0's linux patches (thanks so much for that)
v0.7.5d 12/11/2005
endian issues for x86 mostly resolved
setting genre's segfaults
stik doesn't
get set in a multi-option command, but does as a single atom setting
Debian
port added to binaries (compiled under debian-31r0a-i386 with g++4.02-2,
libc6_2.3.5-8 & libstdc++6_4.0.2-2) - under VirtualPC - with the nano editor!
v0.7.5e 12/16/2005
ammends how atoms are added at the end of the hierarchy (notably this affects
ffmpeg video files)
writes "keyw", "catg", "pcst", "aART" atoms
read-only
"purl" & "egid" added
v0.7.6 12/31/2005
ceased flawed null-termination (which was implemented more in my mind) of text
'data' atoms
UTF-8 output on Mac OS X & Linux - comment in DUSE_ICONV_CONVERSION in the
build file to test it other platforms (maybe my win98Se isn't utf8 aware?)
cygwin build accommodations
fix to the secondary "of" number for track/disk on non-PPC
implemented user-defined completely sanctioned 'uuid' atoms to hold....
anything (text only for now)
"--tagtime", "--url" & "--information" now get set onto uuid atoms
allow creation of uuid atoms directly from the cli
cygwin-win98SE port added to binary releases
added '--freefree' to remove any&all 'free' atoms
v0.8 01/14/2006
switched over to uint8_t for former ADC_CPIL_TMPO & former ADC_Integer
added podcast stik setting & purl/egid
bugfixes to APar_RemoveAtom
bugfixes & optimizations to APar_FindAtom
changes to text output & set values for stik atom
increase in buffer size
limit non-uuid strings to 255bytes
fixed retreats in progress bar
added purd atom
support mdat.length=0 atom (length=1/64-bit isn't supported
I'll somehow cope with a < 4GB file)
switch from long to uint32_t
better x86 bitshifting
added swtich to prevent moving mdat atoms (possible PSP requires mdat before
moov)
universal binary for Mac OS X release
no text limit on lyrics tag
v0.8.4 02/25/2006
fixed an imaging bug from preferences
fixed metaEnema screwing up the meta atom (APar_RemoveAtom bugfix to remove a
direct_find atom)
added --output, --overWrite
added --metaDump to dump ONLY metadata tags to a file
versioning for cvs builds
limited support for 64-bit mdat atoms (limited to a little less than a 32-bit
atom > 4GB)
bugfixes to APar_RemoveAtom for removing uuid atoms or non-existing atoms & to
delete all artwork, then add in 1 command ("--artwork REMOVE_ALL --artwork
/path --artwork /path")
support 64-bit co64 atom
support MacOSX-style type/creator codes for tempfiles that end in ".mp4" (no
need to change extn to ".m4v"/".m4a" anymore)
moved purl/egid onto AtomicDataClass_UInteger (0x00 instead of 0x15) to mirror
Apple's change on these tags
start incorporating Brian's Win32 fixes (if you malloc, memset is sure to
follow fopen)
give the 'name' atom for '---' iTunes-internal tags for metadata printouts
allow --freefree remove 'free's up to a certain level (preserves iTunes
padding)
squash some memory leaks
change how CreateSparseAtom was matching atoms to accommodate EliminateAtom-ed
atoms (facilitates the previous artwork amendments)
exit on unsupported 'ftyp' file brands
anonymous 3rd party native win32 contributions
reworked APar_DetermineAtomLengths to accommodate proper tag setting with
--mdatLock
parsing atoms under 'stsd' is no longer internally used - only for tree
printing
reworked Mac OS X TYPE determination based on new stsd_codec structure member
revisit co64 offset calculations
start extracting track-level details (dates, language, encoder, channels)
changed stco/co64 calculations to support non-muxed files
anonymous "Everyday is NOT like Sunday" contribution
changed unknown 0x15 flagged metadata atoms to hex printouts
move mdat only when moov precedes mdat
new flexible esds parsing
v0.8.8 05/21/2006
prevent libmp4v2 artwork from a hexdump
changed how short strings were set
win32 change for uuid atoms to avoid sprintf
skip parsing 'free' atoms
work around foobar2000 0.9 non-compliant tagging scheme & added cli switch to
give 'tags' the GoLytely - aka '--foobar2000Enema'
ability to read/set completely separate 3gp tags subset (3GPP TS 26.444 version
6.4.0 Release 6 compliant & more like QuickTime-style tags)
added libxml's utf8 & utf16 conversion functions
new windows (windows2000 & later) unicode (utf16) console output (literal utf8
bytes in win98 & earlier
memset standard means of initializing
simplified setting of arbitrary info uniformly onto parsedAtoms.AtomicData
win32 switch to CP_UTF8 codepage on redirected console output for better
unicode output support
eliminate need for libiconv - use xml's utf8<->latin1 functions to supplant
libiconv
properly display atoms like '©nam' under Windows for trees & atom printouts
support setting unicode on Windows CP_UTF8
added 3GP keyword
fixed bug removing last 3GP asset to reset the length of 'udta'
added 'manualAtomRemove' for manually removing iTunes-style atoms
improved tracking of filesize/percentage when large free atoms impinge on % of
new filesize
added 3GP location 'loci' (El Loco) atom - all known 3GP assets can now be
set/viewed (except support for multiple same atoms of different languages)
->forced<- elimination of Nero tagging scheme (their foobar2000 inspired 'tags'
atom) on 3GP files
prevent iTunes-style tags on 3GP files or 3GP assets on MPEG-4 files
fix offsets in fragmented files ("moof.traf.tfhd") up MAX_ATOMS to 1024
Windows support for full utf16 (unicode) for cli args & filenames
v0.9.0 09/15/2006
new file scanning method based on an array of known atoms/KnownAtoms struct
added to list the gamut of known atoms & their basic properties
better atom versioning & flags support
allow negatives in 3gp asset coordinates (switch to high-bit ascii for
getopt_long for assets)
fixed minor bug that crept in on non-Win systems in removing files
switch from moving mdat(s) to moving moov to reorder atoms
mellow_flow's genre fix
SLarew's utf16 fix for printing 3gp assets on Win32
reorder moov's child atoms so that udta is last (as per ISO spec
recommendations) in moov
enable use of 'free' atom padding for rapid updating, pad with a (user-defined)
default amount of padding with a complete file rewrite
switch remaining AtomicInfo variables over to pointers
add support for multiple same atoms with differing languages (like 3gp assets);
more flexible 'stik' setting/retrieving & added Audiobook
genre bugfix (again!!)
added ability to list std genres & stik strings
switch output for rtng's "Lyrics" to "Content"
list file brands
bugfix for removing some cli metadata
prevent optimizing on PSP mpeg-4 files (but allow dynamic updating, and don't
add padding to psp files)
new APar_FindAtom routine eliminating some loops
updated routine to find 'moov.udta.meta.hdlr' or iTunes-style tagging
simplified APar_RemoveAtom
3gp assets differing in language are grouped now instead of being fifo
simplified printing of non-string iTunes-style tags
work around 3rd party bug affecting 'cprt' corruption
switch to fseeko to support files between 2.5GB & 4GB (and ancillary routines
off of filesize like progress bar)
fix co64 reduction offsets
prevent optimizing when just getting a tree or tags (screwed up track level
details)
bashfulbladder's booklet stik, only allow dynamic updating with --overWrite &
new "AP -t +" routine to show padding & supplemental info
changing win32 filename to '-utf8.exe' forces raw utf8 input/output
win32 longhelp is converted to utf16 (for atom names)
new shorthelp added as default help page
bugfix removing non-existing atoms
an actual change (removal/addition/change) of an atom is now required for any
type of write action
fix channel listing for 'esds' without sec5 info
added ability to force image dimensions on MacOSX
revamped track level details
255 byte limit for strings changed to 255 utf8 *character* limit
--stik Audiobook now changes file extension to '.m4b' (for Mac OS X, finder
Type code is changed to 'M4B ' too)
fix --3gp-year "" in APar_RemoveAtom
bugfix setting string lengths in 3gp keyword
added ability to add ISO 'cprt' copyright at movie or track level
implemented v5 sha1 namepsace/name uuids
fixed crash on finding any atom with full uuids (like psp files)
more extensive type/profiles/levels in track level details
add support for embedding files on uuid atoms
switch to reading artwork directly into memory (as opposed to copying from
a->b) when setting artwork
modified ExtractPixPrefs for leaks - defaults now to deleting temp pic files
skip sprintf for uuid binary strings ('qlts' is why) & switch to (less
flexible) memcpy
accommodate iTunes 7.0 adding aprox. 2k of NULL bytes outside of any atom
structure
add 'pgap' atom
defaults to duplicating the gapless padding at the end of file now (but can be
optionally skipped)
fixed clipping when setting unicode characters
v0.9.X ??/??/2007
now checks/lists 3 letter language codes
allow setting 3gp assets at track level
fix double fclose & relative paths with --overWrite
coalesce iso copyright notices into the new APar_UserData_atom_Init
initial support for setting iTunes reverseDNS atoms
fix validation test for 'trak' child atoms for atypical order
add mjpeg2000 (mjp2) major brand support (for copyright notices & uuid atoms)
restyled listings of all text metadata tags (-t 1)
fix multiple BOM prints on printouts
limit offset adjustments to local (non-external) data
added support for adjusting item location offsets
switch to a makefile/configure/config.h build system
start of ID3v2 2.4 implementation to go into ID32 atoms
limit chunk offset updates to local data
extend atom creation to file level (FL meta gets created after 'moov')
much of ID3v2 2.4 is completed: multiple text fields, counters, APIC/GEOB
setting/extracting, group symbols & zlib compression
add 3gp7 brands
allow ID32 based on compatible ftyp branding
refactoring & splitting of metadata listings
allow multiple entries in reverseDNS atoms (excepting iTunes domain)
initial (unfinished) revisit of file reorganizing/padding
update mvhd/tkhd modification timestamps
v0.9.6 02/22/2014
update for iTunes 11 compatibility
if stik "Movie" is used, set value to 9, instead of 0
iTunes now views stick value 0 as "Home Video"
left "Short Film" to also set stik 9, for backward compatibility with work-arounds using "Short Film" to set stik to 9
Swapped TV-Y and TV-Y7 to conform with iTunes usage.

View File

@ -1,3 +1,56 @@
# atomicparsley
# AtomicParsley
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wez/atomicparsley/CI)
## Installation
### macOS
* Navigate to the [latest release](https://github.com/wez/atomicparsley/releases/latest)
* Download the `AtomicParsleyMacOS.zip` file and extract `AtomicParsley`
### Windows
* Navigate to the [latest release](https://github.com/wez/atomicparsley/releases/latest)
* Download the `AtomicParsleyWindows.zip` file and extract `AtomicParsley.exe`
### Building from Source
If you are building from source you will need `cmake` and `make`.
On Windows systems you'll need Visual Studio or MingW.
```
cmake .
cmake --build . --config Release
```
will generate an `AtomicParsley` executable.
### Dependencies:
zlib - used to compress ID3 frames & expand already compressed frames
available from http://www.zlib.net
## A note on maintenance!
> I made some fixes to the original project on sourceforge back in
> in 2009 and became the de-facto fork of AtomicParsley as a
> result. However, I haven't used this tool myself in many years and have
> acted in a very loose guiding role since then.
>
> In 2020 Bitbucket decided to cease hosting Mercurial based repositories
> which meant that I had to move it in order to keep it alive, so you'll
> see a flurry of recent activity.
>
> I'll consider merging pull requests if they are easy to review, but because
> I don't use this tool myself I have no way to verify complex changes.
> If you'd like to make such a change, please consider contributing some
> kind of basic automated test with a corresponding small test file.
>
> This repo has GitHub Actions enabled for the three major platforms
> so bootstrapping some test coverage is feasible.
>
> You are welcome to report issues using the issue tracker, but I am
> unlikely to act upon them.
atomicparsley repo (used for Alpine Linux)

9
src/.clang-format Normal file
View File

@ -0,0 +1,9 @@
---
BasedOnStyle: LLVM
IndentWidth: 2
BinPackArguments: false
BinPackParameters: false
IncludeIsMainRegex: AtomicParse
---
Language: Cpp
---

389
src/AtomDefs.h Normal file
View File

@ -0,0 +1,389 @@
//==================================================================//
/*
AtomicParsley - AtomDefs.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "AtomicParsley.h"
atomDefinition KnownAtoms[] = {
// name parent atom(s) container
// number
// box_type
{"<()>",
{"_ANY_LEVEL"},
UNKNOWN_ATOM_TYPE,
UKNOWN_REQUIREMENTS,
UNKNOWN_ATOM}, // our unknown atom (self-defined)
{"ftyp", {"FILE_LEVEL"}, CHILD_ATOM, REQUIRED_ONCE, SIMPLE_ATOM},
{"moov", {"FILE_LEVEL"}, PARENT_ATOM, REQUIRED_ONCE, SIMPLE_ATOM},
{"mdat", {"FILE_LEVEL"}, CHILD_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"pdin", {"FILE_LEVEL"}, CHILD_ATOM, OPTIONAL_ONCE, VERSIONED_ATOM},
{"moof", {"FILE_LEVEL"}, PARENT_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"mfhd", {"moof"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"traf", {"moof"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tfhd", {"traf"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"trun", {"traf"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"mfra", {"FILE_LEVEL"}, PARENT_ATOM, OPTIONAL_ONCE, SIMPLE_ATOM},
{"tfra", {"mfra"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"mfro", {"mfra"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"free", {"_ANY_LEVEL"}, CHILD_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"skip", {"_ANY_LEVEL"}, CHILD_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"uuid", {"_ANY_LEVEL"}, CHILD_ATOM, REQUIRED_ONCE, EXTENDED_ATOM},
{"mvhd", {"moov"}, CHILD_ATOM, REQUIRED_ONCE, VERSIONED_ATOM},
{"iods", {"moov"}, CHILD_ATOM, OPTIONAL_ONCE, VERSIONED_ATOM},
{"drm ",
{"moov"},
CHILD_ATOM,
OPTIONAL_ONCE,
VERSIONED_ATOM}, // 3gp/MobileMP4
{"trak", {"moov"}, PARENT_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"tkhd", {"trak"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"tref", {"trak"}, PARENT_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"mdia", {"trak"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tapt", {"trak"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"clef", {"tapt"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"prof", {"tapt"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"enof", {"tapt"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"mdhd", {"mdia"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"minf", {"mdia"}, PARENT_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"hdlr",
{"mdia", "meta", "minf"},
CHILD_ATOM,
REQUIRED_ONE,
VERSIONED_ATOM}, // minf parent present in chapterized
{"vmhd", {"minf"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"smhd", {"minf"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"hmhd", {"minf"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"nmhd", {"minf"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"gmhd",
{"minf"},
CHILD_ATOM,
REQ_FAMILIAL_ONE,
VERSIONED_ATOM}, // present in chapterized
{"dinf",
{"minf", "meta"},
PARENT_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, // required in minf
{"dref", {"dinf"}, DUAL_STATE_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"url ", {"dref"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"urn ", {"dref"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"alis", {"dref"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"cios", {"dref"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"stbl", {"minf"}, PARENT_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"stts", {"stbl"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"ctts", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"stsd", {"stbl"}, DUAL_STATE_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"stsz", {"stbl"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"stz2", {"stbl"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"stsc", {"stbl"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"stco", {"stbl"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"co64", {"stbl"}, CHILD_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"stss", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"stsh", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"stdp", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"padb", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"sdtp", {"stbl", "traf"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"sbgp", {"stbl", "traf"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"sbgp", {"stbl"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"stps", {"stbl"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"edts", {"trak"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"elst", {"edts"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"udta", {"moov", "trak"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"meta",
{"FILE_LEVEL", "moov", "trak", "udta"},
DUAL_STATE_ATOM,
OPTIONAL_ONE,
VERSIONED_ATOM}, // optionally contains info
{"mvex", {"moov"}, PARENT_ATOM, OPTIONAL_ONCE, SIMPLE_ATOM},
{"mehd", {"mvex"}, CHILD_ATOM, OPTIONAL_ONCE, VERSIONED_ATOM},
{"trex", {"mvex"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
//{"stsl", {"????"}, CHILD_ATOM,
// OPTIONAL_ONE,
// VERSIONED_ATOM }, //contained by a sample
// entry
// box
{"subs", {"stbl", "traf"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"xml ", {"meta"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"bxml", {"meta"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"iloc", {"meta"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"pitm", {"meta"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"ipro", {"meta"}, PARENT_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"iinf", {"meta"}, DUAL_STATE_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"infe", {"iinf"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"sinf",
{"ipro", "drms", "drmi"},
PARENT_ATOM,
REQUIRED_ONE,
SIMPLE_ATOM}, // parent atom is also "Protected Sample Entry"
{"frma", {"sinf"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"imif", {"sinf"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"schm", {"sinf", "srpp"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"schi", {"sinf", "srpp"}, DUAL_STATE_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"skcr", {"sinf"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"user", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"key ",
{"schi"},
CHILD_ATOM,
OPTIONAL_ONE,
VERSIONED_ATOM}, // could be required in 'drms'/'drmi'
{"iviv", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"righ", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"name", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"priv", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"iKMS",
{"schi"},
CHILD_ATOM,
OPTIONAL_ONE,
VERSIONED_ATOM}, // 'iAEC', '264b', 'iOMA', 'ICSD'
{"iSFM", {"schi"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"iSLT",
{"schi"},
CHILD_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, // boxes with 'k***' are also here; reserved
{"IKEY", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"hint", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"dpnd", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"ipir", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"mpod", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"sync", {"tref"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"chap",
{"tref"},
CHILD_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, //?possible versioned?
{"ipmc", {"moov", "meta"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM},
{"tims", {"rtp "}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"tsro", {"rtp "}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"snro", {"rtp "}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"srpp", {"srtp"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"hnti", {"udta"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"rtp ",
{"hnti"},
CHILD_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, //'rtp ' is defined twice in different containers
{"sdp ", {"hnti"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"hinf", {"udta"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"name", {"udta"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"trpy", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"nump", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tpyl", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"totl", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"npck", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"maxr", {"hinf"}, CHILD_ATOM, OPTIONAL_MANY, SIMPLE_ATOM},
{"dmed", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"dimm", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"drep", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tmin", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tmax", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"pmax", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"dmax", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"payt", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"tpay", {"hinf"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"drms", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"drmi", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"alac", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"mp4a", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"mp4s", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"mp4v", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"avc1", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"avcp", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"text", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"jpeg", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"tx3g", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"rtp ",
{"stsd"},
DUAL_STATE_ATOM,
REQ_FAMILIAL_ONE,
VERSIONED_ATOM}, //"rtp " occurs twice; disparate meanings
{"srtp", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, SIMPLE_ATOM},
{"enca", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"encv", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"enct", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"encs", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"samr", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"sawb", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"sawp", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"s263", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"sevc", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"sqcp", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"ssmv", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"tmcd", {"stsd"}, DUAL_STATE_ATOM, REQ_FAMILIAL_ONE, VERSIONED_ATOM},
{"mjp2",
{"stsd"},
DUAL_STATE_ATOM,
REQ_FAMILIAL_ONE,
VERSIONED_ATOM}, // mjpeg2000
{"alac", {"alac"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"avcC", {"avc1", "drmi"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"damr", {"samr", "sawb"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"d263", {"s263"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"dawp", {"sawp"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"devc", {"sevc"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"dqcp", {"sqcp"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"dsmv", {"ssmv"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"bitr", {"d263"}, CHILD_ATOM, REQUIRED_ONE, SIMPLE_ATOM},
{"btrt",
{"avc1"},
CHILD_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, // found in NeroAVC
{"m4ds",
{"avc1"},
CHILD_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, //?possible versioned?
{"ftab", {"tx3g"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM},
{"jp2h", {"mjp2"}, PARENT_ATOM, OPTIONAL_ONE, SIMPLE_ATOM}, // mjpeg2000
{"ihdr", {"jp2h"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM}, // mjpeg2000
{"colr", {"jp2h"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM}, // mjpeg2000
{"fiel", {"mjp2"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM}, // mjpeg2000
{"jp2p", {"mjp2"}, CHILD_ATOM, OPTIONAL_ONE, VERSIONED_ATOM}, // mjpeg2000
{"jsub", {"mjp2"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM}, // mjpeg2000
{"orfo", {"mjp2"}, CHILD_ATOM, OPTIONAL_ONE, SIMPLE_ATOM}, // mjpeg2000
{"cprt",
{"udta"},
CHILD_ATOM,
OPTIONAL_MANY,
PACKED_LANG_ATOM}, // the only ISO defined metadata tag; also a 3gp asset
{"titl",
{"udta"},
CHILD_ATOM,
OPTIONAL_MANY,
PACKED_LANG_ATOM}, // 3gp assets
{"auth", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"perf", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"gnre", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"dscp", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"albm", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"yrrc", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, VERSIONED_ATOM},
{"rtng", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"clsf", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"kywd", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"loci", {"udta"}, CHILD_ATOM, OPTIONAL_MANY, PACKED_LANG_ATOM},
{"ID32",
{"meta"},
CHILD_ATOM,
OPTIONAL_MANY,
PACKED_LANG_ATOM}, // id3v2 tag
{"tsel",
{"udta"},
CHILD_ATOM,
OPTIONAL_MANY,
SIMPLE_ATOM}, // but only at track level in a 3gp file
//{"chpl", {"udta"}, CHILD_ATOM,
// OPTIONAL_ONCE,
// VERSIONED_ATOM }, //Nero - seems to be versioned
//{"ndrm", {"udta"}, CHILD_ATOM,
// OPTIONAL_ONCE,
// VERSIONED_ATOM }, //Nero - seems to be versioned
//{"tags", {"udta"}, CHILD_ATOM,
// OPTIONAL_ONCE,
// SIMPLE_ATOM }, //Another Nero-Creationª
// ...so if they claim that "tags doesn't have any children",
// why does nerotags.exe say "tshd atom"? If 'tags' doesn't
// have any children, then tshd can't be an atom....
// Clearly, they are EternallyRightª and everyone else is
// always wrong.
// Pish! Seems that Nero is simply unable to register any atoms.
{"ilst",
{"meta"},
PARENT_ATOM,
OPTIONAL_ONCE,
SIMPLE_ATOM}, // iTunes metadata container
{"----",
{"ilst"},
PARENT_ATOM,
OPTIONAL_MANY,
SIMPLE_ATOM}, // reverse dns metadata
{"mean", {"----"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{"name", {"----"}, CHILD_ATOM, REQUIRED_ONE, VERSIONED_ATOM},
{".><.",
{"dref"},
CHILD_ATOM,
OPTIONAL_MANY,
VERSIONED_ATOM}, // support any future named child to dref; keep 4th from
// end; manual return
{"esds",
{"SAMPLE_DESC"},
CHILD_ATOM,
REQUIRED_ONE,
SIMPLE_ATOM}, // multiple parents; keep 3rd from end; manual return
{"(..)",
{"ilst"},
PARENT_ATOM,
OPTIONAL_ONE,
SIMPLE_ATOM}, // multiple parents; keep 2nd from end; manual return
{"data",
{"ITUNES_METADATA"},
CHILD_ATOM,
PARENT_SPECIFIC,
VERSIONED_ATOM} // multiple parents
};

458
src/AtomicParsley.h Normal file
View File

@ -0,0 +1,458 @@
#ifndef ATOMIC_PARSLEY_H
#define ATOMIC_PARSLEY_H
//==================================================================//
/*
AtomicParsley - AtomicParsley.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2005-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#if defined HAVE_WINDOWS_H && !defined _WIN32
#define _WIN32
#endif
#ifdef _WIN32
#ifndef _UNICODE
#define _UNICODE
#endif
#if defined(_MSC_VER)
#define strncasecmp _strnicmp
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4244) // int64_t assignments to int32_t etc.
#endif
#endif
#define __STDC_LIMIT_MACROS
#define __STDC_FORMAT_MACROS
#define __STDC_CONSTANT_MACROS
#include <sys/types.h>
#ifdef __GLIBC__
#define HAVE_LROUNDF 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <errno.h>
#include <math.h>
#include <time.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/ioctl.h>
#endif
#ifdef __linux__
#include <linux/cdrom.h>
#include <sys/mount.h>
#include <sys/param.h>
#endif
#ifdef _WIN32
// Don't break std::min!
#define NOMINMAX
#include <windows.h>
#endif
#include <wchar.h>
#ifndef _WIN32
#include <sys/stat.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#include <io.h>
#endif
#include <signal.h>
#ifndef _WIN32
#include <getopt.h>
#else
#include "extras/getopt.h"
#endif
#ifndef PRIu64
#ifdef _WIN32
#define PRIu64 "I64u"
#else
#define PRIu64 "llu"
#endif
#endif
#ifndef PRIu32
#define PRIu32 "u"
#endif
#ifndef PRIx32
#define PRIx32 "x"
#endif
#ifndef SCNu64
#ifdef _WIN32
#define SCNu64 "I64u"
#else
#define SCNu64 "llu"
#endif
#endif
#ifndef SCNu32
#define SCNu32 "u"
#endif
#ifndef SCNu16
#define SCNu16 "hu"
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 255
#endif
#include "util.h"
#define MAX_ATOMS 2048
#define MAXDATA_PAYLOAD 1256
#define DEFAULT_PADDING_LENGTH 2048;
#define MINIMUM_REQUIRED_PADDING_LENGTH 0;
#define MAXIMUM_REQUIRED_PADDING_LENGTH 5000;
#include "ap_types.h"
extern atomDefinition KnownAtoms[];
extern bool parsedfile;
extern bool file_opened;
extern bool modified_atoms;
extern bool alter_original;
extern bool preserve_timestamps;
extern bool deep_atom_scan;
extern bool cvs_build;
extern bool force_existing_hierarchy;
extern bool move_moov_atom;
extern bool moov_atom_was_mooved;
extern int metadata_style;
extern uint32_t brand;
extern uint64_t mdatData;
extern uint64_t file_size;
extern uint64_t gapless_void_padding;
extern EmployedCodecs track_codecs;
extern AtomicInfo parsedAtoms[];
extern short atom_number;
extern char *ISObasemediafile;
extern FILE *source_file;
extern padding_preferences pad_prefs;
extern uint8_t UnicodeOutputStatus;
extern uint8_t forced_suffix_type;
extern char *twenty_byte_buffer;
extern DynamicUpdateStat dynUpd;
extern ID3FrameDefinition KnownFrames[];
extern ID3v2FieldDefinition FrameTypeConstructionList[];
extern ImageFileFormatDefinition ImageList[];
extern ID3ImageType ImageTypeList[];
void ShowVersionInfo();
void APar_FreeMemory();
short APar_FindParentAtom(int order_in_tree, uint8_t this_atom_level);
AtomicInfo *APar_FindAtomInTrack(uint8_t &total_tracks,
uint8_t &track_num,
const char *search_atom_str);
AtomicInfo *APar_FindAtom(const char *atom_name,
bool createMissing,
uint8_t atom_type,
uint16_t atom_lang,
bool match_full_uuids = false,
const char *reverseDNSdomain = NULL);
int APar_MatchToKnownAtom(const char *atom_name,
const char *atom_container,
bool fromFile,
const char *find_atom_path);
void APar_ScanAtoms(const char *path, bool deepscan_REQ = false);
void APar_IdentifyBrand(char *file_brand);
AtomicInfo *APar_CreateSparseAtom(AtomicInfo *surrogate_atom,
AtomicInfo *parent_atom,
short preceding_atom);
void APar_Unified_atom_Put(AtomicInfo *target_atom,
const char *unicode_data,
uint8_t text_tag_style,
uint64_t ancillary_data,
uint8_t anc_bit_width);
void APar_atom_Binary_Put(AtomicInfo *target_atom,
const char *binary_data,
uint32_t bytecount,
uint64_t atomic_data_offset);
/* iTunes-style metadata */
void APar_MetaData_atomArtwork_Set(const char *artworkPath,
char *env_PicOptions);
void APar_MetaData_atomGenre_Set(const char *atomPayload);
void APar_MetaData_atomLyrics_Set(const char *lyricsPath);
void APar_MetaData_atom_QuickInit(short atom_num,
const uint32_t atomFlags,
uint32_t supplemental_length,
uint32_t allotment = MAXDATA_PAYLOAD + 1);
AtomicInfo *APar_MetaData_atom_Init(const char *atom_path,
const char *MD_Payload,
const uint32_t atomFlags);
AtomicInfo *APar_reverseDNS_atom_Init(const char *rDNS_atom_name,
const char *rDNS_payload,
const uint32_t *atomFlags,
const char *rDNS_domain);
/* uuid user extension metadata; made to look much like iTunes-style metadata
* with a 4byte NULL */
AtomicInfo *APar_uuid_atom_Init(const char *atom_path,
const char *uuidName,
const uint32_t dataType,
const char *uuidValue,
bool shellAtom);
// test whether the ipod uuid can be added for a video track
uint16_t APar_TestVideoDescription(AtomicInfo *video_desc_atom,
FILE *ISObmff_file);
void APar_Generate_iPod_uuid(char *atom_path);
/* 3GP-style metadata */
uint32_t APar_3GP_Keyword_atom_Format(char *keywords_globbed,
uint8_t keyword_count,
bool set_UTF16_text,
char *&formed_keyword_struct);
AtomicInfo *APar_UserData_atom_Init(const char *userdata_atom_name,
const char *atom_payload,
uint8_t udta_container,
uint8_t track_idx,
uint16_t userdata_lang);
/* ID3v2 (2.4) style metadata, non-external form */
AtomicInfo *APar_ID32_atom_Init(const char *frameID_str,
char meta_area,
const char *lang_str,
uint16_t id32_lang);
void APar_RemoveAtom(const char *atom_path,
uint8_t atom_type,
uint16_t UD_lang,
const char *rDNS_domain = NULL);
void APar_freefree(int purge_level);
void APar_MetadataFileDump(const char *ISObasemediafile);
void APar_Optimize(bool mdat_test_only);
void APar_DetermineAtomLengths();
void APar_WriteFile(const char *ISObasemediafile,
const char *outfile,
bool rewrite_original);
void APar_zlib_inflate(char *in_buffer,
uint32_t in_buf_len,
char *out_buffer,
uint32_t out_buf_len);
uint32_t APar_zlib_deflate(char *in_buffer,
uint32_t in_buf_len,
char *out_buffer,
uint32_t out_buf_len);
void APar_print_uuid(ap_uuid_t *uuid, bool new_line = true);
void APar_sprintf_uuid(ap_uuid_t *uuid, char *destination);
uint8_t APar_uuid_scanf(char *in_formed_uuid, const char *raw_uuid);
void APar_endian_uuid_bin_str_conversion(char *raw_uuid);
uint8_t APar_extract_uuid_version(ap_uuid_t *uuid, char *binary_uuid_str);
void APar_generate_uuid_from_atomname(char *atom_name, char *uuid_binary_str);
void APar_generate_random_uuid(char *uuid_binary_str);
/* Initialize structure containing state of computation. */
extern void sha1_init_ctx(struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void
sha1_process_block(const void *buffer, size_t len, struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void
sha1_process_bytes(const void *buffer, size_t len, struct sha1_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 20 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF be correctly
aligned for a 32 bits value. */
extern void *sha1_finish_ctx(struct sha1_ctx *ctx, void *resbuf);
/* Put result from CTX in first 20 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *sha1_read_ctx(const struct sha1_ctx *ctx, void *resbuf);
/* Compute SHA1 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 20 bytes
beginning at RESBLOCK. */
extern int sha1_stream(FILE *stream, void *resblock);
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *sha1_buffer(const char *buffer, size_t len, void *resblock);
int isolat1ToUTF8(unsigned char *out,
int outlen,
const unsigned char *in,
int inlen);
int UTF8Toisolat1(unsigned char *out,
int outlen,
const unsigned char *in,
int inlen);
int UTF16BEToUTF8(unsigned char *out,
int outlen,
const unsigned char *inb,
int inlenb);
int UTF8ToUTF16BE(unsigned char *outb,
int outlen,
const unsigned char *in,
int inlen);
int UTF16LEToUTF8(unsigned char *out,
int outlen,
const unsigned char *inb,
int inlenb);
int UTF8ToUTF16LE(unsigned char *outb,
int outlen,
const unsigned char *in,
int inlen);
int isUTF8(const char *in_string);
unsigned int utf8_length(const char *in_string, unsigned int char_limit);
int strip_bogusUTF16toRawUTF8(unsigned char *out,
int inlen,
wchar_t *in,
int outlen);
int test_conforming_alpha_string(char *in_string);
bool test_limited_ascii(char *in_string, unsigned int str_len);
void APar_ExtractDetails(FILE *isofile, uint8_t optional_output);
void APar_ExtractBrands(char *filepath);
void printBOM();
void APar_fprintf_UTF8_data(const char *utf8_encoded_data);
void APar_unicode_win32Printout(wchar_t *unicode_out, char *utf8_out);
void APar_Extract_uuid_binary_file(AtomicInfo *uuid_atom,
const char *originating_file,
char *output_path);
void APar_Print_APuuid_atoms(const char *path,
char *output_path,
uint8_t target_information);
void APar_Print_iTunesData(const char *path,
char *output_path,
uint8_t supplemental_info,
uint8_t target_information,
AtomicInfo *ilstAtom = NULL);
void APar_PrintUserDataAssests(bool quantum_listing = false);
void APar_Extract_ID3v2_file(AtomicInfo *id32_atom,
const char *frame_str,
const char *originfile,
const char *destination_folder,
AdjunctArgs *id3args);
void APar_Print_ID3v2_tags(AtomicInfo *id32_atom);
void APar_Print_ISO_UserData_per_track();
void APar_Mark_UserData_area(uint8_t track_num,
short userdata_atom,
bool quantum_listing);
// trees
void APar_PrintAtomicTree();
void APar_SimpleAtomPrintout();
uint32_t APar_4CC_CreatorCode(const char *filepath, uint32_t new_type_code);
void APar_SupplySelectiveTypeCreatorCodes(const char *inputPath,
const char *outputPath,
uint8_t forced_type_code);
bool ResizeGivenImage(const char *filePath,
PicPrefs myPicPrefs,
char *resized_path);
char *GenreIntToString(int genre);
uint8_t StringGenreToInt(const char *genre_string);
void ListGenresValues();
stiks *MatchStikString(const char *stik_string);
stiks *MatchStikNumber(uint8_t in_stik_num);
void ListStikValues();
sfIDs *MatchStoreFrontNumber(uint32_t storefrontnum);
bool MatchLanguageCode(const char *in_code);
void ListLanguageCodes();
void ListMediaRatings();
void ListTVGenreIDValues();
void ListMovieGenreIDValues();
const char *Expand_cli_mediastring(const char *cli_rating);
char *ID3GenreIntToString(int genre);
uint8_t ID3StringGenreToInt(const char *genre_string);
#endif /* ATOMIC_PARSLEY_H */
// vim:ts=2:sw=2:et:

589
src/CDtoc.cpp Normal file
View File

@ -0,0 +1,589 @@
//==================================================================//
/*
AtomicParsley - CDtoc.cpp
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C)2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
// gathering of a CD's Table of Contents is going to be hardware specific
// currently only Mac OS X is implemented - using IOKit framework.
// another avenue (applicable to other *nix platforms): ioctl
#include "AtomicParsley.h"
#include "CDtoc.h"
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IOCDTypes.h>
const uint8_t MACOSX_LEADOUT_TRACK = 0xA2;
#endif
const uint8_t CDOBJECT_DATACD = 0;
const uint8_t CDOBJECT_AUDIOCD = 1;
struct CD_TDesc {
uint8_t session;
uint8_t controladdress;
uint8_t unused1; // refered to as 'tno' which equates to "track number" -
// but... its 'point' that actually is the tracknumber in
// mode1 TOC. set to zero for all mode1 TOC
uint8_t tracknumber; // refered to as 'point', but this is actually the
// tracknumber in mode1 audio toc entries.
uint8_t rel_minutes;
uint8_t rel_seconds;
uint8_t rel_frames;
uint8_t zero_space;
uint8_t abs_minutes;
uint8_t abs_seconds;
uint8_t abs_frames;
void *next_description;
};
typedef struct CD_TDesc CD_TDesc;
struct CD_TOC_ {
uint16_t toc_length;
uint8_t first_session;
uint8_t last_session;
CD_TDesc *track_description; // entry to the first track in the linked list
};
typedef struct CD_TOC_ CD_TOC_;
CD_TOC_ *cdTOC = NULL;
#if defined(__APPLE__)
uint8_t LEADOUT_TRACK_NUMBER = MACOSX_LEADOUT_TRACK;
#elif defined(__linux__)
uint8_t LEADOUT_TRACK_NUMBER = CDROM_LEADOUT;
#elif defined(_WIN32)
uint8_t LEADOUT_TRACK_NUMBER =
0xAA; // NOTE: for WinXP IOCTL_CDROM_READ_TOC_EX code, its 0xA2
#endif
/*
MCDI describes the CD TOC - actually talks about "a binary dump of the TOC".
So, a TOC is made up of: a 4 byte TOC header (2 bytes length of the entire TOC,
1 byte start session, 1 byte end session) an array of track entries, and
depending on the mode, of varying lengths. For audio CDs, TOC track entries are
mode1 (or for CD-R/RW mode5, but lets stick to mode1) a mode1 track entry is 11
bytes: 1byte session, 1 byte (packed control/address), 1byte NULL (unused TNO),
1 byte for tracknumber (expressed as the word POINT in mmc nomenclature),
3bytes relative start frametime, 1 byte NULL, 3 bytes duration timeframe
while "binary dump of the TOC" is there, its also modified so that the
timeframe listing in mm:ss::frames (3bytes) is converted to a 4byte LBA
timecode. Combining the first 4 bytes of the "binary dump of the TOC" with the
modifications of the 3byte(frame)->4byte(block), we arrive at MCDI as:
struct mcdi_track_entry {
uint8_t cd_toc_session;
uint8_t cd_toc_controladdress; //bitpacked uint4_t of control & address
uint8_t cd_toc_TNO = 0; //hardcoded to 0 for mode1 audio tracks in the TOC
uint8_t cd_toc_tracknumber; //this is the 1-99 tracknumber (listed in mmc-2
as POINT) uint32_t cd_frame_address; //converted from the 3byte mm:ss:frame
absolute duration
};
struct toc_header {
uint16_t toc_length;
uin8_t first_track;
uint8_t last_track;
};
struct mcdi_frame {
struct toc_header;
struct mcdi_track_entry[total_audio_tracks];
struct mcdi_track_entry lead_out;
};
The problem with including the TOC header is that it can't be used directly
because on the CD toc entries are 3byte msf address, but here they are 4byte
LBA. In any event this header should not have ever been included because the
length can be deduced from the frame length & tracks by dividing by 8. So, the
header length that MCDI refers to: is it for MSF or LBA addressing? Well, since
the rest of MCDI is LBA-based, lets say LBA - which means it needs to be
calculated. As it just so happens, then its the length of the frame. All that
needs to be added are the first & last tracks.
Unfortunately, this frame can't be used as a CD Identifier *AS IS* across
platforms. Because the leadout track is platform specific (a Linux leadout is
0xAA, MacOSX leadout is 0xA2), consideration of the leadout track would have to
be given by anything else using this frame.
*/
///////////////////////////////////////////////////////////////////////////
// Generating MCDI data from a CD TOC //
///////////////////////////////////////////////////////////////////////////
uint8_t DataControlField(uint8_t controlfield) {
#if defined(__ppc__) || defined(__ppc64__)
if (controlfield & 0x04) { // data uninterrupted or increment OR reserved;
// this field is already bitpacked as controlfield
return 1;
}
#else
if (controlfield &
0x40) { // data uninterrupted or increment OR reserved; bitpacked already
return 1;
}
#endif
return 0;
}
uint8_t DetermineCDType(CD_TOC_ *cdTOCdata) {
CD_TDesc *track_TOC_desc = cdTOCdata->track_description;
while (track_TOC_desc != NULL) {
if (track_TOC_desc->tracknumber >= 1 && track_TOC_desc->tracknumber <= 99 &&
!DataControlField(track_TOC_desc->controladdress)) {
return CDOBJECT_AUDIOCD;
}
track_TOC_desc = (CD_TDesc *)track_TOC_desc->next_description;
}
return CDOBJECT_DATACD;
}
CD_TDesc *LeadOutTrack(CD_TOC_ *cdTOCdata) {
CD_TDesc *track_TOC_desc = cdTOCdata->track_description;
while (track_TOC_desc != NULL) {
if (track_TOC_desc->tracknumber == LEADOUT_TRACK_NUMBER) {
return track_TOC_desc;
}
track_TOC_desc = (CD_TDesc *)track_TOC_desc->next_description;
}
return NULL;
}
uint8_t FillSingleMCDIentry(CD_TDesc *atrack, char *mcdi_data_entry) {
mcdi_data_entry[0] = atrack->session;
mcdi_data_entry[1] = atrack->controladdress;
mcdi_data_entry[2] = 0;
mcdi_data_entry[3] = atrack->tracknumber;
// LBA=(M*60+S)*75+F - 150 (table 374)
uint32_t frameduration =
((((atrack->abs_minutes * 60) + atrack->abs_seconds) * 75) +
atrack->abs_frames) -
150;
UInt32_TO_String4(frameduration, mcdi_data_entry + 4);
return 8;
}
uint16_t FormMCDIdata(char *mcdi_data) {
uint16_t mcdi_len = 0;
uint8_t first_track = 0;
uint8_t last_track = 0;
CD_TDesc *track_TOC_desc = cdTOC->track_description;
if (cdTOC->track_description != NULL) {
mcdi_len += 4;
while (track_TOC_desc != NULL) {
if (track_TOC_desc->tracknumber >= 1 &&
track_TOC_desc->tracknumber <= 99 &&
!DataControlField(track_TOC_desc->controladdress)) {
mcdi_len += FillSingleMCDIentry(track_TOC_desc, mcdi_data + mcdi_len);
if (first_track == 0) {
first_track = track_TOC_desc->tracknumber;
}
last_track = track_TOC_desc->tracknumber;
}
track_TOC_desc = (CD_TDesc *)track_TOC_desc->next_description;
}
if (mcdi_len > 0) {
CD_TDesc *leadout = LeadOutTrack(cdTOC);
if (leadout != NULL) {
mcdi_len += FillSingleMCDIentry(leadout, mcdi_data + mcdi_len);
}
}
// backtrack & fill in the header
UInt16_TO_String2(mcdi_len, mcdi_data);
mcdi_data[2] = first_track;
mcdi_data[3] = last_track;
}
return mcdi_len;
}
/////////////////////////////////////////////////////////////////////////////
// Platform Specifics //
/////////////////////////////////////////////////////////////////////////////
#if defined(__linux__)
void Linux_ReadCDTOC(int cd_fd) {
cdrom_tochdr toc_header;
cdrom_tocentry toc_entry;
CD_TDesc *a_TOC_desc = NULL;
CD_TDesc *prev_desc = NULL;
if (ioctl(cd_fd, CDROMREADTOCHDR, &toc_header) == -1) {
fprintf(stderr,
"AtomicParsley error: there was an error reading the CD "
"Table of Contents header.\n");
return;
}
cdTOC = (CD_TOC_ *)calloc(1, sizeof(CD_TOC_));
cdTOC->track_description = NULL;
for (uint8_t i = toc_header.cdth_trk0; i <= toc_header.cdth_trk1 + 1; i++) {
memset(&toc_entry, 0, sizeof(toc_entry));
if (i == toc_header.cdth_trk1 + 1) {
toc_entry.cdte_track = CDROM_LEADOUT;
} else {
toc_entry.cdte_track = i;
}
toc_entry.cdte_format =
CDROM_MSF; // although it could just be easier to use CDROM_LBA
if (ioctl(cd_fd, CDROMREADTOCENTRY, &toc_entry) == -1) {
fprintf(stderr,
"AtomicParsley error: there was an error reading a "
"CD Table of Contents entry (linux cdrom).\n");
return;
}
if (cdTOC->track_description == NULL) {
cdTOC->track_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = cdTOC->track_description;
prev_desc = a_TOC_desc;
} else {
prev_desc->next_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = (CD_TDesc *)prev_desc->next_description;
prev_desc = a_TOC_desc;
}
a_TOC_desc->session = 1; // and for vanilla audio CDs it is session 1, but
// for multi-session...
#if defined(__ppc__) || defined(__ppc64__)
a_TOC_desc->controladdress =
(toc_entry.cdte_ctrl << 4) | toc_entry.cdte_adr;
#else
a_TOC_desc->controladdress =
(toc_entry.cdte_adr << 4) | toc_entry.cdte_ctrl;
#endif
a_TOC_desc->unused1 = 0;
a_TOC_desc->tracknumber = toc_entry.cdte_track;
a_TOC_desc->rel_minutes =
0; // is there anyway to even find this out on
// linux without playing the track? //cdmsf_min0
a_TOC_desc->rel_seconds = 0;
a_TOC_desc->rel_frames = 0;
a_TOC_desc->zero_space = 0;
a_TOC_desc->abs_minutes = toc_entry.cdte_addr.msf.minute;
a_TOC_desc->abs_seconds = toc_entry.cdte_addr.msf.second;
a_TOC_desc->abs_frames = toc_entry.cdte_addr.msf.frame;
}
return;
}
uint16_t Linux_ioctlProbeTargetDrive(const char *id3args_drive,
char *mcdi_data) {
uint16_t mcdi_data_len = 0;
int cd_fd = 0;
cd_fd = open(id3args_drive, O_RDONLY | O_NONBLOCK);
if (cd_fd != -1) {
int cd_mode = ioctl(cd_fd, CDROM_DISC_STATUS);
if (cd_mode != CDS_AUDIO || cd_mode != CDS_MIXED) {
Linux_ReadCDTOC(cd_fd);
mcdi_data_len = FormMCDIdata(mcdi_data);
} else {
// scan for available devices
}
} else {
// scan for available devices
}
return mcdi_data_len;
}
#endif
#if defined(__APPLE__)
uint16_t Extract_cdTOCrawdata(CFDataRef cdTOCdata, char *cdTOCrawdata) {
CFRange cdrange;
CFIndex cdTOClen = CFDataGetLength(cdTOCdata);
cdTOCrawdata = (char *)calloc(1, sizeof(char) * cdTOClen + 1);
cdrange = CFRangeMake(0, cdTOClen + 1);
CFDataGetBytes(cdTOCdata, cdrange, (unsigned char *)cdTOCrawdata);
cdTOC = (CD_TOC_ *)calloc(1, sizeof(CD_TOC_));
cdTOC->toc_length = UInt16FromBigEndian(cdTOCrawdata);
cdTOC->first_session = cdTOCrawdata[2];
cdTOC->first_session = cdTOCrawdata[3];
cdTOC->track_description = NULL;
CD_TDesc *a_TOC_desc = NULL;
CD_TDesc *prev_desc = NULL;
uint16_t toc_offset = 0;
for (toc_offset = 4; toc_offset <= cdTOClen; toc_offset += 11) {
if (cdTOC->track_description == NULL) {
cdTOC->track_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = cdTOC->track_description;
prev_desc = a_TOC_desc;
} else {
prev_desc->next_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = (CD_TDesc *)prev_desc->next_description;
prev_desc = a_TOC_desc;
}
a_TOC_desc->session = cdTOCrawdata[toc_offset];
a_TOC_desc->controladdress = cdTOCrawdata[toc_offset + 1];
a_TOC_desc->unused1 = cdTOCrawdata[toc_offset + 2];
a_TOC_desc->tracknumber = cdTOCrawdata[toc_offset + 3];
a_TOC_desc->rel_minutes = cdTOCrawdata[toc_offset + 4];
a_TOC_desc->rel_seconds = cdTOCrawdata[toc_offset + 5];
a_TOC_desc->rel_frames = cdTOCrawdata[toc_offset + 6];
a_TOC_desc->zero_space = 0;
a_TOC_desc->abs_minutes = cdTOCrawdata[toc_offset + 8];
a_TOC_desc->abs_seconds = cdTOCrawdata[toc_offset + 9];
a_TOC_desc->abs_frames = cdTOCrawdata[toc_offset + 10];
}
return (uint16_t)cdTOClen;
}
void OSX_ReadCDTOC(io_object_t cdobject) {
CFMutableDictionaryRef cd_props = 0;
CFDataRef cdTOCdata = NULL;
char *cdTOCrawdata = NULL;
if (IORegistryEntryCreateCFProperties(
cdobject, &cd_props, kCFAllocatorDefault, kNilOptions) !=
kIOReturnSuccess)
return;
cdTOCdata =
(CFDataRef)CFDictionaryGetValue(cd_props, CFSTR(kIOCDMediaTOCKey));
if (cdTOCdata != NULL) {
Extract_cdTOCrawdata(cdTOCdata, cdTOCrawdata);
}
CFRelease(cd_props);
cd_props = NULL;
return;
}
void OSX_ScanForCDDrive() {
io_iterator_t drive_iter = MACH_PORT_NULL;
io_object_t driveobject = MACH_PORT_NULL;
CFTypeRef drive_path = NULL;
char drive_path_str[20];
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(kIOCDMediaClass),
&drive_iter) !=
kIOReturnSuccess) { // create the iterator
fprintf(stdout, "No device capable of reading cd media present\n");
}
driveobject = IOIteratorNext(drive_iter);
while (driveobject != MACH_PORT_NULL) {
drive_path = IORegistryEntryCreateCFProperty(
driveobject, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
if (drive_path != NULL) {
CFStringGetCString((CFStringRef)drive_path,
(char *)&drive_path_str,
20,
kCFStringEncodingASCII);
fprintf(stdout, "Device '%s' contains cd media\n", drive_path_str);
OSX_ReadCDTOC(driveobject);
if (cdTOC != NULL) {
uint8_t cdType = DetermineCDType(cdTOC);
if (cdType == CDOBJECT_AUDIOCD) {
fprintf(stdout,
"Good news, device '%s' is an Audio CD and can be used for "
"'MCDI' setting\n",
drive_path_str);
} else {
fprintf(stdout, "Tragically, it was a data CD.\n");
}
free(cdTOC); // the other malloced members should be freed also
}
}
IOObjectRelease(driveobject);
driveobject = IOIteratorNext(drive_iter);
}
if (drive_path_str[0] == (uint8_t)0x00) {
fprintf(stdout, "No CD media was found in any device\n");
}
IOObjectRelease(drive_iter);
drive_iter = MACH_PORT_NULL;
exit(0);
}
uint16_t OSX_ProbeTargetDrive(const char *id3args_drive, char *mcdi_data) {
uint16_t mcdi_data_len = 0;
io_object_t cdobject = MACH_PORT_NULL;
if (strncmp(id3args_drive, "disk", 4) != 0) {
OSX_ScanForCDDrive();
exit(0);
}
cdobject = IOServiceGetMatchingService(
kIOMasterPortDefault,
IOBSDNameMatching(kIOMasterPortDefault, 0, id3args_drive));
if (cdobject == MACH_PORT_NULL) {
fprintf(stdout,
"No device found at %s; searching for possible drives...\n",
id3args_drive);
OSX_ScanForCDDrive();
} else if (IOObjectConformsTo(cdobject, kIOCDMediaClass) == false) {
fprintf(stdout, "No cd present in drive at %s\n", id3args_drive);
IOObjectRelease(cdobject);
cdobject = MACH_PORT_NULL;
OSX_ScanForCDDrive();
} else {
// we now have a cd object
OSX_ReadCDTOC(cdobject);
if (cdTOC != NULL) {
uint8_t cdType = DetermineCDType(cdTOC);
if (cdType == CDOBJECT_AUDIOCD) {
mcdi_data_len = FormMCDIdata(mcdi_data);
}
}
}
IOObjectRelease(cdobject);
cdobject = MACH_PORT_NULL;
return mcdi_data_len;
}
#endif
#if defined(_WIN32)
void Windows_ioctlReadCDTOC(HANDLE cdrom_device) {
DWORD bytes_returned;
CDROM_TOC win_cdrom_toc;
// WARNING: "This IOCTL is obsolete beginning with the Microsoft Windows
// Vista. Do not use this IOCTL to develop drivers in Microsoft Windows
// Vista."
if (DeviceIoControl(cdrom_device,
IOCTL_CDROM_READ_TOC,
NULL,
0,
&win_cdrom_toc,
sizeof(CDROM_TOC),
&bytes_returned,
NULL) == 0) {
fprintf(stderr,
"AtomicParsley error: there was an error reading the CD "
"Table of Contents header (win32).\n");
return;
}
cdTOC = (CD_TOC_ *)calloc(1, sizeof(CD_TOC_));
cdTOC->toc_length = ((win_cdrom_toc.Length[0] & 0xFF) << 8) |
(win_cdrom_toc.Length[1] & 0xFF);
// cdTOC->first_session = 0; //seems windows doesn't store session info with
// IOCTL_CDROM_READ_TOC, all tracks from all sessions are available
// cdTOC->last_session = 0; //not used anyway; IOCTL_CDROM_READ_TOC_EX could
// be used to get session information, but its only available on XP
//...............and interestingly enough in XP, IOCTL_CDROM_TOC_EX returns
// the leadout track as 0xA2, which makes a Win2k MCDI & a WinXP MCDI
// different (by 1 byte)
cdTOC->track_description = NULL;
CD_TDesc *a_TOC_desc = NULL;
CD_TDesc *prev_desc = NULL;
for (uint8_t i = win_cdrom_toc.FirstTrack; i <= win_cdrom_toc.LastTrack + 1;
i++) {
TRACK_DATA *thisTrackData = &(win_cdrom_toc.TrackData[i - 1]);
if (cdTOC->track_description == NULL) {
cdTOC->track_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = cdTOC->track_description;
prev_desc = a_TOC_desc;
} else {
prev_desc->next_description = (CD_TDesc *)calloc(1, (sizeof(CD_TDesc)));
a_TOC_desc = (CD_TDesc *)prev_desc->next_description;
prev_desc = a_TOC_desc;
}
a_TOC_desc->session = 1; // and for vanilla audio CDs it is session 1, but
// for multi-session...
#if defined(__ppc__) || defined(__ppc64__)
a_TOC_desc->controladdress =
(thisTrackData->Control << 4) | thisTrackData->Adr;
#else
a_TOC_desc->controladdress =
(thisTrackData->Adr << 4) | thisTrackData->Control;
#endif
a_TOC_desc->unused1 = 0;
a_TOC_desc->tracknumber = thisTrackData->TrackNumber;
a_TOC_desc->rel_minutes =
0; // didn't look too much into finding this since it is unused
a_TOC_desc->rel_seconds = 0;
a_TOC_desc->rel_frames = 0;
a_TOC_desc->zero_space = 0;
a_TOC_desc->abs_minutes = thisTrackData->Address[1];
a_TOC_desc->abs_seconds = thisTrackData->Address[2];
a_TOC_desc->abs_frames = thisTrackData->Address[3];
}
return;
}
uint16_t Windows_ioctlProbeTargetDrive(const char *id3args_drive,
char *mcdi_data) {
uint16_t mcdi_data_len = 0;
char cd_device_path[16];
memset(cd_device_path, 0, 16);
sprintf(cd_device_path, "\\\\.\\%s:", id3args_drive);
HANDLE cdrom_device = APar_OpenFileWin32(cd_device_path,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (cdrom_device != INVALID_HANDLE_VALUE) {
Windows_ioctlReadCDTOC(cdrom_device);
if (cdTOC != NULL) {
uint8_t cdType = DetermineCDType(cdTOC);
if (cdType == CDOBJECT_AUDIOCD) {
mcdi_data_len = FormMCDIdata(mcdi_data);
}
}
CloseHandle(cdrom_device);
}
return mcdi_data_len;
}
#endif
////////////////////////////////////////////////////////////////////////////
// CD TOC Entry Area //
////////////////////////////////////////////////////////////////////////////
uint16_t GenerateMCDIfromCD(const char *drive, char *dest_buffer) {
uint16_t mcdi_bytes = 0;
#if defined(__APPLE__)
mcdi_bytes = OSX_ProbeTargetDrive(drive, dest_buffer);
#elif defined(__linux__)
mcdi_bytes = Linux_ioctlProbeTargetDrive(drive, dest_buffer);
#elif defined(_WIN32)
mcdi_bytes = Windows_ioctlProbeTargetDrive(drive, dest_buffer);
#endif
return mcdi_bytes;
}

80
src/CDtoc.h Normal file
View File

@ -0,0 +1,80 @@
//==================================================================//
/*
AtomicParsley - CDtoc.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "ap_types.h"
#if defined(_WIN32)
// these #defines & structs are copied from the MS W2k DDK headers so the entire
// DDK isn't required to be installed to compile AP_CDTOC for MCDI support
#ifndef DEVICE_TYPE
#define DEVICE_TYPE ULONG
#endif
#define FILE_DEVICE_CD_ROM 0x00000002
#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
#define METHOD_BUFFERED 0
#define FILE_READ_ACCESS (0x0001) // file & pipe
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define IOCTL_CDROM_READ_TOC \
CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
#define MAXIMUM_NUMBER_TRACKS 100
//
// CD ROM Table OF Contents (TOC)
// Format 0 - Get table of contents
//
typedef struct _TRACK_DATA {
UCHAR Reserved;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TrackNumber;
UCHAR Reserved1;
UCHAR Address[4];
} TRACK_DATA, *PTRACK_DATA;
typedef struct _CDROM_TOC {
//
// Header
//
UCHAR Length[2];
UCHAR FirstTrack;
UCHAR LastTrack;
//
// Track data
//
TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC, *PCDROM_TOC;
#endif
uint16_t GenerateMCDIfromCD(const char *drive, char *dest_buffer);

384
src/ap_types.h Normal file
View File

@ -0,0 +1,384 @@
#ifndef AP_TYPES_H
#define AP_TYPES_H
// Atom version 1byte/ Atom flags 3 bytes; 0x00 00 00 00
#define AtomFlags_Data_Binary 0
// UTF-8, no termination
#define AtomFlags_Data_Text 1
// \x0D
#define AtomFlags_Data_JPEGBinary 13
// \x0E
#define AtomFlags_Data_PNGBinary 14
// \x15 for cpil, tmpo, rtng; iTMS atoms: cnID, atID, plID, geID, sfID, akID
#define AtomFlags_Data_UInt 21
// 0x58 for uuid atoms that contain files
#define AtomFlags_Data_uuid_binary 88
enum {
UTF8_iTunesStyle_256glyphLimited = 0, // no NULL termination
UTF8_iTunesStyle_Unlimited = 1, // no NULL termination
UTF8_iTunesStyle_Binary = 3, // no NULL termination, used in purl & egid
UTF8_3GP_Style = 8, // terminated with a NULL uint8_t
UTF16_3GP_Style = 16 // terminated with a NULL uint16_t
};
enum {
UNDEFINED_STYLE = 0,
ITUNES_STYLE = 100,
THIRD_GEN_PARTNER = 300, // 3gpp files prior to 3gp6
THIRD_GEN_PARTNER_VER1_REL6 =
306, // 3GPP Release6 the first spec to contain the complement of assets
THIRD_GEN_PARTNER_VER1_REL7 = 307, // 3GPP Release7 introduces ID32 atoms
THIRD_GEN_PARTNER_VER2 = 320, // 3gp2 files
THIRD_GEN_PARTNER_VER2_REL_A =
321, // 3gp2 files, 3GPP2 C.S0050-A introduces 'gadi'
MOTIONJPEG2000 = 400
};
#include "id3v2types.h"
struct AtomicInfo {
short AtomicNumber;
uint64_t AtomicStart;
uint64_t AtomicLength;
uint64_t AtomicLengthExtended;
char *AtomicName;
char *ReverseDNSname;
char *ReverseDNSdomain;
uint8_t AtomicContainerState;
uint8_t AtomicClassification;
uint32_t AtomicVerFlags; // used by versioned atoms and derivatives
uint16_t AtomicLanguage; // used by 3gp assets & ID32 atoms only
uint8_t AtomicLevel;
char *AtomicData;
int NextAtomNumber; // our first atom is numbered 0; the last points back to
// it - so watch it!
uint32_t
ancillary_data; // just contains a simple number for atoms that contains
// some interesting info (like stsd codec used)
uint8_t uuid_style;
char *uuid_ap_atomname;
ID3v2Tag *ID32_TagInfo;
};
#include "id3v2.h"
// currently this is only used on Mac OS X to set type/creator for generic
// '.mp4' file extension files. The Finder 4 character code TYPE is what
// determines whether a file appears as a video or an audio file in a broad
// sense.
struct EmployedCodecs {
bool has_avc1;
bool has_mp4v;
bool has_drmi;
bool has_alac;
bool has_mp4a;
bool has_drms;
bool has_timed_text; // carries the URL - in the mdat stream at a specific
// time - thus it too is timed.
bool has_timed_jpeg; // no idea of podcasts support 'png ' or 'tiff'
bool has_timed_tx3g; // this IS true timed text stream
bool has_mp4s; // MPEG-4 Systems
bool has_rtp_hint; //'rtp '; implies hinting
};
enum {
MEDIADATA__PRECEDES__MOOV = 2,
ROOT_META__PRECEDES__MOOV = 4,
MOOV_META__PRECEDES__TRACKS = 8,
MOOV_UDTA__PRECEDES__TRACKS = 16,
PADDING_AT_EOF = 0x1000000
};
struct FreeAtomListing {
AtomicInfo *free_atom;
FreeAtomListing *next_free_listing;
};
struct DynamicUpdateStat {
bool updage_by_padding;
bool reorder_moov;
bool moov_was_mooved;
bool prevent_dynamic_update;
uint32_t optimization_flags;
uint64_t padding_bytes;
short consolidated_padding_insertion;
AtomicInfo *last_trak_child_atom;
AtomicInfo *moov_atom;
AtomicInfo *moov_udta_atom;
AtomicInfo *iTunes_list_handler_atom;
AtomicInfo *moov_meta_atom;
AtomicInfo *file_meta_atom;
AtomicInfo *first_mdat_atom;
AtomicInfo *first_movielevel_metadata_tagging_atom;
AtomicInfo *initial_update_atom;
AtomicInfo *first_otiose_freespace_atom;
AtomicInfo *padding_store;
AtomicInfo *padding_resevoir;
FreeAtomListing *first_padding_atom;
FreeAtomListing *last_padding_atom;
};
struct padding_preferences {
uint32_t default_padding_size;
uint32_t minimum_required_padding_size;
uint32_t maximum_present_padding_size;
};
// Structure that defines the known atoms used by mpeg-4 family of
// specifications.
typedef struct {
const char *known_atom_name;
const char *known_parent_atoms[5]; // max known to be tested
uint32_t container_state;
int presence_requirements;
uint32_t box_type;
} atomDefinition;
typedef struct {
uint8_t uuid_form;
char *binary_uuid;
char *uuid_AP_atom_name;
} uuid_vitals;
enum {
PARENT_ATOM = 0, // container atom
SIMPLE_PARENT_ATOM = 1,
DUAL_STATE_ATOM =
2, // acts as both parent (contains other atoms) & child (carries data)
CHILD_ATOM = 3, // atom that does NOT contain any children
UNKNOWN_ATOM_TYPE = 4
};
enum {
REQUIRED_ONCE = 30, // means total of 1 atom per file (or total of 1 if
// parent atom is required to be present)
REQUIRED_ONE = 31, // means 1 atom per container atom; totalling many per file
// (or required present if optional parent atom is present)
REQUIRED_VARIABLE =
32, // means 1 or more atoms per container atom are required to be present
PARENT_SPECIFIC =
33, // means (iTunes-style metadata) the atom defines how many are
// present; most are MAX 1 'data' atoms; 'covr' is ?unlimited?
OPTIONAL_ONCE = 34, // means total of 1 atom per file, but not required
OPTIONAL_ONE = 35, // means 1 atom per container atom but not required; many
// may be present in a file
OPTIONAL_MANY = 36, // means more than 1 occurrence per container atom
REQ_FAMILIAL_ONE =
OPTIONAL_ONE, // means that one of the family of atoms defined by the spec
// is required by the parent atom
UKNOWN_REQUIREMENTS = 38
};
enum {
SIMPLE_ATOM = 50,
VERSIONED_ATOM = 51,
EXTENDED_ATOM = 52,
PACKED_LANG_ATOM = 53,
UNKNOWN_ATOM = 59
};
enum {
PRINT_DATA = 1,
PRINT_FREE_SPACE = 2,
PRINT_PADDING_SPACE = 4,
PRINT_USER_DATA_SPACE = 8,
PRINT_MEDIA_SPACE = 16,
EXTRACT_ARTWORK = 20,
EXTRACT_ALL_UUID_BINARYS = 21
};
typedef struct {
const char *stik_string;
uint8_t stik_number;
} stiks;
typedef struct {
const char *storefront_string;
uint32_t storefront_number;
} sfIDs;
typedef struct {
const char *iso639_2_code;
const char *iso639_1_code;
const char *language_in_english;
} iso639_lang;
typedef struct {
const char *media_rating;
const char *media_rating_cli_str;
} m_ratings;
typedef struct {
const char *genre_id_movie_string;
uint16_t genre_id_movie_value;
} geIDMovie;
typedef struct {
const char *genre_id_tv_string;
uint16_t genre_id_tv_value;
} geIDTV;
enum { UNIVERSAL_UTF8, WIN32_UTF16 };
enum { FORCE_M4B_TYPE = 85, NO_TYPE_FORCING = 90 };
enum { FILE_LEVEL_ATOM, MOVIE_LEVEL_ATOM, ALL_TRACKS_ATOM, SINGLE_TRACK_ATOM };
enum {
UUID_DEPRECATED_FORM,
UUID_SHA1_NAMESPACE,
UUID_AP_SHA1_NAMESPACE,
UUID_OTHER
};
/* Declarations of functions and data types used for SHA1 sum
library functions.
Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
*/
typedef struct {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version;
uint8_t clock_seq_hi_and_reserved;
uint8_t clock_seq_low;
unsigned char node[6];
} ap_uuid_t;
typedef uint32_t md5_uint32;
/* Structure to save state of computation between the single steps. */
struct sha1_ctx {
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
md5_uint32 D;
md5_uint32 E;
md5_uint32 total[2];
md5_uint32 buflen;
char buffer[128]; // char buffer[128] __attribute__ ((__aligned__ (__alignof__
// (md5_uint32))));
};
typedef struct { // if any of these are unused, they are set to 0xFF
uint8_t od_profile_level;
uint8_t scene_profile_level;
uint8_t audio_profile;
uint8_t video_profile_level;
uint8_t graphics_profile_level;
} iods_OD;
typedef struct {
uint64_t creation_time;
uint64_t modified_time;
uint64_t duration;
bool track_enabled;
unsigned char unpacked_lang[4];
char track_hdlr_name[100];
char encoder_name[100];
uint32_t track_type;
uint32_t track_codec;
uint32_t protected_codec;
bool contains_esds;
uint64_t section3_length;
uint64_t section4_length;
uint8_t ObjectTypeIndication;
uint32_t max_bitrate;
uint32_t avg_bitrate;
uint64_t section5_length;
uint8_t descriptor_object_typeID;
uint16_t channels;
uint64_t section6_length; // unused
// specifics
uint8_t m4v_profile;
uint8_t avc_version;
uint8_t profile;
uint8_t level;
uint16_t video_height;
uint16_t video_width;
uint32_t macroblocks;
uint64_t sample_aggregate;
uint16_t amr_modes;
uint8_t type_of_track;
} TrackInfo;
typedef struct {
uint64_t creation_time;
uint64_t modified_time;
uint32_t timescale;
uint32_t duration;
uint32_t playback_rate; // fixed point 16.16
uint16_t volume; // fixed 8.8 point
double seconds;
double simple_bitrate_calc;
bool contains_iods;
} MovieInfo;
typedef struct {
uint8_t total_tracks;
uint8_t track_num;
short track_atom;
} Trackage;
typedef struct {
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
double rem_millisecs;
} ap_time;
enum {
UNKNOWN_TRACK = 0,
VIDEO_TRACK = 2,
AUDIO_TRACK = 4,
DRM_PROTECTED_TRACK = 8,
OTHER_TRACK = 16
};
enum {
MP4V_TRACK = 65,
AVC1_TRACK = 66,
S_AMR_TRACK = 67,
S263_TRACK = 68,
EVRC_TRACK = 69,
QCELP_TRACK = 70,
SMV_TRACK = 71
};
enum { SHOW_TRACK_INFO = 2, SHOW_DATE_INFO = 4 };
struct PicPrefs {
int max_dimension;
int dpi;
int max_Kbytes;
bool squareUp;
bool allJPEG;
bool allPNG;
bool addBOTHpix;
bool removeTempPix;
bool force_dimensions;
int force_height;
int force_width;
};
#endif
/* vim:ts=2:sw=2:et:
*/

945
src/arrays.cpp Normal file
View File

@ -0,0 +1,945 @@
//==================================================================//
/*
AtomicParsley - arrays.cpp
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C) 2005-2007 puck_lock
with contributions from others; see the CREDITS file
----------------------
Code Contributions by:
* Mellow_Flow - fix genre matching/verify genre limits
*/
//==================================================================//
#include "AtomicParsley.h"
//////////////
static const char *ID3v1GenreList[] = {"Blues",
"Classic Rock",
"Country",
"Dance",
"Disco",
"Funk",
"Grunge",
"Hip-Hop",
"Jazz",
"Metal",
"New Age",
"Oldies",
"Other",
"Pop",
"R&B",
"Rap",
"Reggae",
"Rock",
"Techno",
"Industrial",
"Alternative",
"Ska",
"Death Metal",
"Pranks",
"Soundtrack",
"Euro-Techno",
"Ambient",
"Trip-Hop",
"Vocal",
"Jazz+Funk",
"Fusion",
"Trance",
"Classical",
"Instrumental",
"Acid",
"House",
"Game",
"Sound Clip",
"Gospel",
"Noise",
"AlternRock",
"Bass",
"Soul",
"Punk",
"Space",
"Meditative",
"Instrumental Pop",
"Instrumental Rock",
"Ethnic",
"Gothic",
"Darkwave",
"Techno-Industrial",
"Electronic",
"Pop-Folk",
"Eurodance",
"Dream",
"Southern Rock",
"Comedy",
"Cult",
"Gangsta",
"Top 40",
"Christian Rap",
"Pop/Funk",
"Jungle",
"Native American",
"Cabaret",
"New Wave",
"Psychadelic",
"Rave",
"Showtunes",
"Trailer",
"Lo-Fi",
"Tribal",
"Acid Punk",
"Acid Jazz",
"Polka",
"Retro",
"Musical",
"Rock & Roll",
"Hard Rock",
"Folk",
"Folk/Rock",
"National Folk",
"Swing",
"Fast Fusion",
"Bebob",
"Latin",
"Revival",
"Celtic",
"Bluegrass",
"Avantgarde",
"Gothic Rock",
"Progressive Rock",
"Psychedelic Rock",
"Symphonic Rock",
"Slow Rock",
"Big Band",
"Chorus",
"Easy Listening",
"Acoustic",
"Humour",
"Speech",
"Chanson",
"Opera",
"Chamber Music",
"Sonata",
"Symphony",
"Booty Bass",
"Primus",
"Porn Groove",
"Satire",
"Slow Jam",
"Club",
"Tango",
"Samba",
"Folklore",
"Ballad",
"Power Ballad",
"Rhythmic Soul",
"Freestyle",
"Duet",
"Punk Rock",
"Drum Solo",
"A Capella",
"Euro-House",
"Dance Hall"};
/*
"Goa", "Drum & Bass", "Club House", "Hardcore",
"Terror", "Indie", "BritPop", "NegerPunk", "Polsk Punk",
"Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
"Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
"Anime", "JPop", "SynthPop",
}; */ //apparently the other winamp id3v1 extensions aren't valid
stiks stikArray[] = {{"Home Video", 0},
{"Normal", 1},
{"Audiobook", 2},
{"Whacked Bookmark", 5},
{"Music Video", 6},
{"Movie", 9},
{"Short Film", 9},
{"TV Show", 10},
{"Booklet", 11}};
geIDMovie genreidmovie[] = {{"Action & Adventure", 4401},
{"Anime", 4402},
{"Classics", 4403},
{"Comedy", 4404},
{"Documentary", 4405},
{"Drama", 4406},
{"Foreign", 4407},
{"Horror", 4408},
{"Independent", 4409},
{"Kids & Family", 4410},
{"Musicals", 4411},
{"Romance", 4412},
{"Sci-Fi & Fantasy", 4413},
{"Short Films", 4414},
{"Special Interest", 4415},
{"Thriller", 4416},
{"Sports", 4417},
{"Western", 4418},
{"Urban", 4419},
{"Holiday", 4420},
{"Made for TV", 4421},
{"Concert Films", 4422},
{"Music Documentaries", 4423},
{"Music Feature Films", 4424},
{"Japanese Cinema", 4425},
{"Jidaigeki", 4426},
{"Tokusatsu", 4427},
{"Korean Cinema", 4428}};
geIDTV genreidtv[] = {{"Comedy", 4000},
{"Drama", 4001},
{"Animation", 4002},
{"Action & Adventure", 4003},
{"Classic", 4004},
{"Kids", 4005},
{"Nonfiction", 4005},
{"Reality TV", 4007},
{"Sci-Fi & Fantasy", 4008},
{"Sports", 4009},
{"Teens", 4010},
{"Latino TV", 4011}};
// from William Herrera:
// http://search.cpan.org/src/BILLH/LWP-UserAgent-iTMS_Client-0.16/lib/LWP/UserAgent/iTMS_Client.pm
sfIDs storefronts[] = {
{"United States", 143441}, {"France", 143442}, {"Germany", 143443},
{"United Kingdom", 143444}, {"Austria", 143445}, {"Belgium", 143446},
{"Finland", 143447}, {"Greece", 143448}, {"Ireland", 143449},
{"Italy", 143450}, {"Luxembourg", 143451}, {"Netherlands", 143452},
{"Portugal", 143453}, {"Spain", 143454}, {"Canada", 143455},
{"Sweden", 143456}, {"Norway", 143457}, {"Denmark", 143458},
{"Switzerland", 143459}, {"Australia", 143460}, {"New Zealand", 143461},
{"Japan", 143462}};
iso639_lang known_languages[] = {
{"aar", "aa", "Afar"},
{"abk", "ab", "Abkhazian"},
{"ace", NULL, "Achinese"},
{"ach", NULL, "Acoli"},
{"ada", NULL, "Adangme"},
{"ady", NULL, "Adyghe; Adygei"},
{"afa", NULL, "Afro-Asiatic (Other)"},
{"afh", NULL, "Afrihili"},
{"afr", "af", "Afrikaans"},
{"ain", NULL, "Ainu"},
{"aka", "ak", "Akan"},
{"akk", NULL, "Akkadian"},
{"alb/sqi", "sq", "Albanian"}, // dual codes
{"ale", NULL, "Aleut"},
{"alg", NULL, "Algonquian languages"},
{"alt", NULL, "Southern Altai"},
{"amh", "am", "Amharic"},
{"ang", NULL, "English, Old (ca.450-1100)"},
{"anp", NULL, "Angika"},
{"apa", NULL, "Apache languages"},
{"ara", "ar", "Arabic"},
{"arc", NULL, "Aramaic"},
{"arg", "an", "Aragonese"},
{"arm/hye", "hy", "Armenian"}, // dual codes
{"arn", NULL, "Araucanian"},
{"arp", NULL, "Arapaho"},
{"art", NULL, "Artificial (Other)"},
{"arw", NULL, "Arawak"},
{"asm", "as", "Assamese"},
{"ast", NULL, "Asturian; Bable"},
{"ath", NULL, "Athapascan languages"},
{"aus", NULL, "Australian languages"},
{"ava", "av", "Avaric"},
{"ave", "ae", "Avestan"},
{"awa", NULL, "Awadhi"},
{"aym", "ay", "Aymara"},
{"aze", "az", "Azerbaijani"},
{"bad", NULL, "Banda"},
{"bai", NULL, "Bamileke languages"},
{"bak", "ba", "Bashkir"},
{"bal", NULL, "Baluchi"},
{"bam", "bm", "Bambara"},
{"ban", NULL, "Balinese"},
{"baq/eus", "eu", "Basque"}, // dual codes
{"bas", NULL, "Basa"},
{"bat", NULL, "Baltic (Other)"},
{"bej", NULL, "Beja"},
{"bel", "be", "Belarusian"},
{"bem", NULL, "Bemba"},
{"ben", "bn", "Bengali"},
{"ber", NULL, "Berber (Other)"},
{"bho", NULL, "Bhojpuri"},
{"bih", "bh", "Bihari"},
{"bik", NULL, "Bikol"},
{"bin", NULL, "Bini"},
{"bis", "bi", "Bislama"},
{"bla", NULL, "Siksika"},
{"bnt", NULL, "Bantu (Other)"},
{"bos", "bs", "Bosnian"},
{"bra", NULL, "Braj"},
{"bre", "br", "Breton"},
{"btk", NULL, "Batak (Indonesia)"},
{"bua", NULL, "Buriat"},
{"bug", NULL, "Buginese"},
{"bul", "bg", "Bulgarian"},
{"bur/mya", "my", "Burmese"}, // dual codes
{"byn", NULL, "Blin; Bilin"},
{"cad", NULL, "Caddo"},
{"cai", NULL, "Central American Indian (Other)"},
{"car", NULL, "Carib"},
{"cat", "ca", "Catalan; Valencian"},
{"cau", NULL, "Caucasian (Other)"},
{"ceb", NULL, "Cebuano"},
{"cel", NULL, "Celtic (Other)"},
{"cha", "ch", "Chamorro"},
{"chb", NULL, "Chibcha"},
{"che", "ce", "Chechen"},
{"chg", NULL, "Chagatai"},
{"chk", NULL, "Chuukese"},
{"chm", NULL, "Mari"},
{"chn", NULL, "Chinook jargon"},
{"cho", NULL, "Choctaw"},
{"chp", NULL, "Chipewyan"},
{"chr", NULL, "Cherokee"},
{"chu",
"cu",
"Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church "
"Slavonic"},
{"chv", "cv", "Chuvash"},
{"chy", NULL, "Cheyenne"},
{"cmc", NULL, "Chamic languages"},
{"cop", NULL, "Coptic"},
{"cor", "kw", "Cornish"},
{"cos", "co", "Corsican"},
{"cpe", NULL, "Creoles and pidgins, English based (Other)"},
{"cpf", NULL, "Creoles and pidgins, French-based (Other)"},
{"cpp", NULL, "Creoles and pidgins, Portuguese-based (Other)"},
{"cre", "cr", "Cree"},
{"crh", NULL, "Crimean Tatar; Crimean Turkish"},
{"crp", NULL, "Creoles and pidgins (Other)"},
{"csb", NULL, "Kashubian"},
{"cus", NULL, "Cushitic (Other)"},
{"cze/ces", "cs", "Czech"}, // dual codes
{"dak", NULL, "Dakota"},
{"dan", "da", "Danish"},
{"dar", NULL, "Dargwa"},
{"day", NULL, "Dayak"},
{"del", NULL, "Delaware"},
{"den", NULL, "Slave (Athapascan)"},
{"dgr", NULL, "Dogrib"},
{"din", NULL, "Dinka"},
{"div", "dv", "Divehi; Dhivehi; Maldivian"},
{"doi", NULL, "Dogri"},
{"dra", NULL, "Dravidian (Other)"},
{"dsb", NULL, "Lower Sorbian"},
{"dua", NULL, "Duala"},
{"dum", NULL, "Dutch, Middle (ca.1050-1350)"},
{"dut/nld", "nl", "Dutch; Flemish"}, // dual codes
{"dyu", NULL, "Dyula"},
{"dzo", "dz", "Dzongkha"},
{"efi", NULL, "Efik"},
{"egy", NULL, "Egyptian (Ancient)"},
{"eka", NULL, "Ekajuk"},
{"elx", NULL, "Elamite"},
{"eng", "en", "English"},
{"enm", NULL, "English, Middle (1100-1500)"},
{"epo", "eo", "Esperanto"},
{"est", "et", "Estonian"},
{"ewe", "ee", "Ewe"},
{"ewo", NULL, "Ewondo"},
{"fan", NULL, "Fang"},
{"fao", "fo", "Faroese"},
{"fat", NULL, "Fanti"},
{"fij", "fj", "Fijian"},
{"fil", NULL, "Filipino; Pilipino"},
{"fin", "fi", "Finnish"},
{"fiu", NULL, "Finno-Ugrian (Other)"},
{"fon", NULL, "Fon"},
{"fre/fra", "fr", "French"}, // dual codes
{"frm", NULL, "French, Middle (ca.1400-1600)"},
{"fro", NULL, "French, Old (842-ca.1400)"},
{"frr", NULL, "Northern Frisian"},
{"frs", NULL, "Eastern Frisian"},
{"fry", "fy", "Western Frisian"},
{"ful", "ff", "Fulah"},
{"fur", NULL, "Friulian"},
{"gaa", NULL, "Ga"},
{"gay", NULL, "Gayo"},
{"gba", NULL, "Gbaya"},
{"gem", NULL, "Germanic (Other)"},
{"geo/kat", "ka", "Georgian"}, // dual codes
{"ger/deu", "de", "German"}, // dual codes
{"gez", NULL, "Geez"},
{"gil", NULL, "Gilbertese"},
{"gla", "gd", "Gaelic; Scottish Gaelic"},
{"gle", "ga", "Irish"},
{"glg", "gl", "Galician"},
{"glv", "gv", "Manx"},
{"gmh", NULL, "German, Middle High (ca.1050-1500)"},
{"goh", NULL, "German, Old High (ca.750-1050)"},
{"gon", NULL, "Gondi"},
{"gor", NULL, "Gorontalo"},
{"got", NULL, "Gothic"},
{"grb", NULL, "Grebo"},
{"grc", NULL, "Greek, Ancient (to 1453)"},
{"gre/ell", "el", "Greek, Modern (1453-)"}, // dual codes
{"grn", "gn", "Guarani"},
{"gsw", NULL, "Alemanic; Swiss German"},
{"guj", "gu", "Gujarati"},
{"gwi", NULL, "Gwich\u00abin"},
{"hai", NULL, "Haida"},
{"hat", "ht", "Haitian; Haitian Creole"},
{"hau", "ha", "Hausa"},
{"haw", NULL, "Hawaiian"},
{"heb", "he", "Hebrew"},
{"her", "hz", "Herero"},
{"hil", NULL, "Hiligaynon"},
{"him", NULL, "Himachali"},
{"hin", "hi", "Hindi"},
{"hit", NULL, "Hittite"},
{"hmn", NULL, "Hmong"},
{"hmo", "ho", "Hiri Motu"},
{"hsb", NULL, "Upper Sorbian"},
{"hun", "hu", "Hungarian"},
{"hup", NULL, "Hupa"},
{"arm/hye", "hy", "Armenian"},
{"iba", NULL, "Iban"},
{"ibo", "ig", "Igbo"},
{"ice/isl", "is", "Icelandic"}, // dual codes
{"ido", "io", "Ido"},
{"iii", "ii", "Sichuan Yi"},
{"ijo", NULL, "Ijo"},
{"iku", "iu", "Inuktitut"},
{"ile", "ie", "Interlingue"},
{"ilo", NULL, "Iloko"},
{"ina",
"ia",
"Interlingua (International Auxiliary, Language Association)"},
{"inc", NULL, "Indic (Other)"},
{"ind", "id", "Indonesian"},
{"ine", NULL, "Indo-European (Other)"},
{"inh", NULL, "Ingush"},
{"ipk", "ik", "Inupiaq"},
{"ira", NULL, "Iranian (Other)"},
{"iro", NULL, "Iroquoian languages"},
{"ita", "it", "Italian"},
{"jav", "jv", "Javanese"},
{"jbo", NULL, "Lojban"},
{"jpn", "ja", "Japanese"},
{"jpr", NULL, "Judeo-Persian"},
{"jrb", NULL, "Judeo-Arabic"},
{"kaa", NULL, "Kara-Kalpak"},
{"kab", NULL, "Kabyle"},
{"kac", NULL, "Kachin"},
{"kal", "kl", "Kalaallisut; Greenlandic"},
{"kam", NULL, "Kamba"},
{"kan", "kn", "Kannada"},
{"kar", NULL, "Karen"},
{"kas", "ks", "Kashmiri"},
{"kau", "kr", "Kanuri"},
{"kaw", NULL, "Kawi"},
{"kaz", "kk", "Kazakh"},
{"kbd", NULL, "Kabardian"},
{"kha", NULL, "Khasi"},
{"khi", NULL, "Khoisan (Other)"},
{"khm", "km", "Khmer"},
{"kho", NULL, "Khotanese"},
{"kik", "ki", "Kikuyu; Gikuyu"},
{"kin", "rw", "Kinyarwanda"},
{"kir", "ky", "Kirghiz"},
{"kmb", NULL, "Kimbundu"},
{"kok", NULL, "Konkani"},
{"kom", "kv", "Komi"},
{"kon", "kg", "Kongo"},
{"kor", "ko", "Korean"},
{"kos", NULL, "Kosraean"},
{"kpe", NULL, "Kpelle"},
{"krc", NULL, "Karachay-Balkar"},
{"krl", NULL, "Karelian"},
{"kro", NULL, "Kru"},
{"kru", NULL, "Kurukh"},
{"kua", "kj", "Kuanyama; Kwanyama"},
{"kum", NULL, "Kumyk"},
{"kur", "ku", "Kurdish"},
{"kut", NULL, "Kutenai"},
{"lad", NULL, "Ladino"},
{"lah", NULL, "Lahnda"},
{"lam", NULL, "Lamba"},
{"lao", "lo", "Lao"},
{"lat", "la", "Latin"},
{"lav", "lv", "Latvian"},
{"lez", NULL, "Lezghian"},
{"lim", "li", "Limburgan; Limburger; Limburgish"},
{"lin", "ln", "Lingala"},
{"lit", "lt", "Lithuanian"},
{"lol", NULL, "Mongo"},
{"loz", NULL, "Lozi"},
{"ltz", "lb", "Luxembourgish; Letzeburgesch"},
{"lua", NULL, "Luba-Lulua"},
{"lub", "lu", "Luba-Katanga"},
{"lug", "lg", "Ganda"},
{"lui", NULL, "Luiseno"},
{"lun", NULL, "Lunda"},
{"luo", NULL, "Luo (Kenya and Tanzania)"},
{"lus", NULL, "Lushai"},
{"mad", NULL, "Madurese"},
{"mag", NULL, "Magahi"},
{"mah", "mh", "Marshallese"},
{"mai", NULL, "Maithili"},
{"mak", NULL, "Makasar"},
{"mal", "ml", "Malayalam"},
{"man", NULL, "Mandingo"},
{"map", NULL, "Austronesian (Other)"},
{"mar", "mr", "Marathi"},
{"mas", NULL, "Masai"},
{"may/msa", "ms", "Malay"}, // dual codes
{"mdf", NULL, "Moksha"},
{"mdr", NULL, "Mandar"},
{"men", NULL, "Mende"},
{"mga", NULL, "Irish, Middle (900-1200)"},
{"mic", NULL, "Mi'kmaq; Micmac"},
{"min", NULL, "Minangkabau"},
{"mis", NULL, "Miscellaneous languages"},
{"mac/mkd", "mk", "Macedonian"}, // dual codes
{"mkh", NULL, "Mon-Khmer (Other)"},
{"mlg", "mg", "Malagasy"},
{"mlt", "mt", "Maltese"},
{"mnc", NULL, "Manchu"},
{"mni", NULL, "Manipuri"},
{"mno", NULL, "Manobo languages"},
{"moh", NULL, "Mohawk"},
{"mol", "mo", "Moldavian"},
{"mon", "mn", "Mongolian"},
{"mos", NULL, "Mossi"},
{"mao/mri", "mi", "Maori"}, // dual codes
{"mul", NULL, "Multiple languages"},
{"mun", NULL, "Munda languages"},
{"mus", NULL, "Creek"},
{"mwl", NULL, "Mirandese"},
{"mwr", NULL, "Marwari"},
{"myn", NULL, "Mayan languages"},
{"myv", NULL, "Erzya"},
{"nah", NULL, "Nahuatl"},
{"nai", NULL, "North American Indian"},
{"nap", NULL, "Neapolitan"},
{"nau", "na", "Nauru"},
{"nav", "nv", "Navajo; Navaho"},
{"nbl", "nr", "Ndebele, South; South Ndebele"},
{"nde", "nd", "Ndebele, North; North Ndebele"},
{"ndo", "ng", "Ndonga"},
{"nds", NULL, "Low German; Low Saxon; German, Low; Saxon, Low"},
{"nep", "ne", "Nepali"},
{"new", NULL, "Newari; Nepal Bhasa"},
{"nia", NULL, "Nias"},
{"nic", NULL, "Niger-Kordofanian (Other)"},
{"niu", NULL, "Niuean"},
{"nno", "nn", "Norwegian Nynorsk; Nynorsk, Norwegian"},
{"nob", "nb", "Norwegian Bokm\x8cl; Bokm\x8cl, Norwegian"},
{"nog", NULL, "Nogai"},
{"non", NULL, "Norse, Old"},
{"nor", "no", "Norwegian"},
{"nqo", NULL, "N'ko"},
{"nso", NULL, "Northern Sotho, Pedi; Sepedi"},
{"nub", NULL, "Nubian languages"},
{"nwc", NULL, "Classical Newari; Old Newari; Classical Nepal Bhasa"},
{"nya", "ny", "Chichewa; Chewa; Nyanja"},
{"nym", NULL, "Nyamwezi"},
{"nyn", NULL, "Nyankole"},
{"nyo", NULL, "Nyoro"},
{"nzi", NULL, "Nzima"},
{"oci", "oc", "Occitan (post 1500); Proven\u00c7al"},
{"oji", "oj", "Ojibwa"},
{"ori", "or", "Oriya"},
{"orm", "om", "Oromo"},
{"osa", NULL, "Osage"},
{"oss", "os", "Ossetian; Ossetic"},
{"ota", NULL, "Turkish, Ottoman (1500-1928)"},
{"oto", NULL, "Otomian languages"},
{"paa", NULL, "Papuan (Other)"},
{"pag", NULL, "Pangasinan"},
{"pal", NULL, "Pahlavi"},
{"pam", NULL, "Pampanga"},
{"pan", "pa", "Panjabi; Punjabi"},
{"pap", NULL, "Papiamento"},
{"pau", NULL, "Palauan"},
{"peo", NULL, "Persian, Old (ca.600-400 B.C.)"},
{"per/fas", "fa", "Persian"}, // dual codes
{"phi", NULL, "Philippine (Other)"},
{"phn", NULL, "Phoenician"},
{"pli", "pi", "Pali"},
{"pol", "pl", "Polish"},
{"pon", NULL, "Pohnpeian"},
{"por", "pt", "Portuguese"},
{"pra", NULL, "Prakrit languages"},
{"pro", NULL, "Proven\u00c7al, Old (to 1500)"},
{"pus", "ps", "Pushto"},
//{ "qaa-qtz", NULL, "Reserved for local use" },
{"que", "qu", "Quechua"},
{"raj", NULL, "Rajasthani"},
{"rap", NULL, "Rapanui"},
{"rar", NULL, "Rarotongan"},
{"roa", NULL, "Romance (Other)"},
{"roh", "rm", "Raeto-Romance"},
{"rom", NULL, "Romany"},
{"rum/ron", "ro", "Romanian"}, // dual codes
{"run", "rn", "Rundi"},
{"rup", NULL, "Aromanian; Arumanian; Macedo-Romanian"},
{"rus", "ru", "Russian"},
{"sad", NULL, "Sandawe"},
{"sag", "sg", "Sango"},
{"sah", NULL, "Yakut"},
{"sai", NULL, "South American Indian (Other)"},
{"sal", NULL, "Salishan languages"},
{"sam", NULL, "Samaritan Aramaic"},
{"san", "sa", "Sanskrit"},
{"sas", NULL, "Sasak"},
{"sat", NULL, "Santali"},
{"scn", NULL, "Sicilian"},
{"sco", NULL, "Scots"},
{"scr/hrv", "hr", "Croatian"}, // dual codes
{"sel", NULL, "Selkup"},
{"sem", NULL, "Semitic (Other)"},
{"sga", NULL, "Irish, Old (to 900)"},
{"sgn", NULL, "Sign Languages"},
{"shn", NULL, "Shan"},
{"sid", NULL, "Sidamo"},
{"sin", "si", "Sinhala; Sinhalese"},
{"sio", NULL, "Siouan languages"},
{"sit", NULL, "Sino-Tibetan (Other)"},
{"sla", NULL, "Slavic (Other)"},
{"slo/slk", "sk", "Slovak"}, // dual codes
{"slv", "sl", "Slovenian"},
{"sma", NULL, "Southern Sami"},
{"sme", "se", "Northern Sami"},
{"smi", NULL, "Sami languages (Other)"},
{"smj", NULL, "Lule Sami"},
{"smn", NULL, "Inari Sami"},
{"smo", "sm", "Samoan"},
{"sms", NULL, "Skolt Sami"},
{"sna", "sn", "Shona"},
{"snd", "sd", "Sindhi"},
{"snk", NULL, "Soninke"},
{"sog", NULL, "Sogdian"},
{"som", "so", "Somali"},
{"son", NULL, "Songhai"},
{"sot", "st", "Sotho, Southern"},
{"spa", "es", "Spanish; Castilian"},
{"srd", "sc", "Sardinian"},
{"srn", NULL, "Sranan Togo"},
{"scc/srp", "sr", "Serbian"}, // dual codes
{"srr", NULL, "Serer"},
{"ssa", NULL, "Nilo-Saharan (Other)"},
{"ssw", "ss", "Swati"},
{"suk", NULL, "Sukuma"},
{"sun", "su", "Sundanese"},
{"sus", NULL, "Susu"},
{"sux", NULL, "Sumerian"},
{"swa", "sw", "Swahili"},
{"swe", "sv", "Swedish"},
{"syr", NULL, "Syriac"},
{"tah", "ty", "Tahitian"},
{"tai", NULL, "Tai (Other)"},
{"tam", "ta", "Tamil"},
{"tat", "tt", "Tatar"},
{"tel", "te", "Telugu"},
{"tem", NULL, "Timne"},
{"ter", NULL, "Tereno"},
{"tet", NULL, "Tetum"},
{"tgk", "tg", "Tajik"},
{"tgl", "tl", "Tagalog"},
{"tha", "th", "Thai"},
{"tib/bod", "bo", "Tibetan"}, // dual codes
{"tig", NULL, "Tigre"},
{"tir", "ti", "Tigrinya"},
{"tiv", NULL, "Tiv"},
{"tkl", NULL, "Tokelau"},
{"tlh", NULL, "Klingon; tlhIngan-Hol"},
{"tli", NULL, "Tlingit"},
{"tmh", NULL, "Tamashek"},
{"tog", NULL, "Tonga (Nyasa)"},
{"ton", "to", "Tonga (Tonga Islands)"},
{"tpi", NULL, "Tok Pisin"},
{"tsi", NULL, "Tsimshian"},
{"tsn", "tn", "Tswana"},
{"tso", "ts", "Tsonga"},
{"tuk", "tk", "Turkmen"},
{"tum", NULL, "Tumbuka"},
{"tup", NULL, "Tupi languages"},
{"tur", "tr", "Turkish"},
{"tut", NULL, "Altaic (Other)"},
{"tvl", NULL, "Tuvalu"},
{"twi", "tw", "Twi"},
{"tyv", NULL, "Tuvinian"},
{"udm", NULL, "Udmurt"},
{"uga", NULL, "Ugaritic"},
{"uig", "ug", "Uighur; Uyghur"},
{"ukr", "uk", "Ukrainian"},
{"umb", NULL, "Umbundu"},
{"und", NULL, "Undetermined"},
{"urd", "ur", "Urdu"},
{"uzb", "uz", "Uzbek"},
{"vai", NULL, "Vai"},
{"ven", "ve", "Venda"},
{"vie", "vi", "Vietnamese"},
{"vol", "vo", "Volap\u00fck"},
{"vot", NULL, "Votic"},
{"wak", NULL, "Wakashan languages"},
{"wal", NULL, "Walamo"},
{"war", NULL, "Waray"},
{"was", NULL, "Washo"},
{"wel/cym", "cy", "Welsh"}, // //dual codes
{"wen", NULL, "Sorbian languages"},
{"wln", "wa", "Walloon"},
{"wol", "wo", "Wolof"},
{"xal", NULL, "Kalmyk; Oirat"},
{"xho", "xh", "Xhosa"},
{"yao", NULL, "Yao"},
{"yap", NULL, "Yapese"},
{"yid", "yi", "Yiddish"},
{"yor", "yo", "Yoruba"},
{"ypk", NULL, "Yupik languages"},
{"zap", NULL, "Zapotec"},
{"zen", NULL, "Zenaga"},
{"zha", "za", "Zhuang; Chuang"},
{"chi/zho", "zh", "Chinese"}, // dual codes
{"znd", NULL, "Zande"},
{"zul", "zu", "Zulu"},
{"zun", NULL, "Zuni"},
{"zxx", NULL, "No linguistic content"}};
m_ratings known_ratings[] = {
{"us-tv|TV-MA|600|", "TV-MA"},
{"us-tv|TV-14|500|", "TV-14"},
{"us-tv|TV-PG|400|", "TV-PG"},
{"us-tv|TV-G|300|", "TV-G"},
{"us-tv|TV-Y7|200|", "TV-Y7"},
{"us-tv|TV-Y|100|", "TV-Y"},
//{ "us-tv||0|", "not-applicable" }, //though its a valid flag &
// some files have this, AP won't be setting it.
{"mpaa|UNRATED|600|", "Unrated"},
{"mpaa|NC-17|500|", "NC-17"},
{"mpaa|R|400|", "R"},
{"mpaa|PG-13|300|", "PG-13"},
{"mpaa|PG|200|", "PG"},
{"mpaa|G|100|", "G"}
//{ "mpaa||0|", "not-applicable" } //see above
};
char *GenreIntToString(int genre) {
char *return_string = NULL;
if (genre > 0 &&
genre <= (int)(sizeof(ID3v1GenreList) / sizeof(*ID3v1GenreList))) {
return_string = (char *)ID3v1GenreList[genre - 1];
}
return return_string;
}
uint8_t StringGenreToInt(const char *genre_string) {
uint8_t return_genre = 0;
uint8_t total_genres =
(uint8_t)(sizeof(ID3v1GenreList) / sizeof(*ID3v1GenreList));
for (uint8_t i = 0; i < total_genres; i++) {
if (strcmp(genre_string, ID3v1GenreList[i]) == 0) {
return_genre =
i + 1; // the list starts at 0; the embedded genres start at 1
// fprintf(stdout, "Genre %s is %i\n", ID3v1GenreList[i], return_genre);
break;
}
}
if (return_genre > total_genres) {
return_genre = 0;
}
return return_genre;
}
void ListGenresValues() {
uint8_t total_genres =
(uint8_t)(sizeof(ID3v1GenreList) / sizeof(*ID3v1GenreList));
fprintf(stdout, "\tAvailable standard genres - case sensitive.\n");
for (uint8_t i = 0; i < total_genres; i++) {
fprintf(stdout, "(%i.) %s\n", i + 1, ID3v1GenreList[i]);
}
return;
}
stiks *MatchStikString(const char *in_stik_string) {
stiks *matching_stik = NULL;
uint8_t total_known_stiks = (sizeof(stikArray) / sizeof(*stikArray));
for (uint8_t i = 0; i < total_known_stiks; i++) {
if (strcmp(in_stik_string, stikArray[i].stik_string) == 0) {
matching_stik = &stikArray[i];
break;
}
}
return matching_stik;
}
stiks *MatchStikNumber(uint8_t in_stik_num) {
stiks *matching_stik = NULL;
uint8_t total_known_stiks = (sizeof(stikArray) / sizeof(*stikArray));
for (uint8_t i = 0; i < total_known_stiks; i++) {
if (stikArray[i].stik_number == in_stik_num) {
matching_stik = &stikArray[i];
break;
}
}
return matching_stik;
}
void ListStikValues() {
uint8_t total_known_stiks = (sizeof(stikArray) / sizeof(*stikArray));
fprintf(stdout,
"\tAvailable stik settings - case sensitive (number in "
"parens shows the stik value).\n");
for (uint8_t i = 0; i < total_known_stiks; i++) {
fprintf(stdout,
"(%u) %s\n",
stikArray[i].stik_number,
stikArray[i].stik_string);
}
return;
}
sfIDs *MatchStoreFrontNumber(uint32_t storefrontnum) {
sfIDs *matching_sfID = NULL;
uint8_t total_known_sfs = (sizeof(storefronts) / sizeof(*storefronts));
for (uint8_t i = 0; i < total_known_sfs; i++) {
if (storefronts[i].storefront_number == storefrontnum) {
matching_sfID = &storefronts[i];
break;
}
}
return matching_sfID;
}
bool MatchLanguageCode(const char *in_code) {
bool matching_lang = false;
uint16_t total_known_langs =
(uint16_t)(sizeof(known_languages) / sizeof(*known_languages));
for (uint16_t i = 0; i < total_known_langs; i++) {
if (strncmp(in_code, known_languages[i].iso639_2_code, 3) == 0) {
matching_lang = true;
break;
}
if (strlen(known_languages[i].iso639_2_code) > 3) {
if (strncmp(in_code, known_languages[i].iso639_2_code + 4, 3) == 0) {
matching_lang = true;
break;
}
}
}
return matching_lang;
}
void ListLanguageCodes() {
uint16_t total_known_langs =
(uint16_t)(sizeof(known_languages) / sizeof(*known_languages));
fprintf(stdout,
"\tAvailable language codes\nISO639-2 code ... English name:\n");
for (uint16_t i = 0; i < total_known_langs; i++) {
fprintf(stdout,
" %s ... %s\n",
known_languages[i].iso639_2_code,
known_languages[i].language_in_english);
}
return;
}
void ListMediaRatings() {
uint16_t total_known_ratings =
(uint16_t)(sizeof(known_ratings) / sizeof(*known_ratings));
fprintf(stdout, "\tAvailable ratings for the U.S. rating system:\n");
for (uint16_t i = 0; i < total_known_ratings; i++) {
fprintf(stdout, " %s\n", known_ratings[i].media_rating_cli_str);
}
return;
}
void ListTVGenreIDValues() {
uint16_t total_genreidtv = (uint16_t)(sizeof(genreidtv) / sizeof(*genreidtv));
fprintf(stdout, "\tAvailable iTunes TV Genre IDs:\n");
for (uint16_t i = 0; i < total_genreidtv; i++) {
fprintf(stdout,
"(%u) %s\n",
genreidtv[i].genre_id_tv_value,
genreidtv[i].genre_id_tv_string);
}
return;
}
void ListMovieGenreIDValues() {
uint16_t total_genreidmovie =
(uint16_t)(sizeof(genreidmovie) / sizeof(*genreidmovie));
fprintf(stdout, "\tAvailable iTunes Movie Genre IDs:\n");
for (uint16_t i = 0; i < total_genreidmovie; i++) {
fprintf(stdout,
"(%u) %s\n",
genreidmovie[i].genre_id_movie_value,
genreidmovie[i].genre_id_movie_string);
}
return;
}
const char *Expand_cli_mediastring(const char *cli_rating) {
const char *media_rating = NULL;
uint16_t total_known_ratings =
(uint16_t)(sizeof(known_ratings) / sizeof(*known_ratings));
uint8_t rating_len = strlen(cli_rating);
for (uint16_t i = 0; i < total_known_ratings; i++) {
if (strncasecmp(known_ratings[i].media_rating_cli_str,
cli_rating,
rating_len + 1) == 0) {
media_rating = known_ratings[i].media_rating;
break;
}
}
return media_rating;
}
// ID32 for ID3 frame functions
char *ID3GenreIntToString(int genre) {
char *return_string = NULL;
if (genre >= 0 && genre <= 79) {
return_string = (char *)ID3v1GenreList[genre];
}
return return_string;
}
uint8_t ID3StringGenreToInt(const char *genre_string) {
uint8_t return_genre = 0xFF;
uint8_t total_genres = 80;
for (uint8_t i = 0; i < total_genres; i++) {
if (strcmp(genre_string, ID3v1GenreList[i]) == 0) {
return i;
}
}
if (return_genre > total_genres) {
return_genre = 0xFF;
}
return return_genre;
}

95
src/compress.cpp Normal file
View File

@ -0,0 +1,95 @@
//==================================================================//
/*
AtomicParsley - compress.cpp
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C) 2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "AtomicParsley.h"
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
static void *zalloc(void *opaque, unsigned int items, unsigned int size) {
return calloc(items, size);
}
static void zfree(void *opaque, void *ptr) { free(ptr); }
/*----------------------
APar_zlib_inflate
in_buffer - pointer to already compressed data
in_buf_len - length of compressed data
out_buffer - pointer to a buffer to store decompressed/inflated data
out_buf_len - length of the out_buffer/max allowable decompressed size
fill
----------------------*/
void APar_zlib_inflate(char *in_buffer,
uint32_t in_buf_len,
char *out_buffer,
uint32_t out_buf_len) {
#if defined HAVE_ZLIB_H
z_stream zlib;
memset(&zlib, 0, sizeof(zlib));
// Decompress to another buffer
zlib.zalloc = zalloc;
zlib.zfree = zfree;
zlib.opaque = NULL;
zlib.avail_out = out_buf_len + 1;
zlib.next_out = (unsigned char *)out_buffer;
zlib.avail_in = in_buf_len;
zlib.next_in = (unsigned char *)in_buffer;
inflateInit(&zlib);
inflate(&zlib, Z_PARTIAL_FLUSH);
inflateEnd(&zlib);
#endif
return;
}
uint32_t APar_zlib_deflate(char *in_buffer,
uint32_t in_buf_len,
char *out_buffer,
uint32_t out_buf_len) {
uint32_t compressed_bytes = 0;
#if defined HAVE_ZLIB_H
z_stream zlib;
memset(&zlib, 0, sizeof(zlib));
// Compress(default level 6) to another buffer
zlib.zalloc = zalloc;
zlib.zfree = zfree;
zlib.opaque = NULL;
zlib.avail_out = out_buf_len + 1;
zlib.next_out = (unsigned char *)out_buffer;
zlib.avail_in = in_buf_len;
zlib.next_in = (unsigned char *)in_buffer;
zlib.total_out = 0;
deflateInit(&zlib, Z_DEFAULT_COMPRESSION);
if (Z_STREAM_END == deflate(&zlib, Z_FINISH)) {
compressed_bytes = zlib.total_out;
deflateEnd(&zlib);
}
#endif
return compressed_bytes;
}

1785
src/extracts.cpp Normal file

File diff suppressed because it is too large Load Diff

981
src/extras/getopt.c Normal file
View File

@ -0,0 +1,981 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98
Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.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, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
# define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
# ifndef const
# define const
# endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
# include <gnu-versions.h>
# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
# define ELIDE_CODE
# endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
# include <stdlib.h>
# include <unistd.h>
#endif /* GNU C library. */
#ifdef VMS
# include <unixlib.h>
# if HAVE_STRING_H - 0
# include <string.h>
# endif
#endif
#ifndef _
/* This is for other GNU distributions with internationalized messages.
When compiling libc, the _ macro is predefined. */
# ifdef HAVE_LIBINTL_H
# include <libintl.h>
# define _(msgid) gettext (msgid)
# else
# define _(msgid) (msgid)
# endif
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* 1003.2 says this must be 1 before any call. */
int optind = 1;
/* Formerly, initialization of getopt depended on optind==0, which
causes problems with re-calling getopt as programs generally don't
know that. */
int __getopt_initialized = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return -1 with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
# include <string.h>
# define my_index strchr
#else
#define HAVE_STRING_H 1
# if HAVE_STRING_H
# include <string.h>
# else
# include <strings.h>
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
#ifndef getenv
extern char *getenv ();
#endif
static char *
my_index (str, chr)
const char *str;
int chr;
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
# if (!defined __STDC__ || !__STDC__) && !defined strlen
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
# endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
#ifdef _LIBC
/* Bash 2.0 gives us an environment variable containing flags
indicating ARGV elements that should not be considered arguments. */
/* Defined in getopt_init.c */
extern char *__getopt_nonoption_flags;
static int nonoption_flags_max_len;
static int nonoption_flags_len;
static int original_argc;
static char *const *original_argv;
/* Make sure the environment variable bash 2.0 puts in the environment
is valid for the getopt call we must make sure that the ARGV passed
to getopt is that one passed to the process. */
static void
__attribute__ ((unused))
store_args_and_env (int argc, char *const *argv)
{
/* XXX This is no good solution. We should rather copy the args so
that we can compare them later. But we must not use malloc(3). */
original_argc = argc;
original_argv = argv;
}
# ifdef text_set_element
text_set_element (__libc_subinit, store_args_and_env);
# endif /* text_set_element */
# define SWAP_FLAGS(ch1, ch2) \
if (nonoption_flags_len > 0) \
{ \
char __tmp = __getopt_nonoption_flags[ch1]; \
__getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
__getopt_nonoption_flags[ch2] = __tmp; \
}
#else /* !_LIBC */
# define SWAP_FLAGS(ch1, ch2)
#endif /* _LIBC */
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
#if defined __STDC__ && __STDC__
static void exchange (char **);
#endif
static void
exchange (argv)
char **argv;
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
#ifdef _LIBC
/* First make sure the handling of the `__getopt_nonoption_flags'
string can work normally. Our top argument must be in the range
of the string. */
if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
{
/* We must extend the array. The user plays games with us and
presents new arguments. */
char *new_str = malloc (top + 1);
if (new_str == NULL)
nonoption_flags_len = nonoption_flags_max_len = 0;
else
{
memset (__mempcpy (new_str, __getopt_nonoption_flags,
nonoption_flags_max_len),
'\0', top + 1 - nonoption_flags_max_len);
nonoption_flags_max_len = top + 1;
__getopt_nonoption_flags = new_str;
}
}
#endif
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
SWAP_FLAGS (bottom + i, middle + i);
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
#if defined __STDC__ && __STDC__
static const char *_getopt_initialize (int, char *const *, const char *);
#endif
static const char *
_getopt_initialize (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
#ifdef _LIBC
if (posixly_correct == NULL
&& argc == original_argc && argv == original_argv)
{
if (nonoption_flags_max_len == 0)
{
if (__getopt_nonoption_flags == NULL
|| __getopt_nonoption_flags[0] == '\0')
nonoption_flags_max_len = -1;
else
{
const char *orig_str = __getopt_nonoption_flags;
int len = nonoption_flags_max_len = strlen (orig_str);
if (nonoption_flags_max_len < argc)
nonoption_flags_max_len = argc;
__getopt_nonoption_flags =
(char *) malloc (nonoption_flags_max_len);
if (__getopt_nonoption_flags == NULL)
nonoption_flags_max_len = -1;
else
memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
'\0', nonoption_flags_max_len - len);
}
}
nonoption_flags_len = nonoption_flags_max_len;
}
else
nonoption_flags_len = 0;
#endif
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns -1.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
optarg = NULL;
if (optind == 0 || !__getopt_initialized)
{
if (optind == 0)
optind = 1; /* Don't scan ARGV[0], the program name. */
optstring = _getopt_initialize (argc, argv, optstring);
__getopt_initialized = 1;
}
/* Test whether ARGV[optind] points to a non-option argument.
Either it does not have option syntax, or there is an environment flag
from the shell indicating it is not an option. The later information
is only used when the used in the GNU libc. */
#ifdef _LIBC
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
|| (optind < nonoption_flags_len \
&& __getopt_nonoption_flags[optind] == '1'))
#else
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
#endif
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
moved back by the user (who may also have changed the arguments). */
if (last_nonopt > optind)
last_nonopt = optind;
if (first_nonopt > optind)
first_nonopt = optind;
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc && NONOPTION_P)
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return -1;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if (NONOPTION_P)
{
if (ordering == REQUIRE_ORDER)
return -1;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = -1;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar)
== (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
_("%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
_("%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
optopt = 0;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, _("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, _("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
return '?';
}
/* Convenience. Treat POSIX -W foo same as long option --foo */
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr, _("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
/* optarg is now the argument, see if it's in the
table of longopts. */
for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar) == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
fprintf (stderr, _("\
%s: option `-W %s' doesn't allow an argument\n"),
argv[0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
nextchar = NULL;
return 'W'; /* Let the application handle it. */
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr,
_("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* Not ELIDE_CODE. */

127
src/extras/getopt.h Normal file
View File

@ -0,0 +1,127 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.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, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#ifdef __cplusplus
}
#endif
#endif /* getopt.h */

87
src/extras/getopt1.c Normal file
View File

@ -0,0 +1,87 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.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, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (int argc,
char *const *argv,
const char *options,
const struct option *long_options,
int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (int argc,
char *const *argv,
const char *options,
const struct option *long_options,
int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */

993
src/iconv.cpp Normal file
View File

@ -0,0 +1,993 @@
//==================================================================//
/*
AtomicParsley - iconv.cpp
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C) 2005-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
//==================================================================//
// utf conversion functions from libxml2
/*
Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is fur-
nished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Daniel Veillard shall not
be used in advertising or otherwise to promote the sale, use or other deal-
ings in this Software without prior written authorization from him.
*/
// Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" <duerst@w3.org>
#include "AtomicParsley.h"
const unsigned short cp437upperbytes[128] = {
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA,
0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6,
0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC,
0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA,
0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC,
0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561,
0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B,
0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568,
0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518,
0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393,
0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4,
0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320,
0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2,
0x25A0, 0x00A0};
const unsigned short cp850upperbytes[128] = {
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA,
0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6,
0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC,
0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA,
0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC,
0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1,
0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5,
0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00F0,
0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518,
0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4,
0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9,
0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6,
0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2,
0x25A0, 0x00A0};
const unsigned short cp852upperbytes[128] = {
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142,
0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139,
0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC,
0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA,
0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C,
0x015F, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1,
0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C,
0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x0111,
0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518,
0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, 0x00D3, 0x00DF, 0x00D4,
0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170,
0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8,
0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159,
0x25A0, 0x00A0};
const unsigned short cp855upperbytes[128] = {
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455,
0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409,
0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F,
0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411,
0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433,
0x0413, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445,
0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419,
0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x043B,
0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518,
0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, 0x042F, 0x0440, 0x0420,
0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432,
0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417,
0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7,
0x25A0, 0x00A0};
const unsigned short cp858upperbytes[128] = {
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA,
0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6,
0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC,
0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA,
0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC,
0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1,
0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5,
0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00F0,
0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE, 0x00CF, 0x2518,
0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4,
0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9,
0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6,
0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2,
0x25A0, 0x00A0};
//==================================================================//
// utf conversion functions from libxml2
/*
Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is fur-
nished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Daniel Veillard shall not
be used in advertising or otherwise to promote the sale, use or other deal-
ings in this Software without prior written authorization from him.
*/
// Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" <duerst@w3.org>
static int xmlLittleEndian =
#ifdef WORDS_BIGENDIAN
0
#else
1
#endif
;
/**
* isolat1ToUTF8:
* @out: a pointer to an array of bytes to store the result
* @outlen: the length of @out
* @in: a pointer to an array of ISO Latin 1 chars
* @inlen: the length of @in
*
* Take a block of ISO Latin 1 chars in and try to convert it to an UTF-8
* block of chars out.
* Returns the number of bytes written if success, or -1 otherwise
* The value of @inlen after return is the number of octets consumed
* if the return value is positive, else unpredictable.
* The value of @outlen after return is the number of octets consumed.
*/
int isolat1ToUTF8(unsigned char *out,
int outlen,
const unsigned char *in,
int inlen) {
unsigned char *outstart = out;
const unsigned char *base = in;
unsigned char *outend;
const unsigned char *inend;
const unsigned char *instop;
if ((out == NULL) || (in == NULL) || (outlen == 0) || (inlen == 0))
return (-1);
outend = out + outlen;
inend = in + (inlen);
instop = inend;
while (in < inend && out < outend - 1) {
if (*in >= 0x80) {
*out++ = (((*in) >> 6) & 0x1F) | 0xC0;
*out++ = ((*in) & 0x3F) | 0x80;
++in;
}
if (instop - in > outend - out)
instop = in + (outend - out);
while (in < instop && *in < 0x80) {
*out++ = *in++;
}
}
if (in < inend && out < outend && *in < 0x80) {
*out++ = *in++;
}
outlen = out - outstart;
inlen = in - base;
return (outlen);
}
/**
* UTF8Toisolat1:
* @out: a pointer to an array of bytes to store the result
* @outlen: the length of @out
* @in: a pointer to an array of UTF-8 chars
* @inlen: the length of @in
*
* Take a block of UTF-8 chars in and try to convert it to an ISO Latin 1
* block of chars out.
*
* Returns the number of bytes written if success, -2 if the transcoding fails,
or -1 otherwise
* The value of @inlen after return is the number of octets consumed
* if the return value is positive, else unpredictable.
* The value of @outlen after return is the number of octets consumed.
*/
int UTF8Toisolat1(unsigned char *out,
int outlen,
const unsigned char *in,
int inlen) {
const unsigned char *processed = in;
const unsigned char *outend;
const unsigned char *outstart = out;
const unsigned char *instart = in;
const unsigned char *inend;
unsigned int c, d;
int trailing;
if ((out == NULL) || (outlen == 0) || (inlen == 0))
return (-1);
if (in == NULL) {
/*
* initialization nothing to do
*/
outlen = 0;
inlen = 0;
return (0);
}
inend = in + (inlen);
outend = out + (outlen);
while (in < inend) {
d = *in++;
if (d < 0x80) {
c = d;
trailing = 0;
} else if (d < 0xC0) {
/* trailing byte in leading position */
outlen = out - outstart;
inlen = processed - instart;
return (-2);
} else if (d < 0xE0) {
c = d & 0x1F;
trailing = 1;
} else if (d < 0xF0) {
c = d & 0x0F;
trailing = 2;
} else if (d < 0xF8) {
c = d & 0x07;
trailing = 3;
} else {
/* no chance for this in IsoLat1 */
outlen = out - outstart;
inlen = processed - instart;
return (-2);
}
if (inend - in < trailing) {
break;
}
for (; trailing; trailing--) {
if (in >= inend)
break;
if (((d = *in++) & 0xC0) != 0x80) {
outlen = out - outstart;
inlen = processed - instart;
return (-2);
}
c <<= 6;
c |= d & 0x3F;
}
/* assertion: c is a single UTF-4 value */
if (c <= 0xFF) {
if (out >= outend)
break;
*out++ = c;
} else {
/* no chance for this in IsoLat1 */
outlen = out - outstart;
inlen = processed - instart;
return (-2);
}
processed = in;
}
outlen = out - outstart;
inlen = processed - instart;
return (outlen);
}
/**
* UTF16BEToUTF8:
* @out: a pointer to an array of bytes to store the result
* @outlen: the length of @out
* @inb: a pointer to an array of UTF-16 passed as a byte array
* @inlenb: the length of @in in UTF-16 chars
*
* Take a block of UTF-16 ushorts in and try to convert it to an UTF-8
* block of chars out. This function assumes the endian property
* is the same between the native type of this machine and the
* inputed one.
*
* Returns the number of bytes written, or -1 if lack of space, or -2
* if the transcoding fails (if *in is not a valid utf16 string)
* The value of *inlen after return is the number of octets consumed
* if the return value is positive, else unpredictable.
*/
int UTF16BEToUTF8(unsigned char *out,
int outlen,
const unsigned char *inb,
int inlenb) {
unsigned char *outstart = out;
const unsigned char *processed = inb;
unsigned char *outend = out + outlen;
unsigned short *in = (unsigned short *)inb;
unsigned short *inend;
unsigned int c, d, inlen;
unsigned char *tmp;
int bits;
if ((inlenb % 2) == 1)
(inlenb)--;
inlen = inlenb / 2;
inend = in + inlen;
while (in < inend) {
if (xmlLittleEndian) {
tmp = (unsigned char *)in;
c = *tmp++;
c = c << 8;
c = c | (unsigned int)*tmp;
in++;
} else {
c = *in++;
if (c == 0xFEFF) {
c = *in++; // skip BOM
}
}
if ((c & 0xFC00) == 0xD800) { /* surrogates */
if (in >= inend) { /* (in > inend) shouldn't happens */
outlen = out - outstart;
inlenb = processed - inb;
return (-2);
}
if (xmlLittleEndian) {
tmp = (unsigned char *)in;
d = *tmp++;
d = d << 8;
d = d | (unsigned int)*tmp;
in++;
} else {
d = *in++;
}
if ((d & 0xFC00) == 0xDC00) {
c &= 0x03FF;
c <<= 10;
c |= d & 0x03FF;
c += 0x10000;
} else {
outlen = out - outstart;
inlenb = processed - inb;
return (-2);
}
}
/* assertion: c is a single UTF-4 value */
if (out >= outend)
break;
if (c < 0x80) {
*out++ = c;
bits = -6;
} else if (c < 0x800) {
*out++ = ((c >> 6) & 0x1F) | 0xC0;
bits = 0;
} else if (c < 0x10000) {
*out++ = ((c >> 12) & 0x0F) | 0xE0;
bits = 6;
} else {
*out++ = ((c >> 18) & 0x07) | 0xF0;
bits = 12;
}
for (; bits >= 0; bits -= 6) {
if (out >= outend)
break;
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
processed = (const unsigned char *)in;
}
outlen = out - outstart;
inlenb = processed - inb;
return (outlen);
}
/**
* UTF8ToUTF16BE:
* @outb: a pointer to an array of bytes to store the result
* @outlen: the length of @outb
* @in: a pointer to an array of UTF-8 chars
* @inlen: the length of @in
*
* Take a block of UTF-8 chars in and try to convert it to an UTF-16BE
* block of chars out.
*
* Returns the number of byte written, or -1 by lack of space, or -2
* if the transcoding failed.
*/
int UTF8ToUTF16BE(unsigned char *outb,
int outlen,
const unsigned char *in,
int inlen) {
unsigned short *out = (unsigned short *)outb;
const unsigned char *processed = in;
const unsigned char *const instart = in;
unsigned short *outstart = out;
unsigned short *outend;
const unsigned char *inend = in + inlen;
unsigned int c, d;
int trailing;
unsigned char *tmp;
unsigned short tmp1, tmp2;
/* UTF-16BE has no BOM */
if ((outb == NULL) || (outlen == 0) || (inlen == 0))
return (-1);
if (in == NULL) {
outlen = 0;
inlen = 0;
return (0);
}
outend = out + (outlen / 2);
while (in < inend) {
d = *in++;
if (d < 0x80) {
c = d;
trailing = 0;
} else if (d < 0xC0) {
/* trailing byte in leading position */
outlen = out - outstart;
inlen = processed - instart;
return (-2);
} else if (d < 0xE0) {
c = d & 0x1F;
trailing = 1;
} else if (d < 0xF0) {
c = d & 0x0F;
trailing = 2;
} else if (d < 0xF8) {
c = d & 0x07;
trailing = 3;
} else {
/* no chance for this in UTF-16 */
outlen = out - outstart;
inlen = processed - instart;
return (-2);
}
if (inend - in < trailing) {
break;
}
for (; trailing; trailing--) {
if ((in >= inend) || (((d = *in++) & 0xC0) != 0x80))
break;
c <<= 6;
c |= d & 0x3F;
}
/* assertion: c is a single UTF-4 value */
if (c < 0x10000) {
if (out >= outend)
break;
if (xmlLittleEndian) {
tmp = (unsigned char *)out;
*tmp = c >> 8;
*(tmp + 1) = c;
out++;
} else {
*out++ = c;
}
} else if (c < 0x110000) {
if (out + 1 >= outend)
break;
c -= 0x10000;
if (xmlLittleEndian) {
tmp1 = 0xD800 | (c >> 10);
tmp = (unsigned char *)out;
*tmp = tmp1 >> 8;
*(tmp + 1) = (unsigned char)tmp1;
out++;
tmp2 = 0xDC00 | (c & 0x03FF);
tmp = (unsigned char *)out;
*tmp = tmp2 >> 8;
*(tmp + 1) = (unsigned char)tmp2;
out++;
} else {
*out++ = 0xD800 | (c >> 10);
*out++ = 0xDC00 | (c & 0x03FF);
}
} else
break;
processed = in;
}
outlen = (out - outstart) * 2;
inlen = processed - instart;
return (outlen);
}
/**
* UTF16LEToUTF8:
* @out: a pointer to an array of bytes to store the result
* @outlen: the length of @out
* @inb: a pointer to an array of UTF-16LE passwd as a byte array
* @inlenb: the length of @in in UTF-16LE chars
*
* Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8
* block of chars out. This function assumes the endian property
* is the same between the native type of this machine and the
* inputed one.
*
* Returns the number of bytes written, or -1 if lack of space, or -2
* if the transcoding fails (if *in is not a valid utf16 string)
* The value of *inlen after return is the number of octets consumed
* if the return value is positive, else unpredictable.
*/
int UTF16LEToUTF8(unsigned char *out,
int outlen,
const unsigned char *inb,
int inlenb) {
unsigned char *outstart = out;
const unsigned char *processed = inb;
unsigned char *outend = out + outlen;
unsigned short *in = (unsigned short *)inb;
unsigned short *inend;
unsigned int c, d, inlen;
unsigned char *tmp;
int bits;
if ((inlenb % 2) == 1)
(inlenb)--;
inlen = inlenb / 2;
inend = in + inlen;
while ((in < inend) && (out - outstart + 5 < outlen)) {
if (xmlLittleEndian) {
c = *in++;
} else {
tmp = (unsigned char *)in;
c = *tmp++;
c = c | (((unsigned int)*tmp) << 8);
in++;
}
if ((c & 0xFC00) == 0xD800) { /* surrogates */
if (in >= inend) { /* (in > inend) shouldn't happens */
break;
}
if (xmlLittleEndian) {
d = *in++;
} else {
tmp = (unsigned char *)in;
d = *tmp++;
d = d | (((unsigned int)*tmp) << 8);
in++;
}
if ((d & 0xFC00) == 0xDC00) {
c &= 0x03FF;
c <<= 10;
c |= d & 0x03FF;
c += 0x10000;
} else {
outlen = out - outstart;
inlenb = processed - inb;
return (-2);
}
}
/* assertion: c is a single UTF-4 value */
if (out >= outend)
break;
if (c < 0x80) {
*out++ = c;
bits = -6;
} else if (c < 0x800) {
*out++ = ((c >> 6) & 0x1F) | 0xC0;
bits = 0;
} else if (c < 0x10000) {
*out++ = ((c >> 12) & 0x0F) | 0xE0;
bits = 6;
} else {
*out++ = ((c >> 18) & 0x07) | 0xF0;
bits = 12;
}
for (; bits >= 0; bits -= 6) {
if (out >= outend)
break;
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
processed = (const unsigned char *)in;
}
outlen = out - outstart;
inlenb = processed - inb;
return (outlen);
}
/**
* UTF8ToUTF16LE:
* @outb: a pointer to an array of bytes to store the result
* @outlen: the length of @outb
* @in: a pointer to an array of UTF-8 chars
* @inlen: the length of @in
*
* Take a block of UTF-8 chars in and try to convert it to an UTF-16LE
* block of chars out.
*
* Returns the number of bytes written, or -1 if lack of space, or -2
* if the transcoding failed.
*/
int UTF8ToUTF16LE(unsigned char *outb,
int outlen,
const unsigned char *in,
int inlen) {
unsigned short *out = (unsigned short *)outb;
const unsigned char *processed = in;
const unsigned char *const instart = in;
unsigned short *outstart = out;
unsigned short *outend;
const unsigned char *inend = in + inlen;
unsigned int c, d;
int trailing;
unsigned char *tmp;
unsigned short tmp1, tmp2;
/* UTF16LE encoding has no BOM */
if ((out == NULL) || (outlen == 0) || (inlen == 0))
return (-1);
if (in == NULL) {
outlen = 0;
inlen = 0;
return (0);
}
outend = out + (outlen / 2);
while (in < inend) {
d = *in++;
if (d < 0x80) {
c = d;
trailing = 0;
} else if (d < 0xC0) {
/* trailing byte in leading position */
outlen = (out - outstart) * 2;
inlen = processed - instart;
return (-2);
} else if (d < 0xE0) {
c = d & 0x1F;
trailing = 1;
} else if (d < 0xF0) {
c = d & 0x0F;
trailing = 2;
} else if (d < 0xF8) {
c = d & 0x07;
trailing = 3;
} else {
/* no chance for this in UTF-16 */
outlen = (out - outstart) * 2;
inlen = processed - instart;
return (-2);
}
if (inend - in < trailing) {
break;
}
for (; trailing; trailing--) {
if ((in >= inend) || (((d = *in++) & 0xC0) != 0x80))
break;
c <<= 6;
c |= d & 0x3F;
}
/* assertion: c is a single UTF-4 value */
if (c < 0x10000) {
if (out >= outend)
break;
if (xmlLittleEndian) {
*out++ = c;
} else {
tmp = (unsigned char *)out;
*tmp = c;
*(tmp + 1) = c >> 8;
out++;
}
} else if (c < 0x110000) {
if (out + 1 >= outend)
break;
c -= 0x10000;
if (xmlLittleEndian) {
*out++ = 0xD800 | (c >> 10);
*out++ = 0xDC00 | (c & 0x03FF);
} else {
tmp1 = 0xD800 | (c >> 10);
tmp = (unsigned char *)out;
*tmp = (unsigned char)tmp1;
*(tmp + 1) = tmp1 >> 8;
out++;
tmp2 = 0xDC00 | (c & 0x03FF);
tmp = (unsigned char *)out;
*tmp = (unsigned char)tmp2;
*(tmp + 1) = tmp2 >> 8;
out++;
}
} else
break;
processed = in;
}
outlen = (out - outstart) * 2;
inlen = processed - instart;
return (outlen);
}
int isUTF8(const char *in_string) {
// fprintf(stdout, "utf8 test-> %s\n", in_string);
int str_bytes = 0;
if (in_string != NULL) {
str_bytes = strlen(in_string);
} else {
return -1;
}
bool is_validUTF8 = true;
bool is_high_ascii = false;
int index = 0;
while (index < str_bytes && is_validUTF8) {
char achar = in_string[index];
int supplemental_bytes = 0;
if ((unsigned char)achar > 0x80) {
is_high_ascii = true;
}
if ((achar & 0x80) == 0) { // 0xxxxxxx
++index;
} else if ((achar & 0xF8) == 0xF0) { // 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++index;
supplemental_bytes = 3;
is_high_ascii = true;
} else if ((achar & 0xE0) == 0xE0) { // 1110zzzz 10yyyyyy 10xxxxxx
++index;
supplemental_bytes = 2;
is_high_ascii = true;
} else if ((achar & 0xE0) == 0xC0) { // 110yyyyy 10xxxxxx
++index;
supplemental_bytes = 1;
is_high_ascii = true;
} else {
is_validUTF8 = false;
}
while (is_validUTF8 && supplemental_bytes--) {
if (index >= str_bytes) {
is_validUTF8 = false;
} else if ((in_string[index++] & 0xC0) != 0x80) { // 10uuzzzz
is_validUTF8 = false;
}
}
}
if (is_high_ascii) {
return 8;
} else if (is_validUTF8) {
return 1;
} else {
return 0;
}
}
/*----------------------
utf8_length
in_string - pointer to location of a utf8 string
char_limit - either 0 (count all characters) or non-zero (limit utf8 to
that character count)
Because of the lovely way utf8 is aligned, test only the first byte in each.
If char_limit is 0, return the number of CHARACTERS in the string, if the
char_limit is not zero (the char_limit will equal
utf_string_leghth because of the break), so change gears, save space and just
return the byte_count.
----------------------*/
#include <stdio.h>
unsigned int utf8_length(const char *in_string, unsigned int char_limit) {
const char *utf8_str = in_string;
unsigned int utf8_string_length = 0;
unsigned int in_str_len = strlen(in_string);
unsigned int byte_count = 0;
unsigned int bytes_in_char = 0;
if (in_string == NULL)
return 0;
while (byte_count < in_str_len) {
bytes_in_char = 0;
if ((*utf8_str & 0x80) == 0x00)
bytes_in_char = 1;
else if ((*utf8_str & 0xE0) == 0xC0)
bytes_in_char = 2;
else if ((*utf8_str & 0xF0) == 0xE0)
bytes_in_char = 3;
else if ((*utf8_str & 0xF8) == 0xF0)
bytes_in_char = 4;
if (bytes_in_char > 0) {
utf8_string_length++;
utf8_str += bytes_in_char;
byte_count += bytes_in_char;
} else {
break;
}
if (char_limit != 0 && char_limit == utf8_string_length) {
utf8_string_length = byte_count;
break;
}
}
return utf8_string_length;
}
#if defined(_WIN32) && !defined(__CYGWIN__)
unsigned char APar_Return_rawutf8_CP(unsigned short cp_bound_glyph) {
unsigned short total_known_points = 0;
unsigned int win32cp = GetConsoleCP();
if (win32cp == 437 || win32cp == 850 || win32cp == 852 || win32cp == 855 ||
win32cp == 858) {
total_known_points = 128;
} else {
if (cp_bound_glyph >= 0x0080) {
exit(win32cp);
}
}
if (cp_bound_glyph < 0x0080) {
return cp_bound_glyph << 0;
} else if (total_known_points) {
if (win32cp == 437) {
for (uint16_t i = 0; i < total_known_points; i++) {
if (cp_bound_glyph == cp437upperbytes[i]) {
return i + 128;
}
}
} else if (win32cp == 850) {
for (uint16_t i = 0; i < total_known_points; i++) {
if (cp_bound_glyph == cp850upperbytes[i]) {
return i + 128;
}
}
} else if (win32cp == 852) {
for (uint16_t i = 0; i < total_known_points; i++) {
if (cp_bound_glyph == cp852upperbytes[i]) {
return i + 128;
}
}
} else if (win32cp == 855) {
for (uint16_t i = 0; i < total_known_points; i++) {
if (cp_bound_glyph == cp855upperbytes[i]) {
return i + 128;
}
}
} else if (win32cp == 858) {
for (uint16_t i = 0; i < total_known_points; i++) {
if (cp_bound_glyph == cp858upperbytes[i]) {
return i + 128;
}
}
} else {
fprintf(stderr,
"AtomicParsley error: this windows codepage(%u) is "
"unsupported.\nProvide the output of the 'CPTester' utility run "
"from the bat script\n",
win32cp);
exit(win32cp);
}
}
return 0;
}
int strip_bogusUTF16toRawUTF8(unsigned char *out,
int inlen,
wchar_t *in,
int outlen) {
unsigned char *outstart = out;
unsigned char *outend;
const wchar_t *inend;
const wchar_t *instop;
if ((out == NULL) || (in == NULL) || (outlen == 0) || (inlen == 0))
return (-1);
outend = out + outlen;
inend = in + (inlen);
instop = inend;
while (in < inend && out < outend - 1) {
*out++ = APar_Return_rawutf8_CP(*in); //*in << 0;
++in;
}
outlen = out - outstart;
return (outlen);
}
#endif
/*----------------------
test_conforming_alpha_string
in_string - pointer to location of a utf8 string
limit string to A-Z or a-z
----------------------*/
int test_conforming_alpha_string(char *in_string) {
int valid_bytes = 0;
int string_len = 0;
char *test_str = in_string;
if (in_string != NULL) {
string_len = strlen(in_string);
} else {
return -1;
}
while (valid_bytes < string_len) {
if ((*test_str >= 65 && *test_str <= 90) ||
(*test_str >= 97 && *test_str <= 122) || *test_str == 95 ||
(*test_str >= 48 && *test_str <= 57)) {
valid_bytes++;
} else {
break;
}
test_str++;
}
return valid_bytes;
}
bool test_limited_ascii(char *in_string, unsigned int str_len) {
char *test_str = in_string;
while (test_str < in_string + str_len) {
if (*test_str < 32 || *test_str > 126) {
return false;
}
test_str++;
}
return true;
}

3119
src/id3v2.cpp Normal file

File diff suppressed because it is too large Load Diff

68
src/id3v2.h Normal file
View File

@ -0,0 +1,68 @@
//==================================================================//
/*
AtomicParsley - id3v2.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
struct AdjunctArgs {
const char *targetLang;
const char *descripArg;
const char *mimeArg;
const char *pictypeArg;
const char *filenameArg;
const char *ratingArg;
const char *dataArg; // multipurposed: PRIV's binary data, GRID's group data,
// UFID's binary data, POPM's counter field
uint8_t pictype_uint8;
uint8_t groupSymbol;
bool zlibCompressed;
bool multistringtext;
};
uint64_t syncsafeXX_to_UInt64(char *syncsafe_int, uint8_t syncsafe_len);
uint32_t syncsafe32_to_UInt32(char *syncsafe_int);
bool ID3v2_TestTagFlag(uint8_t TagFlag, uint8_t TagBit);
bool ID3v2_TestFrameFlag(uint16_t FrameFlag, uint16_t FrameBit);
uint8_t ImageListMembers();
void ListID3FrameIDstrings();
void List_imagtype_strings();
const char *ConvertCLIFrameStr_TO_frameID(const char *frame_str);
bool TestCLI_for_FrameParams(int frametype, uint8_t testparam);
int MatchID3FrameIDstr(const char *foundFrameID, uint8_t tagVersion);
uint8_t GetFrameCompositionDescription(int ID3v2_FrameTypeID);
int FrameStr_TO_FrameType(const char *frame_str);
void APar_ID32_ScanID3Tag(FILE *source_file, AtomicInfo *id32_atom);
uint32_t APar_GetTagSize(AtomicInfo *id32_atom);
uint32_t APar_Render_ID32_Tag(AtomicInfo *id32_atom, uint32_t max_alloc);
char *APar_ConvertField_to_UTF8(ID3v2Frame *targetframe, int fieldtype);
void APar_ID3Tag_Init(AtomicInfo *id32_atom);
void APar_ID3FrameAmmend(AtomicInfo *id32_atom,
const char *frame_str,
const char *frame_payload,
AdjunctArgs *adjunct_payloads,
uint8_t str_encoding);
void APar_FreeID32Memory(ID3v2Tag *id32tag);

597
src/id3v2defs.h Normal file
View File

@ -0,0 +1,597 @@
//==================================================================//
/*
AtomicParsley - id3v2defs.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
ID3FrameDefinition KnownFrames[] = {
{"", "", "", "Unknown frame", "", ID3v2_UNKNOWN_FRAME, ID3_UNKNOWN_FRAME},
{"TAL",
"TALB",
"TALB",
"Album/Movie/Show title",
"album",
ID3v2_FRAME_ALBUM,
ID3_TEXT_FRAME},
{"TBP",
"TBPM",
"TBPM",
"BPM (beats per minute)",
"bpm",
ID3v2_FRAME_BPM,
ID3_TEXT_FRAME},
{"TCM",
"TCOM",
"TCOM",
"Composer",
"composer",
ID3v2_FRAME_COMPOSER,
ID3_TEXT_FRAME},
{"TCO",
"TCON",
"TCON",
"Content Type/Genre",
"genre",
ID3v2_FRAME_CONTENTTYPE,
ID3_TEXT_FRAME},
{"TCP",
"TCOP",
"TCOP",
"Copyright message",
"copyright",
ID3v2_FRAME_COPYRIGHT,
ID3_TEXT_FRAME},
{"",
"",
"TDEN",
"Encoding time",
"",
ID3v2_FRAME_ENCODINGTIME,
ID3_TEXT_FRAME},
{"TDY",
"TDLY",
"TDLY",
"Playlist delay",
"",
ID3v2_FRAME_PLAYLISTDELAY,
ID3_TEXT_FRAME},
{"",
"",
"TDOR",
"Original release time",
"",
ID3v2_FRAME_ORIGRELTIME,
ID3_TEXT_FRAME},
{"",
"",
"TDRC",
"Recording time",
"date",
ID3v2_FRAME_RECORDINGTIME,
ID3_TEXT_FRAME},
{"",
"",
"TDRL",
"Release time",
"released",
ID3v2_FRAME_RELEASETIME,
ID3_TEXT_FRAME},
{"",
"",
"TDTG",
"Tagging time",
"tagged",
ID3v2_FRAME_TAGGINGTIME,
ID3_TEXT_FRAME},
{"TEN",
"TENC",
"TENC",
"Encoded by",
"encoder",
ID3v2_FRAME_ENCODER,
ID3_TEXT_FRAME},
{"TXT",
"TEXT",
"TEXT",
"Lyricist/Text writer",
"writer",
ID3v2_FRAME_LYRICIST,
ID3_TEXT_FRAME},
{"TFT",
"TFLT",
"TFLT",
"File type",
"",
ID3v2_FRAME_FILETYPE,
ID3_TEXT_FRAME},
{"",
"",
"TIPL",
"Involved people list",
"",
ID3v2_FRAME_INVOLVEDPEOPLE,
ID3_TEXT_FRAME},
{"TT1",
"TIT1",
"TIT1",
"Content group description",
"grouping",
ID3v2_FRAME_GROUP_DESC,
ID3_TEXT_FRAME},
{"TT2",
"TIT2",
"TIT2",
"Title/songname/content description",
"title",
ID3v2_FRAME_TITLE,
ID3_TEXT_FRAME},
{"TT3",
"TIT3",
"TIT3",
"Subtitle/Description refinement",
"subtitle",
ID3v2_FRAME_SUBTITLE,
ID3_TEXT_FRAME},
{"TKE",
"TKEY",
"TKEY",
"Initial key",
"",
ID3v2_FRAME_INITIALKEY,
ID3_TEXT_FRAME},
{"TLA",
"TLAN",
"TLAN",
"Language(s)",
"",
ID3v2_FRAME_LANGUAGE,
ID3_TEXT_FRAME},
{"TLE",
"TLEN",
"TLEN",
"Length",
"",
ID3v2_FRAME_TIMELENGTH,
ID3_TEXT_FRAME},
{"",
"",
"TMCL",
"Musician credits list",
"credits",
ID3v2_FRAME_MUSICIANLIST,
ID3_TEXT_FRAME},
{"TMT",
"TMED",
"TMED",
"Media type",
"media",
ID3v2_FRAME_MEDIATYPE,
ID3_TEXT_FRAME},
{"", "", "TMOO", "Mood", "mood", ID3v2_FRAME_MOOD, ID3_TEXT_FRAME},
{"TOT",
"TOAL",
"TOAL",
"Original album/movie/show title",
"",
ID3v2_FRAME_ORIGALBUM,
ID3_TEXT_FRAME},
{"TOF",
"TOFN",
"TOFN",
"Original filename",
"",
ID3v2_FRAME_ORIGFILENAME,
ID3_TEXT_FRAME},
{"TOL",
"TOLY",
"TOLY",
"Original lyricist(s)/text writer(s)",
"",
ID3v2_FRAME_ORIGWRITER,
ID3_TEXT_FRAME},
{"TOA",
"TOPE",
"TOPE",
"Original artist(s)/performer(s)",
"",
ID3v2_FRAME_ORIGARTIST,
ID3_TEXT_FRAME},
{"",
"TOWN",
"TOWN",
"File owner/licensee",
"",
ID3v2_FRAME_FILEOWNER,
ID3_TEXT_FRAME},
{"TP1",
"TPE1",
"TPE1",
"Artist/Lead performer(s)/Soloist(s)",
"artist",
ID3v2_FRAME_ARTIST,
ID3_TEXT_FRAME},
{"TP2",
"TPE2",
"TPE2",
"Album artist/Band/orchestra/accompaniment",
"album artist",
ID3v2_FRAME_ALBUMARTIST,
ID3_TEXT_FRAME},
{"TP3",
"TPE3",
"TPE3",
"Conductor/performer refinement",
"conductor",
ID3v2_FRAME_CONDUCTOR,
ID3_TEXT_FRAME},
{"TP4",
"TPE4",
"TPE4",
"Interpreted or remixed by",
"remixer",
ID3v2_FRAME_REMIXER,
ID3_TEXT_FRAME},
{"TPA",
"TPOS",
"TPOS",
"Part of a set",
"",
ID3v2_FRAME_PART_O_SET,
ID3_TEXT_FRAME},
{"",
"",
"TPRO",
"Produced notice",
"",
ID3v2_FRAME_PRODNOTICE,
ID3_TEXT_FRAME},
{"TPB",
"TPUB",
"TPUB",
"Publisher",
"publisher",
ID3v2_FRAME_PUBLISHER,
ID3_TEXT_FRAME},
{"TRK",
"TRCK",
"TRCK",
"Track number/Position in set",
"trk#",
ID3v2_FRAME_TRACKNUM,
ID3_TEXT_FRAME},
{"",
"TRSN",
"TRSN",
"Internet radio station name",
"",
ID3v2_FRAME_IRADIONAME,
ID3_TEXT_FRAME},
{"",
"TRSO",
"TRSO",
"Internet radio station owner",
"",
ID3v2_FRAME_IRADIOOWNER,
ID3_TEXT_FRAME},
{"",
"",
"TSOA",
"Album sort order",
"",
ID3v2_FRAME_ALBUMSORT,
ID3_TEXT_FRAME},
{"",
"",
"TSOP",
"Performer sort order",
"",
ID3v2_FRAME_PERFORMERSORT,
ID3_TEXT_FRAME},
{"",
"",
"TSOT",
"Title sort order",
"",
ID3v2_FRAME_TITLESORT,
ID3_TEXT_FRAME},
{"TRC", "TSRC", "TSRC", "ISRC", "", ID3v2_FRAME_ISRC, ID3_TEXT_FRAME},
{"TSS",
"TSSE",
"TSSE",
"Software/Hardware and settings used for encoding",
"",
ID3v2_FRAME_ENCODINGSETTINGS,
ID3_TEXT_FRAME},
{"",
"",
"TSST",
"Set subtitle",
"",
ID3v2_FRAME_SETSUBTITLE,
ID3_TEXT_FRAME},
{"TDA", "TDAT", "", "Date", "", ID3v2_DATE, ID3_TEXT_FRAME},
{"TIM", "TIME", "", "TIME", "", ID3v2_TIME, ID3_TEXT_FRAME},
{"TOR",
"TORY",
"",
"Original Release Year",
"",
ID3v2_ORIGRELYEAR,
ID3_TEXT_FRAME},
{"TRD",
"TRDA",
"",
"Recording dates",
"",
ID3v2_RECORDINGDATE,
ID3_TEXT_FRAME},
{"TSI", "TSIZ", "", "Size", "", ID3v2_FRAME_SIZE, ID3_TEXT_FRAME},
{"TYE", "TYER", "", "YEAR", "", ID3v2_FRAME_YEAR, ID3_TEXT_FRAME},
{"TXX",
"TXXX",
"TXXX",
"User defined text information frame",
"",
ID3v2_FRAME_USERDEF_TEXT,
ID3_TEXT_FRAME_USERDEF},
// some of these (like WCOM, WOAF) allow for muliple frames - but (sigh)
// alas, such is not the case in AP.
{"WCM",
"WCOM",
"WCOM",
"Commercial information",
"",
ID3v2_FRAME_URLCOMMINFO,
ID3_URL_FRAME},
{"WCP",
"WCOP",
"WCOP",
"Copyright/Legal information",
"",
ID3v2_FRAME_URLCOPYRIGHT,
ID3_URL_FRAME},
{"WAF",
"WOAF",
"WOAF",
"Official audio file webpage",
"",
ID3v2_FRAME_URLAUDIOFILE,
ID3_URL_FRAME},
{"WAR",
"WOAR",
"WOAR",
"Official artist/performer webpage",
"",
ID3v2_FRAME_URLARTIST,
ID3_URL_FRAME},
{"WAS",
"WOAS",
"WOAS",
"Official audio source webpage",
"",
ID3v2_FRAME_URLAUDIOSOURCE,
ID3_URL_FRAME},
{"",
"WORS",
"WORS",
"Official Internet radio station homepage",
"",
ID3v2_FRAME_URLIRADIO,
ID3_URL_FRAME},
{"", "WPAY", "WPAY", "Payment", "", ID3v2_FRAME_URLPAYMENT, ID3_URL_FRAME},
{"WPB",
"WPUB",
"WPUB",
"Publishers official webpage",
"",
ID3v2_FRAME_URLPUBLISHER,
ID3_URL_FRAME},
{"WXX",
"WXXX",
"WXXX",
"User defined URL link frame",
"",
ID3v2_FRAME_USERDEF_URL,
ID3_URL_FRAME_USERDEF},
{"UFI",
"UFID",
"UFID",
"Unique file identifier",
"",
ID3v2_FRAME_UFID,
ID3_UNIQUE_FILE_ID_FRAME},
{"MCI",
"MCID",
"MCDI",
"Music CD Identifier",
"",
ID3v2_FRAME_MUSIC_CD_ID,
ID3_CD_ID_FRAME},
{"COM",
"COMM",
"COMM",
"Comment",
"comment",
ID3v2_FRAME_COMMENT,
ID3_DESCRIBED_TEXT_FRAME},
{"ULT",
"USLT",
"USLT",
"Unsynchronised lyrics",
"lyrics",
ID3v2_FRAME_UNSYNCLYRICS,
ID3_DESCRIBED_TEXT_FRAME},
{"",
"APIC",
"APIC",
"Attached picture",
"",
ID3v2_EMBEDDED_PICTURE,
ID3_ATTACHED_PICTURE_FRAME},
{"PIC",
"",
"",
"Attached picture",
"",
ID3v2_EMBEDDED_PICTURE_V2P2,
ID3_OLD_V2P2_PICTURE_FRAME},
{"GEO",
"GEOB",
"GEOB",
"Attached object",
"",
ID3v2_EMBEDDED_OBJECT,
ID3_ATTACHED_OBJECT_FRAME},
{"",
"GRID",
"GRID",
"Group ID registration",
"",
ID3v2_FRAME_GRID,
ID3_GROUP_ID_FRAME},
{"",
"",
"SIGN",
"Signature",
"",
ID3v2_FRAME_SIGNATURE,
ID3_SIGNATURE_FRAME},
{"",
"PRIV",
"PRIV",
"Private frame",
"",
ID3v2_FRAME_PRIVATE,
ID3_PRIVATE_FRAME},
{"CNT",
"PCNT",
"PCNT",
"Play counter",
"",
ID3v2_FRAME_PLAYCOUNTER,
ID3_PLAYCOUNTER_FRAME},
{"POP",
"POPM",
"POPM",
"Popularimeter",
"",
ID3v2_FRAME_POPULARITY,
ID3_POPULAR_FRAME}
};
// the field listing array is mostly used for mental clarification instead of
// internal use - frames are parsed/rendered hardcoded irrespective of ordering
// here
ID3v2FieldDefinition FrameTypeConstructionList[] = {
{ID3_UNKNOWN_FRAME, 1, {ID3_UNKNOWN_FIELD}},
{ID3_TEXT_FRAME, 2, {ID3_TEXT_ENCODING_FIELD, ID3_TEXT_FIELD}},
{ID3_TEXT_FRAME_USERDEF,
3,
{ID3_TEXT_ENCODING_FIELD, ID3_DESCRIPTION_FIELD, ID3_TEXT_FIELD}},
{ID3_URL_FRAME, 1, {ID3_URL_FIELD}},
{ID3_URL_FRAME_USERDEF,
3,
{ID3_TEXT_ENCODING_FIELD, ID3_DESCRIPTION_FIELD, ID3_URL_FIELD}},
{ID3_UNIQUE_FILE_ID_FRAME, 2, {ID3_OWNER_FIELD, ID3_BINARY_DATA_FIELD}},
{ID3_CD_ID_FRAME, 1, {ID3_BINARY_DATA_FIELD}},
{ID3_DESCRIBED_TEXT_FRAME,
4,
{ID3_TEXT_ENCODING_FIELD,
ID3_LANGUAGE_FIELD,
ID3_DESCRIPTION_FIELD,
ID3_TEXT_FIELD}},
{ID3_ATTACHED_PICTURE_FRAME,
5,
{ID3_TEXT_ENCODING_FIELD,
ID3_MIME_TYPE_FIELD,
ID3_PIC_TYPE_FIELD,
ID3_DESCRIPTION_FIELD,
ID3_BINARY_DATA_FIELD}},
{ID3_ATTACHED_OBJECT_FRAME,
5,
{ID3_TEXT_ENCODING_FIELD,
ID3_MIME_TYPE_FIELD,
ID3_FILENAME_FIELD,
ID3_DESCRIPTION_FIELD,
ID3_BINARY_DATA_FIELD}},
{ID3_GROUP_ID_FRAME,
3,
{ID3_OWNER_FIELD, ID3_GROUPSYMBOL_FIELD, ID3_BINARY_DATA_FIELD}},
{ID3_SIGNATURE_FRAME, 2, {ID3_GROUPSYMBOL_FIELD, ID3_BINARY_DATA_FIELD}},
{ID3_PRIVATE_FRAME, 2, {ID3_OWNER_FIELD, ID3_BINARY_DATA_FIELD}},
{ID3_PLAYCOUNTER_FRAME, 1, {ID3_COUNTER_FIELD}},
{ID3_POPULAR_FRAME,
3,
{ID3_OWNER_FIELD, ID3_BINARY_DATA_FIELD, ID3_COUNTER_FIELD}},
{ID3_OLD_V2P2_PICTURE_FRAME,
5,
{ID3_TEXT_ENCODING_FIELD,
ID3_IMAGEFORMAT_FIELD,
ID3_PIC_TYPE_FIELD,
ID3_DESCRIPTION_FIELD,
ID3_BINARY_DATA_FIELD}}};
// used to determine mimetype for APIC image writing
ImageFileFormatDefinition ImageList[] = {
{"image/jpeg", ".jpg", 3, "\xFF\xD8\xFF"},
{"image/png", ".png", 8, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"},
{"image/pdf", ".pdf", 7, "%PDF-1."},
{"image/jp2",
".jp2",
12,
"\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A\x00\x00\x00\x14\x66\x74"
"\x79\x70\x6A\x70\x32\x20"},
{"image/gif", ".gif", 6, "GIF89a"},
{"image/tiff", ".tiff", 4, "\x4D\x4D\x00\x2A"},
{"image/tiff", ".tiff", 4, "\x49\x49\x2A\x00"},
{"image/bmp", ".bmp", 2, "\x42\x4D"},
{"image/bmp", ".bmp", 2, "\x42\x41"},
{"image/photoshop", ".psd", 4, "8BPS"},
{"image/other", ".img", 0, ""}};
ID3ImageType ImageTypeList[] = {
{0x00, "0x00", "Other"},
{0x01, "0x01", "32x32 pixels 'file icon' (PNG only)"},
{0x02, "0x02", "Other file icon"},
{0x03, "0x03", "Cover (front)"},
{0x04, "0x04", "Cover (back)"},
{0x05, "0x05", "Leaflet page"},
{0x06, "0x06", "Media (e.g. label side of CD)"},
{0x07, "0x07", "Lead artist/lead performer/soloist"},
{0x08, "0x08", "Artist/performer"},
{0x09, "0x09", "Conductor"},
{0x0A, "0x0A", "Band/Orchestra"},
{0x0B, "0x0B", "Composer"},
{0x0C, "0x0C", "Lyricist/text writer"},
{0x0D, "0x0D", "Recording Location"},
{0x0E, "0x0E", "During recording"},
{0x0F, "0x0F", "During performance"},
{0x10, "0x10", "Movie/video screen capture"},
{0x11, "0x11", "A bright coloured fish"},
{0x12, "0x12", "Illustration"},
{0x13, "0x13", "Band/artist logotype"},
{0x14, "0x14", "Publisher/Studio logotype"}};

280
src/id3v2types.h Normal file
View File

@ -0,0 +1,280 @@
//==================================================================//
/*
AtomicParsley - id3v2types.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
enum ID3_FieldTypes {
ID3_UNKNOWN_FIELD = -1,
ID3_TEXT_FIELD,
ID3_TEXT_ENCODING_FIELD,
ID3_OWNER_FIELD, // UFID,PRIV
ID3_DESCRIPTION_FIELD, // TXXX, WXXX
ID3_URL_FIELD,
ID3_LANGUAGE_FIELD, // USLT
ID3_MIME_TYPE_FIELD, // APIC
ID3_PIC_TYPE_FIELD, // APIC
ID3_BINARY_DATA_FIELD, // APIC,GEOB
ID3_FILENAME_FIELD, // GEOB
ID3_GROUPSYMBOL_FIELD,
ID3_COUNTER_FIELD,
ID3_IMAGEFORMAT_FIELD // PIC in v2.2
};
// the order of these frame types must exactly match the order listed in the
// FrameTypeConstructionList[] array!!!
enum ID3v2FrameType {
ID3_UNKNOWN_FRAME = -1,
ID3_TEXT_FRAME,
ID3_TEXT_FRAME_USERDEF,
ID3_URL_FRAME,
ID3_URL_FRAME_USERDEF,
ID3_UNIQUE_FILE_ID_FRAME,
ID3_CD_ID_FRAME,
ID3_DESCRIBED_TEXT_FRAME, // oy... these frames (COMM, USLT) can differ by
// description
ID3_ATTACHED_PICTURE_FRAME,
ID3_ATTACHED_OBJECT_FRAME,
ID3_GROUP_ID_FRAME,
ID3_SIGNATURE_FRAME,
ID3_PRIVATE_FRAME,
ID3_PLAYCOUNTER_FRAME,
ID3_POPULAR_FRAME,
ID3_OLD_V2P2_PICTURE_FRAME
};
// the order of these frames must exactly match the order listed in the
// KnownFrames[] array!!!
enum ID3v2FrameIDs {
ID3v2_UNKNOWN_FRAME = -1,
ID3v2_FRAME_ALBUM,
ID3v2_FRAME_BPM,
ID3v2_FRAME_COMPOSER,
ID3v2_FRAME_CONTENTTYPE,
ID3v2_FRAME_COPYRIGHT,
ID3v2_FRAME_ENCODINGTIME,
ID3v2_FRAME_PLAYLISTDELAY,
ID3v2_FRAME_ORIGRELTIME,
ID3v2_FRAME_RECORDINGTIME,
ID3v2_FRAME_RELEASETIME,
ID3v2_FRAME_TAGGINGTIME,
ID3v2_FRAME_ENCODER,
ID3v2_FRAME_LYRICIST,
ID3v2_FRAME_FILETYPE,
ID3v2_FRAME_INVOLVEDPEOPLE,
ID3v2_FRAME_GROUP_DESC,
ID3v2_FRAME_TITLE,
ID3v2_FRAME_SUBTITLE,
ID3v2_FRAME_INITIALKEY,
ID3v2_FRAME_LANGUAGE,
ID3v2_FRAME_TIMELENGTH,
ID3v2_FRAME_MUSICIANLIST,
ID3v2_FRAME_MEDIATYPE,
ID3v2_FRAME_MOOD,
ID3v2_FRAME_ORIGALBUM,
ID3v2_FRAME_ORIGFILENAME,
ID3v2_FRAME_ORIGWRITER,
ID3v2_FRAME_ORIGARTIST,
ID3v2_FRAME_FILEOWNER,
ID3v2_FRAME_ARTIST,
ID3v2_FRAME_ALBUMARTIST,
ID3v2_FRAME_CONDUCTOR,
ID3v2_FRAME_REMIXER,
ID3v2_FRAME_PART_O_SET,
ID3v2_FRAME_PRODNOTICE,
ID3v2_FRAME_PUBLISHER,
ID3v2_FRAME_TRACKNUM,
ID3v2_FRAME_IRADIONAME,
ID3v2_FRAME_IRADIOOWNER,
ID3v2_FRAME_ALBUMSORT,
ID3v2_FRAME_PERFORMERSORT,
ID3v2_FRAME_TITLESORT,
ID3v2_FRAME_ISRC,
ID3v2_FRAME_ENCODINGSETTINGS,
ID3v2_FRAME_SETSUBTITLE,
ID3v2_DATE,
ID3v2_TIME,
ID3v2_ORIGRELYEAR,
ID3v2_RECORDINGDATE,
ID3v2_FRAME_SIZE,
ID3v2_FRAME_YEAR,
ID3v2_FRAME_USERDEF_TEXT,
ID3v2_FRAME_URLCOMMINFO,
ID3v2_FRAME_URLCOPYRIGHT,
ID3v2_FRAME_URLAUDIOFILE,
ID3v2_FRAME_URLARTIST,
ID3v2_FRAME_URLAUDIOSOURCE,
ID3v2_FRAME_URLIRADIO,
ID3v2_FRAME_URLPAYMENT,
ID3v2_FRAME_URLPUBLISHER,
ID3v2_FRAME_USERDEF_URL,
ID3v2_FRAME_UFID,
ID3v2_FRAME_MUSIC_CD_ID,
ID3v2_FRAME_COMMENT,
ID3v2_FRAME_UNSYNCLYRICS,
ID3v2_EMBEDDED_PICTURE,
ID3v2_EMBEDDED_PICTURE_V2P2,
ID3v2_EMBEDDED_OBJECT,
ID3v2_FRAME_GRID,
ID3v2_FRAME_SIGNATURE,
ID3v2_FRAME_PRIVATE,
ID3v2_FRAME_PLAYCOUNTER,
ID3v2_FRAME_POPULARITY
};
enum ID3v2_TagFlags {
ID32_TAGFLAG_BIT0 = 0x01,
ID32_TAGFLAG_BIT1 = 0x02,
ID32_TAGFLAG_BIT2 = 0x04,
ID32_TAGFLAG_BIT3 = 0x08,
ID32_TAGFLAG_FOOTER = 0x10,
ID32_TAGFLAG_EXPERIMENTAL = 0x20,
ID32_TAGFLAG_EXTENDEDHEADER = 0x40,
ID32_TAGFLAG_UNSYNCRONIZATION = 0x80
};
enum ID3v2_FrameFlags {
ID32_FRAMEFLAG_STATUS = 0x4000,
ID32_FRAMEFLAG_PRESERVE = 0x2000,
ID32_FRAMEFLAG_READONLY = 0x1000,
ID32_FRAMEFLAG_GROUPING = 0x0040,
ID32_FRAMEFLAG_COMPRESSED = 0x0008,
ID32_FRAMEFLAG_ENCRYPTED = 0x0004,
ID32_FRAMEFLAG_UNSYNCED = 0x0002,
ID32_FRAMEFLAG_LENINDICATED = 0x0001
};
// the wording of the ID3 (v2.4 in this case) 'informal standard' is not always
// replete with clarity. text encodings are worded as having a NULL terminator
// (8or16bit), even for the body of text frames with that in hand, then a
// description field from COMM should look much like a utf8 text field and yet
// for TXXX, description is expressely worded as:
//
// "The frame body consists of a description of the string, represented as a
// terminated string, followed by the actual string."
//
// Description <text string according to encoding> $00 (00)
// Value <text string according to encoding>
//
// Note how description is expressly *worded* as having a NULL terminator, but
// the text field is not. GEOB text clarifies things better: "The first two
// strings [mime & filename] may be omitted, leaving only their terminations.
//
// MIME type <text string> $00
// Filename <text string according to encoding> $00 (00)
//
// so these trailing $00 (00) are the terminators for the strings - not
// separators between n-length string fields. If the string is devoid of
// content (not NULLed out, but *devoid* of info), then the only thing that
// should exist is for a utf16 BOM to exist on text encoding 0x01. The
// (required) terminator for mime & filename are specifically enumerated in the
// frame format, which matches the wording of the frame description. ...and so
// AP does not terminate text fields
//
// Further sealing the case is the reference implementation for id3v2.3
// (id3lib) doesn't terminate text fields:
//
// http://sourceforge.net/project/showfiles.php?group_id=979&package_id=4679
enum text_encodings {
TE_LATIN1 = 0,
TE_UTF16LE_WITH_BOM = 1,
TE_UTF16BE_NO_BOM = 2,
TE_UTF8 = 3
};
// Structure that defines the (subset) known ID3 frames defined by id3 informal
// specification.
typedef struct {
const char *ID3V2p2_FrameID;
const char *ID3V2p3_FrameID;
const char *ID3V2p4_FrameID;
const char *ID3V2_FrameDescription;
const char *CLI_frameIDpreset;
int ID3v2_InternalFrameID;
int ID3v2_FrameType;
} ID3FrameDefinition;
typedef struct {
const char *image_mimetype;
const char *image_fileextn;
uint8_t image_testbytes;
const char *image_binaryheader;
} ImageFileFormatDefinition;
typedef struct {
uint8_t hexcode;
const char *hexstring;
const char *imagetype_str;
} ID3ImageType;
// Structure that defines how any ID3v2FrameType is constructed, listing an
// array of its constituent ID3_FieldTypes
typedef struct {
ID3v2FrameType ID3_FrameType;
uint8_t ID3_FieldCount;
ID3_FieldTypes ID3_FieldComponents[5]; // max known to be tested
} ID3v2FieldDefinition;
struct ID3v2Fields {
int ID3v2_Field_Type;
uint32_t field_length;
uint32_t alloc_length;
char *field_string;
ID3v2Fields *next_field;
};
struct ID3v2Frame {
char ID3v2_Frame_Namestr[5];
uint32_t ID3v2_Frame_Length; // this is the real length, not a syncsafe int;
// note: does not include frame ID (like 'TIT2',
// 'TCO' - 3or4 bytes) or frame flags (2bytes)
uint16_t ID3v2_Frame_Flags;
// these next 2 values can be potentially be stored based on bitsetting in
// frame flags;
uint8_t ID3v2_Frame_GroupingSymbol;
uint32_t ID3v2_Frame_ExpandedLength;
int ID3v2_Frame_ID;
int ID3v2_FrameType;
uint8_t ID3v2_FieldCount;
uint8_t textfield_tally;
ID3v2Fields *ID3v2_Frame_Fields; // malloc
ID3v2Frame *ID3v2_NextFrame;
bool eliminate_frame;
};
struct ID3v2Tag {
uint8_t ID3v2Tag_MajorVersion;
uint8_t ID3v2Tag_RevisionVersion;
uint8_t ID3v2Tag_Flags;
uint32_t ID3v2Tag_Length; // this is a bonafide uint_32_t length, not a
// syncsafe int
// this extended header section depends on a bitsetting in ID3v2Tag_Flags
uint32_t
ID3v2_Tag_ExtendedHeader_Length; // the entire extended header section is
// unimplemented flags & flag frames
ID3v2Frame *ID3v2_FirstFrame;
ID3v2Frame *ID3v2_FrameList;
uint16_t ID3v2_FrameCount;
bool modified_tag;
};

4482
src/main.cpp Normal file

File diff suppressed because it is too large Load Diff

2163
src/metalist.cpp Normal file

File diff suppressed because it is too large Load Diff

182
src/nsfile.mm Normal file
View File

@ -0,0 +1,182 @@
//==================================================================//
/*
AtomicParsley - nsfile.mm
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "AtomicParsley.h"
#import <Cocoa/Cocoa.h>
/*----------------------
APar_TestTracksForKind
By testing which tracks are contained within the file, for Mac OS X we can avoid having to change file extension by instead using Finder.app metadata to signal
the same info as file extension. For each trak atom, find the 'stsd' atom - its ancillary_data will contain the track type that is contained - the info is filled
in as the file was initially parsed in APar_ScanAtoms. Then using Mac OS X Cocoa calls (in AP_NSFile_utils), set the Finder TYPE/CREATOR codes to signal to the
OS/Finder/iTunes that this file is .m4a or .m4v without having to change its extension based on what the tracks actually contain.
There are 2 issues with this - iTunes requires the Quicktime player type/creator codes for video that has multi-channel audio, and for chapterized video files.
TODO: address these issues.
----------------------*/
void APar_TestTracksForKind() {
uint8_t total_tracks = 0;
uint8_t track_num = 0;
AtomicInfo* codec_atom = NULL; //short codec_atom = 0;
//With track_num set to 0, it will return the total trak atom into total_tracks here.
APar_FindAtomInTrack(total_tracks, track_num, NULL);
if (total_tracks > 0) {
while (total_tracks > track_num) {
track_num+= 1;
codec_atom = APar_FindAtomInTrack(total_tracks, track_num, "stsd");
if (codec_atom == NULL) return;
//now test this trak's stsd codec against these 4cc codes:
switch(codec_atom->ancillary_data) {
//video types
case 0x61766331 : // "avc1"
track_codecs.has_avc1 = true;
break;
case 0x6D703476 : // "mp4v"
track_codecs.has_mp4v = true;
break;
case 0x64726D69 : // "drmi"
track_codecs.has_drmi = true;
break;
//audio types
case 0x616C6163 : // "alac"
track_codecs.has_alac = true;
break;
case 0x6D703461 : // "mp4a"
track_codecs.has_mp4a = true;
break;
case 0x64726D73 : // "drms"
track_codecs.has_drms = true;
break;
//chapterized types (audio podcasts or movies)
case 0x74657874 : // "text"
track_codecs.has_timed_text = true;
break;
case 0x6A706567 : // "jpeg"
track_codecs.has_timed_jpeg = true;
break;
//either podcast type (audio-only) or timed text subtitles
case 0x74783367 : // "tx3g"
track_codecs.has_timed_tx3g = true;
break;
//other
case 0x6D703473 : // "mp4s"
track_codecs.has_mp4s = true;
break;
case 0x72747020 : // "rtp "
track_codecs.has_rtp_hint = true;
break;
}
}
}
return;
}
//TODO: there is a problem with this code seen in: "5.1channel audio-orig.mp4"
//it makes no difference what the file contains, iTunes won't see any (ANY) metadata if its hook/'M4A '.
//in fact, iTunes won't play the file at all
//changing the exact file (with all kinds of metadata) to TVOD/mpg4 - iTunes can play it fine, but doesn't fetch any metadata
//
//it might be beneficial to eval for channels and if its audio only & multichannel to NOT change the TYPE/creator codes
uint32_t APar_4CC_CreatorCode(const char* filepath, uint32_t new_type_code) {
uint32_t return_value = 0;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *inFile = [NSString stringWithUTF8String: filepath];
if (new_type_code) {
NSNumber* creator_code = [NSNumber numberWithUnsignedLong:'hook'];
NSNumber* type_code = [NSNumber numberWithUnsignedLong:new_type_code];
NSDictionary* output_attributes = [NSDictionary dictionaryWithObjectsAndKeys:creator_code, NSFileHFSCreatorCode,
type_code, NSFileHFSTypeCode, nil];
if (![[NSFileManager defaultManager] changeFileAttributes:output_attributes atPath:inFile]) {
NSLog(@" AtomicParsley error: setting type and creator code on %@", inFile);
}
} else {
NSDictionary* file_attributes = [[NSFileManager defaultManager] fileAttributesAtPath:inFile traverseLink:YES];
return_value = [[file_attributes objectForKey:NSFileHFSTypeCode] unsignedLongValue ];
//NSLog(@"code: %@\n", [file_attributes objectForKey:NSFileHFSTypeCode] );
}
[pool release];
return return_value;
}
//there is a scenario that is as of now unsupported (or botched, depending if you use the feature), although it would be easy to implement. To make a file bookmarkable, the TYPE code is set to 'M4B ' - which can be *also* done by changing the extension to ".m4b". However, due to the way that the file is tested here, a ".mp4" with 'M4B ' type code will get changed into a normal audio file (not-bookmarkable).
void APar_SupplySelectiveTypeCreatorCodes(const char *inputPath, const char *outputPath, uint8_t forced_type_code) {
if (forced_type_code != NO_TYPE_FORCING) {
if (forced_type_code == FORCE_M4B_TYPE) {
APar_4CC_CreatorCode(outputPath, 'M4B ');
}
return;
}
const char* input_suffix = strrchr(inputPath, '.');
//user-defined output paths may have the original file as ".m4a" & show up fine when output to ".m4a"
//output to ".mp4" and it becomes a generic (sans TYPE/CREATOR) file that defaults to Quicktime Player
const char* output_suffix = strrchr(outputPath, '.');
char* typecode = (char*)malloc( sizeof(char)* 4 );
memset(typecode, 0, sizeof(char)*4);
uint32_t type_code = APar_4CC_CreatorCode(inputPath, 0);
UInt32_TO_String4(type_code, typecode);
//fprintf(stdout, "%s - %s\n", typecode, input_suffix);
APar_TestTracksForKind();
if (strncasecmp(input_suffix, ".mp4", 4) == 0 || strncasecmp(output_suffix, ".mp4", 4) == 0) { //only work on the generic .mp4 extension
if (track_codecs.has_avc1 || track_codecs.has_mp4v || track_codecs.has_drmi) {
type_code = APar_4CC_CreatorCode(outputPath, 'M4V ');
//for a podcast an audio track with either a text, jpeg or url track is required, otherwise it will fall through to generic m4a;
//files that are already .m4b or 'M4B ' don't even enter into this situation, so they are safe
//if the file had video with subtitles (tx3g), then it would get taken care of above in the video section - unsupported by QT currently
} else if (track_codecs.has_mp4a && (track_codecs.has_timed_text || track_codecs.has_timed_jpeg || track_codecs.has_timed_tx3g) ) {
type_code = APar_4CC_CreatorCode(outputPath, 'M4B ');
//default to audio; technically so would a drms iTMS drm audio file with ".mp4". But that would also mean it was renamed. They should be 'M4P '
} else {
type_code = APar_4CC_CreatorCode(outputPath, 'M4A ');
}
} else if (track_codecs.has_avc1 || track_codecs.has_mp4v || track_codecs.has_drmi) {
type_code = APar_4CC_CreatorCode(outputPath, 'M4V ');
}
return;
}

244
src/nsimage.mm Normal file
View File

@ -0,0 +1,244 @@
//==================================================================//
/*
AtomicParsley - nsimage.mm
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2005-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "AtomicParsley.h"
#import <Cocoa/Cocoa.h>
bool isJPEG=false;
bool isPNG=false;
void DetermineType(const char *picfilePath) {
char* picHeader = (char*)calloc(1, sizeof(char)*20);
u_int64_t r;
FILE *pic_file = NULL;
pic_file = fopen(picfilePath, "rb");
r = fread(picHeader, 8, 1, pic_file);
fclose(pic_file);
if (memcmp(picHeader, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) == 0) {
isPNG=true;
isJPEG=false;
} else if (memcmp(picHeader, "\xFF\xD8\xFF", 3) == 0) {
isJPEG=true;
isPNG=false;
}
free(picHeader);
picHeader=NULL;
return;
}
char* DeriveNewPath(const char *filePath, PicPrefs myPicPrefs, char* newpath) {
const char* suffix = strrchr(filePath, '.');
size_t filepath_len = strlen(filePath);
memset(newpath, 0, MAXPATHLEN+1);
size_t base_len = filepath_len-strlen(suffix);
memcpy(newpath, filePath, base_len);
memcpy(newpath+base_len, "-resized-", 9);
char* randstring = (char*)calloc(1, sizeof(char)*20);
struct timeval tv;
gettimeofday (&tv, NULL);
srand( (int) tv.tv_usec / 1000 ); //Seeds rand()
int randNum = rand()%10000;
sprintf(randstring, "%i", randNum);
strcat(newpath, randstring);
if (myPicPrefs.allJPEG) {
strcat(newpath, ".jpg");
} else if (myPicPrefs.allPNG) {
strcat(newpath, ".png");
} else {
strcat(newpath, suffix);
}
if ( (strncmp(suffix,".jpg",4) == 0) || (strncmp(suffix,".jpeg",5) == 0) || (strncmp(suffix,".JPG",4) == 0) || (strncmp(suffix,".JPEG",5) == 0) ) {
isJPEG=true;
} else if ((strncmp(suffix,".png",4) == 0) || (strncmp(suffix,".PNG",4) == 0)) {
isPNG=true;
}
free(randstring);
randstring=NULL;
return newpath;
}
bool ResizeGivenImage(const char* filePath, PicPrefs myPicPrefs, char* resized_path) {
bool resize = false;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSImage* source = [ [NSImage alloc] initWithContentsOfFile: [NSString stringWithUTF8String: filePath] ];
[source setScalesWhenResized: YES];
if ( source == nil ) {
fprintf( stderr, "Image '%s' could not be loaded.\n", filePath );
exit (1);
}
NSSize sourceSize = [source size];
float hmax, vmax, aspect;
hmax = sourceSize.width;
vmax = sourceSize.height;
aspect = sourceSize.height / sourceSize.width;
//fprintf(stdout, "aspect %f2.4\n", aspect);
if (myPicPrefs.max_dimension != 0) {
if ( ( (int)sourceSize.width > myPicPrefs.max_dimension) || ( (int)sourceSize.height > myPicPrefs.max_dimension) ) {
resize = true; //only if dimensions are LARGER than our max do we resize
if (hmax > vmax) {
hmax = myPicPrefs.max_dimension;
vmax = myPicPrefs.max_dimension * aspect;
} else {
hmax = myPicPrefs.max_dimension / aspect;
vmax = myPicPrefs.max_dimension;
}
}
}
///// determine dpi/ppi
float hres, vres, hdpi, vdpi;
NSImageRep *myRep = [[source representations] objectAtIndex:0];
hres = [myRep pixelsWide]; //native pixel dimensions
vres = [myRep pixelsHigh];
hdpi = hres/sourceSize.width; //in native resolution (multiply by 72 to get native dpi)
vdpi = vres/sourceSize.height;
if ( ( (int)hdpi != 1 ) || ( (int)vdpi != 1) ) {
resize = true;
hmax = hres;
vmax = vres;
if (myPicPrefs.max_dimension != 0) {
//we also need to recheck we don't go over our max dimensions (again)
if ( ( (int)hres > myPicPrefs.max_dimension) || ( (int)vres > myPicPrefs.max_dimension) ) {
if (hmax > vmax) {
hmax = myPicPrefs.max_dimension;
vmax = myPicPrefs.max_dimension * aspect;
} else {
hmax = myPicPrefs.max_dimension / aspect;
vmax = myPicPrefs.max_dimension;
}
}
}
}
if (myPicPrefs.squareUp) {
if (myPicPrefs.max_dimension != 0) {
vmax = myPicPrefs.max_dimension;
hmax = myPicPrefs.max_dimension;
resize = true;
} else {
//this will stretch the image to the largest dimension. Hope you don't try to scale a 160x1200 image... it could get ugly
if (hmax > vmax) {
vmax = hmax;
resize = true;
} else if (vmax > hmax) {
hmax = vmax;
resize = true;
}
}
}
if (myPicPrefs.force_dimensions) {
if (myPicPrefs.force_height > 0 && myPicPrefs.force_width > 0) {
vmax = myPicPrefs.force_height;
hmax = myPicPrefs.force_width;
resize = true;
}
}
uint64_t pic_file_size = findFileSize(filePath);
if ( ( (int)pic_file_size > myPicPrefs.max_Kbytes) && ( myPicPrefs.max_Kbytes != 0) ) {
resize = true;
}
DetermineType(filePath);
if ( (isJPEG && myPicPrefs.allPNG) || (isPNG && myPicPrefs.allJPEG) ) { //handle jpeg->png & png->jpg conversion
resize = true;
}
NSRect destinationRect = NSMakeRect( 0, 0, hmax, vmax );
NSSize size = NSMakeSize( hmax, vmax );
if (resize) {
[NSApplication sharedApplication];
[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
[source setSize: size];
NSImage* image = [[NSImage alloc] initWithSize:size];
[image lockFocus];
NSEraseRect( destinationRect );
[source drawInRect: destinationRect
fromRect: destinationRect
operation: NSCompositeCopy fraction: 1.0];
NSBitmapImageRep* bitmap = [ [NSBitmapImageRep alloc]
initWithFocusedViewRect: destinationRect ];
NSBitmapImageFileType filetype;
NSDictionary *props;
if ( (isPNG && !myPicPrefs.allJPEG) || myPicPrefs.allPNG) {
filetype = NSPNGFileType;
props = nil;
} else {
filetype = NSJPEGFileType;
props = [ NSDictionary dictionaryWithObject:
[NSNumber numberWithFloat: 0.7] forKey: NSImageCompressionFactor];
}
NSData* data = [bitmap representationUsingType:filetype properties:props];
unsigned dataLength = [data length]; //holds the file length
int iter = 0;
float compression = 0.65;
if ( (myPicPrefs.max_Kbytes != 0) && (filetype == NSJPEGFileType) ) {
while ( (dataLength > (unsigned)myPicPrefs.max_Kbytes) && (iter < 10) ) {
props = [ NSDictionary dictionaryWithObject:
[NSNumber numberWithFloat: compression] forKey: NSImageCompressionFactor];
data = [bitmap representationUsingType:filetype properties:props];
dataLength = [data length];
compression = compression - 0.05;
iter++;
}
}
[bitmap release];
NSString *outFile= [NSString stringWithUTF8String: DeriveNewPath(filePath, myPicPrefs, resized_path)];
//NSLog(outFile);
[[NSFileManager defaultManager]
createFileAtPath: outFile
contents: data
attributes: nil ];
[image unlockFocus];
[image release];
isJPEG=false;
isPNG=false;
memcpy(resized_path, [outFile cStringUsingEncoding: NSUTF8StringEncoding], [outFile lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
}
[source release];
[pool release];
return resize;
}

6537
src/parsley.cpp Normal file

File diff suppressed because it is too large Load Diff

402
src/sha1.cpp Normal file
View File

@ -0,0 +1,402 @@
/* sha1.cpp - Functions to compute SHA1 message digest of files or
memory blocks according to the NIST specification FIPS-180-1.
Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, 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, or (at your option) any
later version.
This program is distributed in the hope that 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. */
/* Written by Scott G. Miller
Credits:
Robert Klep <robert@ilse.nl> -- Expansion function fix
*/
/*
This file has been modified from the original found in
http://www.gnu.org/software/coreutils/ coreutils-5.97 for use within
AtomicParsley. Modifications are : endian detection change a cast for
compiling under g++ file renaming eliminated SWAP in favor of swap32 & swap16
in util.h alignment macros (for msvc)
*/
#include "AtomicParsley.h"
/* SWAP does an endian swap on architectures that are little-endian,
as SHA1 needs some data in a big-endian form. */
/*
#if defined (__ppc__) || defined (__ppc64__)
# define SWAP(n) (n)
#else
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#endif
*/
#define BLOCKSIZE 4096
#if BLOCKSIZE % 64 != 0
#error "invalid BLOCKSIZE"
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
/*
Takes a pointer to a 160 bit block of data (five 32 bit ints) and
intializes it to the start constants of the SHA1 algorithm. This
must be called before using hash in the call to sha1_hash.
*/
void sha1_init_ctx(struct sha1_ctx *ctx) {
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->E = 0xc3d2e1f0;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Put result from CTX in first 20 bytes following RESBUF. The result
must be in little endian byte order.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
void *sha1_read_ctx(const struct sha1_ctx *ctx, void *resbuf) {
((md5_uint32 *)resbuf)[0] = SWAP32(ctx->A);
((md5_uint32 *)resbuf)[1] = SWAP32(ctx->B);
((md5_uint32 *)resbuf)[2] = SWAP32(ctx->C);
((md5_uint32 *)resbuf)[3] = SWAP32(ctx->D);
((md5_uint32 *)resbuf)[4] = SWAP32(ctx->E);
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
void *sha1_finish_ctx(struct sha1_ctx *ctx, void *resbuf) {
/* Take yet unprocessed bytes into account. */
md5_uint32 bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy(&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
*(md5_uint32 *)&ctx->buffer[bytes + pad + 4] = SWAP32(ctx->total[0] << 3);
*(md5_uint32 *)&ctx->buffer[bytes + pad] =
SWAP32((ctx->total[1] << 3) | (ctx->total[0] >> 29));
/* Process last bytes. */
sha1_process_block(ctx->buffer, bytes + pad + 8, ctx);
return sha1_read_ctx(ctx, resbuf);
}
/* Compute SHA1 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
int sha1_stream(FILE *stream, void *resblock) {
struct sha1_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
/* Initialize the computation context. */
sha1_init_ctx(&ctx);
/* Iterate over full file contents. */
while (1) {
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
computation function processes the whole buffer so that with the
next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
while (1) {
n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
if (sum == BLOCKSIZE)
break;
if (n == 0) {
/* Check for the error flag IFF N == 0, so that we don't
exit the loop after a partial read due to e.g., EAGAIN
or EWOULDBLOCK. */
if (ferror(stream))
return 1;
goto process_partial_block;
}
/* We've read at least one byte, so ignore errors. But always
check for EOF, since feof may be true even though N > 0.
Otherwise, we could end up calling fread after EOF. */
if (feof(stream))
goto process_partial_block;
}
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
*/
sha1_process_block(buffer, BLOCKSIZE, &ctx);
}
process_partial_block:;
/* Process any remaining bytes. */
if (sum > 0)
sha1_process_bytes(buffer, sum, &ctx);
/* Construct result in desired memory. */
sha1_finish_ctx(&ctx, resblock);
return 0;
}
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *sha1_buffer(const char *buffer, size_t len, void *resblock) {
struct sha1_ctx ctx;
/* Initialize the computation context. */
sha1_init_ctx(&ctx);
/* Process whole buffer but last len % 64 bytes. */
sha1_process_bytes(buffer, len, &ctx);
/* Put result in desired memory area. */
return sha1_finish_ctx(&ctx, resblock);
}
void sha1_process_bytes(const void *buffer, size_t len, struct sha1_ctx *ctx) {
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0) {
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy(&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64) {
sha1_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
}
buffer = (const char *)buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64) {
#if !_STRING_ARCH_unaligned
#define alignof(type) \
offsetof( \
struct { \
char c; \
type x; \
}, \
x)
#define UNALIGNED_P(p) \
(((size_t)p) % 4 != \
0) //# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0)
if (UNALIGNED_P(buffer))
while (len > 64) {
sha1_process_block(memcpy(ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *)buffer + 64;
len -= 64;
}
else
#endif
{
sha1_process_block(buffer, len & ~63, ctx);
buffer = (const char *)buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0) {
size_t left_over = ctx->buflen;
memcpy(&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 64) {
sha1_process_block(ctx->buffer, 64, ctx);
left_over -= 64;
memcpy(ctx->buffer, &ctx->buffer[64], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between md5.c and sha1.c --- */
/* SHA1 round constants */
#define K1 0x5a827999L
#define K2 0x6ed9eba1L
#define K3 0x8f1bbcdcL
#define K4 0xca62c1d6L
/* Round functions. Note that F2 is the same as F4. */
#define F1(B, C, D) (D ^ (B & (C ^ D)))
#define F2(B, C, D) (B ^ C ^ D)
#define F3(B, C, D) ((B & C) | (D & (B | C)))
#define F4(B, C, D) (B ^ C ^ D)
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */
void sha1_process_block(const void *buffer, size_t len, struct sha1_ctx *ctx) {
const md5_uint32 *words = (md5_uint32 *)buffer;
size_t nwords = len / sizeof(md5_uint32);
const md5_uint32 *endp = words + nwords;
md5_uint32 x[16];
md5_uint32 a = ctx->A;
md5_uint32 b = ctx->B;
md5_uint32 c = ctx->C;
md5_uint32 d = ctx->D;
md5_uint32 e = ctx->E;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define M(I) \
(tm = x[I & 0x0f] ^ x[(I - 14) & 0x0f] ^ x[(I - 8) & 0x0f] ^ \
x[(I - 3) & 0x0f], \
(x[I & 0x0f] = rol(tm, 1)))
#define R(A, B, C, D, E, F, K, M) \
do { \
E += rol(A, 5) + F(B, C, D) + K + M; \
B = rol(B, 30); \
} while (0)
while (words < endp) {
md5_uint32 tm;
int t;
for (t = 0; t < 16; t++) {
x[t] = SWAP32(*words);
words++;
}
R(a, b, c, d, e, F1, K1, x[0]);
R(e, a, b, c, d, F1, K1, x[1]);
R(d, e, a, b, c, F1, K1, x[2]);
R(c, d, e, a, b, F1, K1, x[3]);
R(b, c, d, e, a, F1, K1, x[4]);
R(a, b, c, d, e, F1, K1, x[5]);
R(e, a, b, c, d, F1, K1, x[6]);
R(d, e, a, b, c, F1, K1, x[7]);
R(c, d, e, a, b, F1, K1, x[8]);
R(b, c, d, e, a, F1, K1, x[9]);
R(a, b, c, d, e, F1, K1, x[10]);
R(e, a, b, c, d, F1, K1, x[11]);
R(d, e, a, b, c, F1, K1, x[12]);
R(c, d, e, a, b, F1, K1, x[13]);
R(b, c, d, e, a, F1, K1, x[14]);
R(a, b, c, d, e, F1, K1, x[15]);
R(e, a, b, c, d, F1, K1, M(16));
R(d, e, a, b, c, F1, K1, M(17));
R(c, d, e, a, b, F1, K1, M(18));
R(b, c, d, e, a, F1, K1, M(19));
R(a, b, c, d, e, F2, K2, M(20));
R(e, a, b, c, d, F2, K2, M(21));
R(d, e, a, b, c, F2, K2, M(22));
R(c, d, e, a, b, F2, K2, M(23));
R(b, c, d, e, a, F2, K2, M(24));
R(a, b, c, d, e, F2, K2, M(25));
R(e, a, b, c, d, F2, K2, M(26));
R(d, e, a, b, c, F2, K2, M(27));
R(c, d, e, a, b, F2, K2, M(28));
R(b, c, d, e, a, F2, K2, M(29));
R(a, b, c, d, e, F2, K2, M(30));
R(e, a, b, c, d, F2, K2, M(31));
R(d, e, a, b, c, F2, K2, M(32));
R(c, d, e, a, b, F2, K2, M(33));
R(b, c, d, e, a, F2, K2, M(34));
R(a, b, c, d, e, F2, K2, M(35));
R(e, a, b, c, d, F2, K2, M(36));
R(d, e, a, b, c, F2, K2, M(37));
R(c, d, e, a, b, F2, K2, M(38));
R(b, c, d, e, a, F2, K2, M(39));
R(a, b, c, d, e, F3, K3, M(40));
R(e, a, b, c, d, F3, K3, M(41));
R(d, e, a, b, c, F3, K3, M(42));
R(c, d, e, a, b, F3, K3, M(43));
R(b, c, d, e, a, F3, K3, M(44));
R(a, b, c, d, e, F3, K3, M(45));
R(e, a, b, c, d, F3, K3, M(46));
R(d, e, a, b, c, F3, K3, M(47));
R(c, d, e, a, b, F3, K3, M(48));
R(b, c, d, e, a, F3, K3, M(49));
R(a, b, c, d, e, F3, K3, M(50));
R(e, a, b, c, d, F3, K3, M(51));
R(d, e, a, b, c, F3, K3, M(52));
R(c, d, e, a, b, F3, K3, M(53));
R(b, c, d, e, a, F3, K3, M(54));
R(a, b, c, d, e, F3, K3, M(55));
R(e, a, b, c, d, F3, K3, M(56));
R(d, e, a, b, c, F3, K3, M(57));
R(c, d, e, a, b, F3, K3, M(58));
R(b, c, d, e, a, F3, K3, M(59));
R(a, b, c, d, e, F4, K4, M(60));
R(e, a, b, c, d, F4, K4, M(61));
R(d, e, a, b, c, F4, K4, M(62));
R(c, d, e, a, b, F4, K4, M(63));
R(b, c, d, e, a, F4, K4, M(64));
R(a, b, c, d, e, F4, K4, M(65));
R(e, a, b, c, d, F4, K4, M(66));
R(d, e, a, b, c, F4, K4, M(67));
R(c, d, e, a, b, F4, K4, M(68));
R(b, c, d, e, a, F4, K4, M(69));
R(a, b, c, d, e, F4, K4, M(70));
R(e, a, b, c, d, F4, K4, M(71));
R(d, e, a, b, c, F4, K4, M(72));
R(c, d, e, a, b, F4, K4, M(73));
R(b, c, d, e, a, F4, K4, M(74));
R(a, b, c, d, e, F4, K4, M(75));
R(e, a, b, c, d, F4, K4, M(76));
R(d, e, a, b, c, F4, K4, M(77));
R(c, d, e, a, b, F4, K4, M(78));
R(b, c, d, e, a, F4, K4, M(79));
a = ctx->A += a;
b = ctx->B += b;
c = ctx->C += c;
d = ctx->D += d;
e = ctx->E += e;
}
}

1107
src/util.cpp Normal file

File diff suppressed because it is too large Load Diff

118
src/util.h Normal file
View File

@ -0,0 +1,118 @@
//==================================================================//
/*
AtomicParsley - util.h
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright ©2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
#include "ap_types.h"
#if defined(__ppc__) || defined(__ppc64__)
#define SWAP16(x) (x)
#define SWAP32(x) (x)
#else
#define SWAP16(x) ((((x)&0xFF) << 8) | (((x) >> 8) & 0xFF))
#define SWAP32(x) \
((((x)&0xFF) << 24) | (((x) >> 24) & 0xFF) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8))
#endif
#if defined(_WIN32) && defined(_MSC_VER)
#undef HAVE_GETOPT_H
#undef HAVE_LROUNDF
#undef HAVE_STRSEP
//#undef HAVE_ZLIB_H //comment this IN when compiling on win32 withOUT zlib
// present #define HAVE_ZLIB_H 1 //and comment this OUT
#undef HAVE_SRANDDEV
#endif
#define MAXTIME_32 6377812095ULL
uint64_t findFileSize(const char *utf8_filepath);
FILE *APar_OpenFile(const char *utf8_filepath, const char *file_flags);
FILE *APar_OpenISOBaseMediaFile(const char *file, bool open); // openSomeFile
void TestFileExistence(const char *filePath, bool errorOut);
#if defined(_WIN32)
#ifndef HAVE_FSEEKO
int fseeko(FILE *stream, uint64_t pos, int whence);
#endif
HANDLE APar_OpenFileWin32(const char *utf8_filepath,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
#endif
bool IsUnicodeWinOS();
const char *APar_strferror(FILE *f);
uint8_t APar_read8(FILE *ISObasemediafile, uint64_t pos);
uint16_t APar_read16(char *buffer, FILE *ISObasemediafile, uint64_t pos);
uint32_t APar_read32(char *buffer, FILE *ISObasemediafile, uint64_t pos);
uint64_t APar_read64(char *buffer, FILE *ISObasemediafile, uint64_t pos);
void APar_readX_noseek(char *buffer, FILE *ISObasemediafile, uint32_t length);
void APar_readX(char *buffer,
FILE *ISObasemediafile,
uint64_t pos,
uint32_t length);
uint32_t
APar_ReadFile(char *destination_buffer, FILE *a_file, uint32_t bytes_to_read);
uint32_t APar_FindValueInAtom(char *uint32_buffer,
FILE *ISObasemediafile,
short an_atom,
uint64_t start_position,
uint32_t eval_number);
void APar_UnpackLanguage(unsigned char lang_code[], uint16_t packed_language);
uint16_t PackLanguage(const char *language_code, uint8_t lang_offset);
#ifndef HAVE_STRSEP
char *strsep(char **stringp, const char *delim);
#endif
char *APar_extract_UTC(uint64_t total_secs);
uint32_t APar_get_mpeg4_time();
void APar_StandardTime(char *&formed_time);
wchar_t *Convert_multibyteUTF16_to_wchar(char *input_unicode,
size_t glyph_length,
bool skip_BOM);
unsigned char *Convert_multibyteUTF16_to_UTF8(char *input_utf8,
size_t glyph_length,
size_t byte_count);
wchar_t *Convert_multibyteUTF8_to_wchar(const char *input_utf8);
uint32_t
findstringNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len);
uint32_t skipNULLterm(char *in_string, uint8_t encodingFlag, uint32_t max_len);
uint16_t UInt16FromBigEndian(const char *string);
uint32_t UInt32FromBigEndian(const char *string);
uint64_t UInt64FromBigEndian(const char *string);
void UInt16_TO_String2(uint16_t snum, char *data);
void UInt32_TO_String4(uint32_t lnum, char *data);
void UInt64_TO_String8(uint64_t ullnum, char *data);
uint32_t float_to_16x16bit_fixed_point(double floating_val);
double fixed_point_16x16bit_to_double(uint32_t fixed_point);
uint32_t widechar_len(char *instring, uint32_t _bytes_);
bool APar_assert(bool expression, int error_msg, const char *supplemental_info);
unsigned long xor4096i();

467
src/uuid.cpp Normal file
View File

@ -0,0 +1,467 @@
//==================================================================//
/*
AtomicParsley - uuid.cpp
AtomicParsley is GPL software; you can freely distribute,
redistribute, modify & use under the terms of the GNU General
Public License; either version 2 or its successor.
AtomicParsley is distributed under the GPL "AS IS", without
any warranty; without the implied warranty of merchantability
or fitness for either an expressed or implied particular purpose.
Please see the included GNU General Public License (GPL) for
your rights and further details; see the file COPYING. If you
cannot, write to the Free Software Foundation, 59 Temple Place
Suite 330, Boston, MA 02111-1307, USA. Or www.fsf.org
Copyright (C) 2006-2007 puck_lock
with contributions from others; see the CREDITS file
*/
//==================================================================//
//==================================================================//
/*
Much of AP_Create_UUID_ver5_sha1_name was derived from
http://www.ietf.org/rfc/rfc4122.txt
which I don't believe conflicts with or restricts the GPL.
And this page:
http://home.famkruithof.net/guid-uuid-namebased.html
tells me I'm not on crack when I try to calculate the uuids
myself.
Copyright (c) 1990- 1993, 1996 Open Software Foundation,
Inc. Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital
Equipment Corporation, Maynard, Mass. Copyright (c) 1998 Microsoft. To anyone
who acknowledges that this file is provided "AS IS" without any express or
implied warranty: permission to use, copy, modify, and distribute this file
for any purpose is hereby granted without fee, provided that the above
copyright notices and this notice appears in all source code copies, and that
none of the names of Open Software Foundation, Inc., Hewlett-Packard Company,
Microsoft, or Digital Equipment Corporation be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission. Neither Open Software Foundation, Inc.,
Hewlett-Packard Company, Microsoft, nor Digital Equipment Corporation makes
any representations about the suitability of this software for any purpose.
*/
//==================================================================//
#include "AtomicParsley.h"
/*----------------------
print_hash
hash - the string array of the sha1 hash
prints out the hex representation of the 16 byte hash - this
relates to sha1, but its here to keep the sha1 files as close to original as
possible
----------------------*/
void print_hash(char hash[]) {
for (int i = 0; i < 20; i++) {
fprintf(stdout, "%02x", (uint8_t)hash[i]);
}
fprintf(stdout, "\n");
return;
}
/*----------------------
Swap_Char
in_str - the string to have the swap operation performed on
str_len - the amount of bytes to swap in the string
Make a pointer to the start & end of the string, as well as a
temporary string to hold the swapped byte. As the start increments up, the end
decrements down. Copy the byte at each advancing start position. Copy the byte
of the diminishing end string into the start byte, then advance the start byte.
Finaly, set each byte of the decrementing end pointer to the temp string byte.
----------------------*/
void Swap_Char(char *in_str, uint8_t str_len) {
char *start_str, *end_str, temp_str;
start_str = in_str;
end_str = start_str + str_len;
while (start_str < --end_str) {
temp_str = *start_str;
*start_str++ = *end_str;
*end_str = temp_str;
}
return;
}
/*----------------------
APar_endian_uuid_bin_str_conversion
raw_uuid - a binary string representation of a uuid
As a string representation of a uuid, there is a 32-bit & 2
16-bit numbers in the uuid. These members need to be swapped on big endian
systems.
----------------------*/
void APar_endian_uuid_bin_str_conversion(char *raw_uuid) {
#if defined(__ppc__) || defined(__ppc64__)
return; // we are *naturally* network byte ordered - simplicity
#else
Swap_Char(raw_uuid, 4);
Swap_Char(raw_uuid + 4, 2);
Swap_Char(raw_uuid + 4 + 2, 2);
return;
#endif
}
/*----------------------
APar_print_uuid
uuid - a uuid structure containing the uuid
Print out a full string representation of a uuid
----------------------*/
void APar_print_uuid(ap_uuid_t *uuid, bool new_line) {
fprintf(stdout,
"%08" PRIx32 "-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid->time_low,
uuid->time_mid,
uuid->time_hi_and_version,
uuid->clock_seq_hi_and_reserved,
uuid->clock_seq_low,
uuid->node[0],
uuid->node[1],
uuid->node[2],
uuid->node[3],
uuid->node[4],
uuid->node[5]);
if (new_line)
fprintf(stdout, "\n");
return;
}
/*----------------------
APar_sprintf_uuid
uuid - a uuid structure containing the uuid
destination - the end result uuid will be placed here
Put a binary representation of a uuid to a human-readable
ordered uuid string
----------------------*/
void APar_sprintf_uuid(ap_uuid_t *uuid, char *destination) {
sprintf(destination,
"%08" PRIx32 "-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid->time_low,
uuid->time_mid,
uuid->time_hi_and_version,
uuid->clock_seq_hi_and_reserved,
uuid->clock_seq_low,
uuid->node[0],
uuid->node[1],
uuid->node[2],
uuid->node[3],
uuid->node[4],
uuid->node[5]);
return;
}
/*----------------------
APar_uuid_scanf
in_formed_uuid - pointer to a string (or a place in a string) where to place a
binary (hex representation) string uuid of 16 bytes raw_uuid - the string that
contains a string representation of a uuid (from cli input for example). This
string isn't 16 bytes - its 36
Skip past a hyphen, make any upper case characters lower (ahh,
that hex 'Q') to do a manual scanf on the string. Add its hex representation as
a number for 1/2 of the bits (a single byte is 2 hex characters), shift it over
to the upper bits, and repeat adding the lower bits. Repeat until done.
----------------------*/
uint8_t APar_uuid_scanf(char *in_formed_uuid, const char *raw_uuid_in) {
char *uuid_str, *end_uuid_str, *uuid_byte;
uint8_t uuid_pos, uuid_len;
uint8_t keeprap = 0;
#if defined(_WIN32) && !defined(__CYGWIN__)
char *raw_uuid = _strdup(raw_uuid_in);
#else
char *raw_uuid = strdup(raw_uuid_in);
#endif
uuid_len = strlen(
raw_uuid); // it will be like "55534d54-21d2-4fce-bb88-695cfac9c740"
uuid_str = raw_uuid;
uuid_pos = 0;
end_uuid_str = uuid_str + uuid_len;
while (uuid_str < end_uuid_str) {
uuid_byte = &in_formed_uuid[uuid_pos];
if (uuid_str[0] == '-')
uuid_str++;
if (uuid_str[0] >= 'A' && uuid_str[0] <= 90)
uuid_str[0] += 32;
if (uuid_str[1] >= 'A' && uuid_str[1] <= 90)
uuid_str[0] += 32;
for (int i = 0; i <= 1; i++) {
switch (uuid_str[i]) {
case '0': {
keeprap = 0;
break;
}
case '1': {
keeprap = 1;
break;
}
case '2': {
keeprap = 2;
break;
}
case '3': {
keeprap = 3;
break;
}
case '4': {
keeprap = 4;
break;
}
case '5': {
keeprap = 5;
break;
}
case '6': {
keeprap = 6;
break;
}
case '7': {
keeprap = 7;
break;
}
case '8': {
keeprap = 8;
break;
}
case '9': {
keeprap = 9;
break;
}
case 'a': {
keeprap = 10;
break;
}
case 'b': {
keeprap = 11;
break;
}
case 'c': {
keeprap = 12;
break;
}
case 'd': {
keeprap = 13;
break;
}
case 'e': {
keeprap = 14;
break;
}
case 'f': {
keeprap = 15;
break;
}
}
if (i == 0) {
*uuid_byte = keeprap << 4;
} else {
*uuid_byte |= keeprap; //(keeprap & 0xF0);
}
}
uuid_str += 2;
uuid_pos++;
}
APar_endian_uuid_bin_str_conversion(in_formed_uuid);
free(raw_uuid);
return uuid_pos;
}
/*----------------------
APar_extract_uuid_version
uuid - a uuid structure containing the uuid
binary_uuid_str - a binary string rep of a uuid (without dashes, just
the hex)
Test the 6th byte in a str and push the bits to get the version
or take the 3rd member of a uuid (uint16_t) and shift bits by 12
----------------------*/
uint8_t APar_extract_uuid_version(ap_uuid_t *uuid, char *binary_uuid_str) {
uint8_t uuid_ver = 0;
if (binary_uuid_str != NULL) {
uuid_ver = (binary_uuid_str[6] >> 4);
} else if (uuid != NULL) {
uuid_ver = (uuid->time_hi_and_version >> 12);
}
return uuid_ver;
}
/*----------------------
AP_Create_UUID_ver5_sha1_name
uuid - pointer to the final version 5 sha1 hash bashed uuid
desired_namespace - the input uuid used as a basis for the hash; a ver5
uuid is a namespace/name uuid. This is the namespace portion name - this is the
name portion used to make a v5 sha1 hash namelen - length of name (currently a
strlen() value)
This will create a version 5 sha1 based uuid of a name in a
namespace. The desired_namespace has its endian members swapped to newtwork byte
ordering. The sha1 hash algorithm is fed the reordered netord_namespace uuid to
create a hash; the name is then added to the hash to create a hash of the name
in the namespace. The final hash is then copied into the out_uuid, and the
endian members of the ap_uuid_t are swapped to endian ordering.
----------------------*/
void AP_Create_UUID_ver5_sha1_name(ap_uuid_t *out_uuid,
ap_uuid_t desired_namespace,
const char *name,
int namelen) {
sha1_ctx sha_state;
char hash[20];
ap_uuid_t networkorderd_namespace;
// swap the endian members of uuid to network byte order for hash uniformity
// across platforms (the NULL or AP.sf.net uuid)
networkorderd_namespace = desired_namespace;
networkorderd_namespace.time_low = SWAP32(networkorderd_namespace.time_low);
networkorderd_namespace.time_mid = SWAP16(networkorderd_namespace.time_mid);
networkorderd_namespace.time_hi_and_version =
SWAP16(networkorderd_namespace.time_hi_and_version);
// make a hash of the input desired_namespace (as netord_ns); add the name
// (the AP.sf.net namespace as string or the atom name)
sha1_init_ctx(&sha_state);
sha1_process_bytes((char *)&networkorderd_namespace,
sizeof networkorderd_namespace,
&sha_state);
sha1_process_bytes(name, namelen, &sha_state);
sha1_finish_ctx(&sha_state, hash);
// quasi uuid sha1hash is network byte ordered. swap the endian members of the
// uuid (uint32_t & uint16_t) to local byte order this creates additional
// requirements later that have to be APar_endian_uuid_bin_str_conversion()
// swapped, but leave this for now for coherence
memcpy(out_uuid, hash, sizeof *out_uuid);
out_uuid->time_low = SWAP32(out_uuid->time_low);
out_uuid->time_mid = SWAP16(out_uuid->time_mid);
out_uuid->time_hi_and_version = SWAP16(out_uuid->time_hi_and_version);
out_uuid->time_hi_and_version &= 0x0FFF; // mask hash octes 6&7
out_uuid->time_hi_and_version |=
(5 << 12); // set bits 12-15 to the version (5 for sha1 namespace/name
// hash uuids)
out_uuid->clock_seq_hi_and_reserved &= 0x3F; // mask hash octet 8
out_uuid->clock_seq_hi_and_reserved |=
0x80; // Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively.
return;
}
/*----------------------
AP_Create_UUID_ver3_random
out_uuid - pointer to the final version 3 randomly generated uuid
Use a high quality random number generator (still requiring a
seed) to generate a random uuid. In 2.5 million creations, all have been unique
(at least on Mac OS X with sranddev providing the initial seed).
----------------------*/
void AP_Create_UUID_ver3_random(ap_uuid_t *out_uuid) {
uint32_t rand1 = 0;
out_uuid->time_low = xor4096i();
rand1 = xor4096i();
out_uuid->time_mid = (rand1 >> 16) & 0xFFFF;
out_uuid->node[0] = (rand1 >> 8) & 0xFF;
out_uuid->node[1] = (rand1 >> 0) & 0xFF;
rand1 = xor4096i();
out_uuid->node[2] = (rand1 >> 24) & 0xFF;
out_uuid->node[3] = (rand1 >> 16) & 0xFF;
out_uuid->node[4] = (rand1 >> 8) & 0xFF;
out_uuid->node[5] = (rand1 >> 0) & 0xFF;
rand1 = xor4096i();
out_uuid->time_hi_and_version = (rand1 >> 16) & 0xFFFF;
out_uuid->clock_seq_low = (rand1 >> 8) & 0xFF;
out_uuid->clock_seq_hi_and_reserved = (rand1 >> 0) & 0x3F;
out_uuid->clock_seq_hi_and_reserved |=
0x40; // bits 6 & 7 must be 0 & 1 respectively
out_uuid->time_hi_and_version &= 0x0FFF;
out_uuid->time_hi_and_version |=
(3 << 12); // set bits 12-15 to the version (3 for peusdo-random/random)
return;
}
/*----------------------
APar_generate_uuid_from_atomname
atom_name - the 4 character atom name to create a uuid for
uuid_binary_str - the destination for the created uuid (as a hex string)
This will create a 16-byte universal unique identifier for any
atom name in the AtomicParsley namespace.
1. Make a namespace for all uuids to derive from (here its
AP.sf.net)
2. Make a sha1 hash of the namespace string; use that hash as
the basis for a v5 uuid into a NULL/blank uuid to create an AP namespace uuid
3. Make a sha2 hash of the atom_name string; use that hash as
the basis for a v5 uuid into an AtomicParsley namespace uuid to create the final
uuid.
4. copy the uuid structure into a binary string representation
----------------------*/
void APar_generate_uuid_from_atomname(char *atom_name, char *uuid_binary_str) {
ap_uuid_t blank_namespace = {0x00000000,
0x0000,
0x0000,
0x00,
0x00,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
ap_uuid_t APar_namespace_uuid;
ap_uuid_t AP_atom_uuid;
AP_Create_UUID_ver5_sha1_name(
&APar_namespace_uuid, blank_namespace, "AtomicParsley.sf.net", 20);
AP_Create_UUID_ver5_sha1_name(
&AP_atom_uuid, APar_namespace_uuid, atom_name, 4);
memset(uuid_binary_str, 0, 20);
memcpy(uuid_binary_str, &AP_atom_uuid, sizeof(AP_atom_uuid));
return;
}
void APar_generate_random_uuid(char *uuid_binary_str) {
ap_uuid_t rand_uuid = {0x00000000,
0x0000,
0x0000,
0x00,
0x00,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
AP_Create_UUID_ver3_random(&rand_uuid);
memcpy(uuid_binary_str, &rand_uuid, sizeof(rand_uuid));
return;
}
void APar_generate_test_uuid() {
ap_uuid_t blank_ns = {0x00000000,
0x0000,
0x0000,
0x00,
0x00,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
ap_uuid_t APar_ns_uuid;
ap_uuid_t APar_test_uuid;
AP_Create_UUID_ver5_sha1_name(
&APar_ns_uuid, blank_ns, "AtomicParsley.sf.net", 20);
APar_print_uuid(
&APar_ns_uuid); // should be aa80eaf3-1f72-5575-9faa-de9388dc2a90
fprintf(stdout, "uuid for 'cprt' in AP namespace: ");
AP_Create_UUID_ver5_sha1_name(&APar_test_uuid, APar_ns_uuid, "cprt", 4);
APar_print_uuid(
&APar_test_uuid); //'cprt' should be 4bd39a57-e2c8-5655-a4fb-7a19620ef151
// uuid_t domain_ns_uuid = { 0x6ba7b810, 0x9dad, 0x11d1,
// 0x80,
// 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }; //
// 6ba7b810-9dad-11d1-80b4-00c04fd430c8 a blank representation of a blank
// domain
return;
}

2
tools/format-code.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/bash
clang-format -i src/*.cpp src/*.h

230
tools/iTunMOVI-1.1.pl Executable file
View File

@ -0,0 +1,230 @@
#!/usr/bin/perl
#
# build --rDNSatom iTunMOVI data for AtomicParsley and write or print to file
#
# by HolyRoses
#
# example line from film "Extract"
# http://www.imdb.com/title/tt1225822/fullcredits
#
#./iTunMOVI.pl --cast "Jason Bateman" --cast "Mila Kunis,Kristen Wiig" --directors "Mike Judge" --producers "John Altschuler,Michael Flynn" --studio "Miramax Films" --copy_warning "FBI ANTI-PIRACY WARNING: UNAUTHORIZED COPYING IS PUNISHABLE UNDER FEDERAL LAW." --screenwriters "Mike Judge" --codirectors "Jasmine Alhambra,Maria Mantia" --print
use Getopt::Long;
#Getopt::Long::Configure ("bundling");
# default values for some items.
$ripper = "HolyRoses";
$copy_warning = "Help control the pet population. Have your pets spayed or neutered.";
$studio = "A $ripper Production";
GetOptions (
'version' => \$version,
'help' => \$help,
'print'=> \$print,
'write' => \$write,
'file=s' => \$file,
'copy_warning=s' => \$copy_warning,
'studio=s' => \$studio,
'cast|actors=s' => \@cast,
'directors=s' => \@directors,
'codirectors=s' => \@codirectors,
'screenwriters=s' => \@screenwriters,
'producers=s' => \@producers);
#print help
if ( $help ) {
print << "EOF";
AtomicParsley iTunMOVI writer for Apple TV and iTunes.
The options cast|actors, directors, codirectors, screenwriters, producers can take multiple of the same type.
You can issue --cast "x person" --cast "y person" or --cast "x person,y person,b person"
-------------------------------------------------------------------------------------------------------------
Atom options:
--copy_warning: Add copy warning (displayed in iTunes summary page)
--studio: Add film studio (displayed on Apple TV)
--cast|actors: Add Actors (displayed on Apple TV and iTunes under long description)
--directors: Add Directors (displayed on Apple TV and iTunes under long description)
--producers: Add Producers (displayed on Apple TV and iTunes under long description)
--codirectors: Add Co-Directors (displayed in iTunes under long description)
--screenwriters: Add ScreenWriters (displayed in iTunes under long description)
Write and print options:
--print: Display XML data to screen
--file: MP4 file to write XML information to
--write: Write XML data to MP4 file with AtomicParlsey
Misc options:
--version: Displays version
--help: Displays help
-------------------------------------------------------------------------------------------------------------
If there is more than 1 entry of cast, directors, producers, codirectors, screenwriters then in iTunes the verbage changes to plural. (PRODUCER -> PRODUCERS).
Apple TV display items:
Actors, Directors, Producers are displayed for Movies.
Actors are displayed for TV shows.
Studio is displayed on all videos (while video is playing press up arrow 2x, it is located under Title).
EOF
exit;
}
# version
$version_number = "1.1";
if ( $version ) {
print "\n$0 v$version_number\n\n";
print "Written by HolyRoses\n\n";
exit;
}
# process arrays, join multiple --options of same type and join options seperated by commas
@cast = split(/,/,join(',',@cast));
@directors = split(/,/,join(',',@directors));
@producers = split(/,/,join(',',@producers));
@codirectors = split(/,/,join(',',@codirectors));
@screenwriters = split(/,/,join(',',@screenwriters));
# set header
$iTunMOVI_data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
";
# set copy-warning
$iTunMOVI_data .= " <key>copy-warning</key>
<string>$copy_warning</string>
";
# set studio
$iTunMOVI_data .= " <key>studio</key>
<string>$studio</string>
";
# assigned a default producer
if ($producers[0] eq '') {
@producers = ("$ripper");
}
# Process cast array
if ($cast[0] ne '') {
$iTunMOVI_data .= " <key>cast</key>
<array>
";
}
foreach $actor (@cast) {
$iTunMOVI_data .= " <dict>
<key>name</key>
<string>$actor</string>
</dict>
";
}
if ($cast[0] ne '') {
$iTunMOVI_data .= " </array>
";
}
# Process directors array
if ($directors[0] ne '') {
$iTunMOVI_data .= " <key>directors</key>
<array>
";
}
foreach $director (@directors) {
$iTunMOVI_data .= " <dict>
<key>name</key>
<string>$director</string>
</dict>
";
}
if ($directors[0] ne '') {
$iTunMOVI_data .= " </array>
";
}
# Process producers array
if ($producers[0] ne '') {
$iTunMOVI_data .= " <key>producers</key>
<array>
";
}
foreach $producer (@producers) {
$iTunMOVI_data .= " <dict>
<key>name</key>
<string>$producer</string>
</dict>
";
}
if ($producers[0] ne '') {
$iTunMOVI_data .= " </array>
";
}
# Process codirectors array
if ($codirectors[0] ne '') {
$iTunMOVI_data .= " <key>codirectors</key>
<array>
";
}
foreach $codirector (@codirectors) {
$iTunMOVI_data .= " <dict>
<key>name</key>
<string>$codirector</string>
</dict>
";
}
if ($codirectors[0] ne '') {
$iTunMOVI_data .= " </array>
";
}
# Process screenwriters array
if ($screenwriters[0] ne '') {
$iTunMOVI_data .= " <key>screenwriters</key>
<array>
";
}
foreach $screenwriter (@screenwriters) {
$iTunMOVI_data .= " <dict>
<key>name</key>
<string>$screenwriter</string>
</dict>
";
}
if ($screenwriters[0] ne '') {
$iTunMOVI_data .= " </array>
";
}
# set footer
$iTunMOVI_data .= "</dict>
</plist>
";
# print output
if ( $print ) {
print "$iTunMOVI_data\n";
}
# check if file they want to write to can be opened
if ( $file ) {
open(FILE, "$file") or die "Cannot open file <$file>: $!";
close(FILE);
}
# do the AtomicParsley write
if ( $file && $write ) {
`AtomicParsley \"$file\" --rDNSatom \'$iTunMOVI_data\' name=iTunMOVI domain=com.apple.iTunes --overWrite`;
}

3
tools/tag-release.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
TAGNAME=$(git "show" "-s" "--format=%cd.%h" "--date=format:%Y%m%d.%H%M%S")
git tag $TAGNAME