Initial commit
This commit is contained in:
parent
464d2aceed
commit
62b2a5c57c
90
CMakeLists.txt
Normal file
90
CMakeLists.txt
Normal 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
280
COPYING
Normal 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
48
CREDITS
Normal 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
536
Changes.txt
Normal 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.
|
||||
|
||||
|
||||
57
README.md
57
README.md
@ -1,3 +1,56 @@
|
||||
# atomicparsley
|
||||
# AtomicParsley
|
||||
|
||||

|
||||
|
||||
## 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
9
src/.clang-format
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 2
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
IncludeIsMainRegex: AtomicParse
|
||||
---
|
||||
Language: Cpp
|
||||
---
|
||||
389
src/AtomDefs.h
Normal file
389
src/AtomDefs.h
Normal 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
458
src/AtomicParsley.h
Normal 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
589
src/CDtoc.cpp
Normal 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
80
src/CDtoc.h
Normal 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
384
src/ap_types.h
Normal 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
945
src/arrays.cpp
Normal 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
95
src/compress.cpp
Normal 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
1785
src/extracts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
981
src/extras/getopt.c
Normal file
981
src/extras/getopt.c
Normal 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
127
src/extras/getopt.h
Normal 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
87
src/extras/getopt1.c
Normal 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
993
src/iconv.cpp
Normal 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
3119
src/id3v2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
src/id3v2.h
Normal file
68
src/id3v2.h
Normal 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
597
src/id3v2defs.h
Normal 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
280
src/id3v2types.h
Normal 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
4482
src/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2163
src/metalist.cpp
Normal file
2163
src/metalist.cpp
Normal file
File diff suppressed because it is too large
Load Diff
182
src/nsfile.mm
Normal file
182
src/nsfile.mm
Normal 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
244
src/nsimage.mm
Normal 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
6537
src/parsley.cpp
Normal file
File diff suppressed because it is too large
Load Diff
402
src/sha1.cpp
Normal file
402
src/sha1.cpp
Normal 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
1107
src/util.cpp
Normal file
File diff suppressed because it is too large
Load Diff
118
src/util.h
Normal file
118
src/util.h
Normal 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
467
src/uuid.cpp
Normal 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
2
tools/format-code.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
clang-format -i src/*.cpp src/*.h
|
||||
230
tools/iTunMOVI-1.1.pl
Executable file
230
tools/iTunMOVI-1.1.pl
Executable 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
3
tools/tag-release.sh
Executable 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
|
||||
Loading…
Reference in New Issue
Block a user