This commit is contained in:
TheLuda 2008-10-14 00:29:20 +02:00
parent d767495d5b
commit 800ee76535
3322 changed files with 903437 additions and 0 deletions

340
COPYING Normal file
View file

@ -0,0 +1,340 @@
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
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

563
ChangeLog Normal file
View file

@ -0,0 +1,563 @@
MaNGOS 0.12 (??? ??? 2008)
MaNGOS 0.12 - Codename "???" - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
==== Server Features ====
==== Statistics ====
* Fixed Bugs: ???
* Total number of changes: ???
MaNGOS 0.11 (Jul 22 2008)
MaNGOS 0.11 - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
* Added: Support for show possible blocked damage, armor penetration, negative stats and other data in client.
* Added: Support for show aura charges in client.
* Added: Support for spell casting delay at damage dependence from casting partly interrupts amount, apply interrupts in spell direct damage case also.
* Added: Support for form requirement check for item/itemset casts at equip. Correctly cast at equip and cast/remove at form switch.
* Added: Support for correct speed bonus stacking.
* Added: Support for instant honor updating.
* Added: Support for cap experience received from high level creatures.
* Added: Support mining/herbalism mode for skinning of special creatures.
* Added: Support for more battleground types, many improvements in battlegrounds work.
* Added: Support for quests work with player title rewards, check for shareable quests base at quest flags.
* Added: Support for quest rewarding with mail send after specific delay with possible items sent.
* Added: Support for boss +3 target dependent level for attack rolls and chances.
* Added: Support for dodge chance calculations depends from agility and level (use dbc based values) instead wrong hardcoded values.
* Added: Support for defense/weapon skills maxed in PvP fight.
* Added: Support for bilinear interpolation use for height calculation between existed map point data for better ground height selection for point.
* Added: Support for corpse reclaim delay dependence from character death count in last period.
* Added: Support for creatures movement flags storing in DB and setup from scripts, also store extra flags to mark creatures that can't parry/block/counterattack or not provide xp at kill.
* Added: Support for offhand expertize.
* Added: Support for generation of pet passive auras by DBC data.
* Improved: Re-Implemented group/friend/enemy/pet area auras.
* Improved: Finished fill spell_affect DB table allow have related spells correct working. Now only required update table at client switch.
* Improved: Allow DoTs/HoTs ticks from dead caster if its not required caster alive state.
* Improved: Better spell targeting selection code.
* Improved: Removed outdated honor diminishing return support.
* Improved: Fixed well known unexpected sit at stun bug.
* Improved: More correct show and work with faction reputation.
* Improved: Finish update to expected level dependent mana/health stats data for player's classes.
* Improved: Better creature corpse despawn time selection. Corpse instant despawn after skinning.
* Improved: Better check in front spell target requirement.
* Improved: Show parry/dodge/block/crit calculation in client for same level creature enemy.
* Improved: Correctly show item random property in all cases, including random property with suffix factor, in inspect and in equipped state at other player.
* Improved: Use correct way to check binding items and check enchants apply in trade slot.
* Improved: Rewritten mana regen calculation, also implement creature in combat mana regeneration delay.
* Improved: Fixed long time existed problem with unexpected auto start melee attack after spell casting.
* Improved: Re-implemented diminishing returns system.
* Improved: Re-implemented fear movement.
* Improved: Rewritten distract/dispel/spell steal effects.
* Improved: Updated pet name generation data in DB.
* Improved: Better work combat enter/leave system in PvP/PvE cases.
* Improved: Many items and item set effects start work.
* plus lots of fixes for auras, effects, spells, talents, and more.
==== Server Features ====
* Added: New sql/tools directory for useful SQL queries for check and restore DB integrity.
* Added: Own counter for HIGHGUID_PET low guids. Use it for pets. This let have lot more range for pet guids, and then more creature guid for instances spawns/totems.
* Added: Replace existed random generators by Mersenne Twister random number generator.
* Added: Support for Russian, Spanish Mexico, traditional and simplified Chinese clients to ad.exe.
* Added: Support for using the failed_logins field in the account table. Support IP/account temporary ban at max allowed failed logins for account.
* Added: Support for --enable-doxygen to enable doc generation at configure use at Unix/Linux.
* Added: Anti-freeze system.
* Added: AD.EXE now also extracts DBC files. It also now searches for patch files dynamically.
* Improved: Updated MySQL client libs to 5.0.56.
* Improved: Better checking DB data at server loading.
* Improved: Apply reserver names check to pet/charter names also.
* Improved: Move hardcoded base fishing skill for zone from code to new DB table.
* Improved: Removed `spell_learn_skill` and `PlayerCreateInfo_skill` tables, use DBC data instead.
* Improved: Many improvements in Gamemaster chat commands.
* Improved: Many improvements in config options.
* Improved: Better scripting support (DB base and C++ based scripts).
==== Statistics ====
* Fixed Bugs: 194
* Total number of changes: 708
MaNGOS 0.10 (Apr 18 2008)
MaNGOS 0.10 - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
* Added: Implement talent inspecting.
* Added: Implement unique equipped items support, including gems.
* Added: Check instances where mount using allowed. Still need implement in-building check.
* Added: Implement master looter loot mode.
* Added: Implement quest related lootable gameobject activating only for characters with active quest.
* Added: Implement multi-map taxi flights, allow teleport to instances/battleground in taxi flight time.
* Added: Allow equip 2hand weapon in case swap with equipped mainhand/offhand weapon pair.
* Added: Implement player confirmation request at player summon attempt.
* Added: Implement support items with limited lifetime.
* Added: Implement chance additional items crafting with appropriate profession specialization.
* Added: Implement FFA PvP zones and FFA PvP server type.
* Added: Implement Guild Banks.
* Added: Implement expertise and better rating work.
* Added: Implement dialog status show for gameobject like yellow exclamation signs above gameobject if quest available.
* Added: Implement money requirement show for gossip box open.
* Added: Apply reputation discounts to trainer spell prices.
* Added: Implement death at fall to void/textures.
* Added: Support dead by default creatures.
* Added: Implemented work some nice items like "safe" teleport items.
* Added: Implement correct stacking elixirs/flasks.
* Added: Implement Fishing hole gameobjects work.
* Added: Implement support correctly sitting at chairs with different height and slots.
* Added: Implement normalized weapon damage use where it expected.
* Improved: Limit player money amount by 214748g 36s 46c.
* Improved: Allow join to LFG channel if character registered in LFG tool.
* Improved: Better detection and calculation in fall damage.
* Improved: Update XP generation for high levels and use coefficients dependent from new/old continents position.
* Improved: Better immunity/resisted/interrupting spell work.
* Improved: Better check area/zone/map/mapset limited spells at cast and zone leave.
* Improved: Fixed long time existed problems with client crash at group member using transports.
* Improved: Add/update lot spell_affect/spell_proc_event tables content that let work many talents, spells, and item effects.
* Improved: Better mail system work, use it for problematic items at character loading, and sending honor marks if need.
* Improved: Use correct coefficients for damage/healing spell bonuses for many spells.
* Improved: Restore work weather system.
* Improved: More correct spell affects stacking at target, and spell icons stacking in spellbook.
* Improved: More correct work explicit target positive aura rank auto-selection and implemented area auras rank auto-selection.
* Improved: Correct work permanent skill bonuses.
* Improved: Prevent lost money at unexpected double pay for learned spell with lags.
* Improved: More correct show for other players character state under different spell affects and in time spell casting.
* Improved: More correct random item enchantment bonuses selection and work code.
* Improved: Better battlegrounds work.
* Improved: Implement default open doors/pushed buttons support.
* plus lots of fixes for auras, effects, spells, talents, and more.
==== Server Features ====
* Added: broken spells check at use and loading.
* Added: Implement pid file support.
* Added: Extract and include svn revision version data in binaries at build.
* Added: Implement binding socket to specific network interface (IP address) instead all interfaces using new config option.
* Added: Implement support 64-bit binaries building at Windows.
* Added: Enable the LARGEADDRESSAWARE flag for Visual Studio 2003 mangosd and realmd projects.
* Improved: Allow Gamemasters see any creature/gameobject including invisible/stealth, allow select unselectable units.
* Improved: Many server-side check for casts (while shapeshifted, other caster and target reqirents) to prevent cheating.
* Improved: better loot system implementation including more loot conditions support and simplify loot managment for DB creators.
* Improved: better DB content error reporting at server load.`
* Improved: Many improvements in Gamemaster chat commands.
* Improved: Update sockets library to v.2.2.9 version.
* Improved: More arena support but not full yet.
* Improved: Less amount data sent to clients, including in spell casting time.
* Improved: Fixed/finish PostgreSql support.
* Improved: Better scripting support (DB base and C++ based scripts).
==== Statistics ====
* Fixed Bugs: 784
* Total number of changes: 804
MaNGOS 0.9 (Dec 14 2007)
MaNGOS 0.9 - Codename "Flight Master" - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
* Added: support for recipe discovery,
* Added: support for allowing use of an item only in a specific map or area,
* Added: support for free-for-all quest/non-quest loot items, additional loot conditions,
* Improved: a more correct implementation of XP gain (level dependent) when in a group,
* Improved: fixed creature killed from DoTs but remaining stuck with 1/3 health,
* Improved: spell and melee crit chance now calculated from DBC data and combat rating coefficients,
* Improved: a more correct implementation of mana/health regeneration calculation, including quick health regeneration in a polymorphed state,
* Improved: better support for quests with multiple speakto goals, less dependent on DB for quest flag calculation,
* Improved: more functionality added to battlegrounds, including correctly showing battleground scores,
* Improved: a more correct implementation of reputation gain for other factions from the same team,
* Improved: better support for simple database scripts (quest-start/end, buttons, spells)
* plus lots of fixes for auras, effects, spells, talents, and more.
==== Server Features ====
* Added: support for running mangosd/realmd as Windows services,
* Added: support for auto-generation of mangosd/realmd crash reports (Windows version only),
* Added: support for Visual Studio 2008 Express and Pro,
* Added: support for new Char.log for basic character operations, including save dump of character data on deletion, and logging client IP,
* Added: support for players queue at login,
* Improved: better DB content error reporting at server load,
* Improved: division of Mangos DataBase to MangosDB(WorldDB) and CharactersDB.
* Improved: better support for older autoconf / automake versions,
* Improved: existing chat and console commands for server gamemasters/administrators, and added new commands.
==== Statistics ====
* Fixed Bugs: 161
* Total number of changes: 228
MaNGOS 0.8 (Oct 16, 2007)
MaNGOS 0.8 - Codename "Innkeeper" - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
Important License Change Notice: MaNGOS still is licensed under the terms
of the GPL v2, but we now have added an exception to officially allow our
users to link MaNGOS against the OpenSSL libraries.
==== Game Features ====
* Added: a new threat manager was introduced,
* Added: log more GM activities,
* Added: many new features for creatures and game objects working,
* Added: support for client build 6898, aka version 2.1.3,
* Added: support for custom creature equipment and display,
* Added: support for daily quests,
* Added: support for different fishing loot in sub-zones,
* Added: support for gender specific models,
* Added: support for instance specific scripts and data,
* Added: support for localization of names, texts, etc.,
* Added: support for multiple battleground instances,
* Added: support for scripted game object buttons,
* Improved: battlegrounds should be mostly working, only a few issues left,
* Improved: dungeon system has seen a few improvements,
* Improved: formulas for most aspects of the game,
* Improved: many player level up values have been corrected,
* Improved: pet and demon handling has seen a lot of improvements,
* Improved: properly divide loot and reputation in groups,
* Rewritten: battleground queue system,
* Rewritten: invisibility detection,
* plus lots of fixes for auras, effects, spells, talents, and more.
==== Server Features ====
* Added: support for database transactions,
* Added: support for height maps -- named vmaps -- to tackle the LOS issue,
* Added: support for OpenBSD and FreeBSD building,
* Fixed: lots of memory leaks closed,
* Fixed: Numerous bug fixes to the core,
* Improved: database queries adding performance boosts here and there,
==== Statistics ====
* Fixed Bugs: 528
* Total number of changes: 558
MaNGOS 0.7 (Jul 9, 2007)
MaNGOS 0.7 - Codename "Eye of the Storm" -adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
* Fixed: random item enchantment display in the auction/mail/group loot dialogs. The item properties are also properly applied to the items at creation.
* Added: support for opening gameobjects/items using their specific keys. Implemented key requirements for entering instances.
* Added: a threat based aggro system along with threat bonuses from spells.
* Implemented many additional spell effects and auras. The spell system is one step closer to completeness.
* Improved: creature/player hostility checks using more accurate faction hostility data. Hostility is checked when casting spells including area-of-effect spells.
* Fixed: parry/dodge related code.
* Improved rage generation formula on blocked attacks/armor reduction etc.
* Fixed: creature movement problems after creature stun/roots and creature orientation in some cases.
* Fixed: some small problems in the player inventory system.
* Added: support for all resurrection methods for various classes. Resurrection from corpse is also implemented.
* Fixed: showing cooldown for items and spells, server side check and saving to the database is also implemented.
* Added: support for gift creation.
* Improved: the pet system and more improvements will follow in next release.
* Added: keyring support.
* Improved: many features related to raids/groups.
* Added: support for in game guild creation. Guild system can be considered finished. Arena team creation is also partly implemented.
* Added: target immunity. The targetable flag and the creature type limitation for spell targeting, which is now check when creating the target list, allows area spells against specific creature types like undeads/demons to work.
* Added: support for diminishing duration of stun/fear/etc effects.
* Rewrote: pet stable code along with improvements and bug fixes.
* Added: support for who list filters.
* Added: the instance system.
* Fixed: the weather system, now common weather is shown for all players in the same zone.
* Improved: the mail system and implemented the delay for mails containing items.
* Added: an initial version of the battleground system. One type of battleground is mostly done, still needs more work.
* Added: the jewelry profession, prospecting and support for inserting gems in sockets including meta gems bonuses.
* Added: support for multi-mining veins.
* Added: support for auto-renaming of characters on login at the request of GMs.
* Added: a new, more correct visibility system, invisibility is also implemented correctly now.
* Improved: durability cost calculation.
==== Server Features ====
* Added: full support for 2.0.x client branch.
* Added/improved: many GM-commands.
* Added: many checks for DB data at server load to simplify detecting problems and DB development.
* Moved: many data stored in code to the DB and cached most static DB data at server load to speed up runtime access to it.
* Added: support for saving next spawn time for creatures/GOs which is now used it at grid/server load.
* Improved: the script system allowing more item/creature/GO scripts with more features to be written easily.
* Added: size checking for all packets received from the to prevent crashes at wrong data. Many other received data check were also added to prevent cheating.
* Improved: the compatibility with 64-bit platforms.
* Added: support for account password encryption in the DB to increase secure security.
* Added: support for a log directory and the date info is now added to log name.
* Updated: the network library to a recent version.
* Fixed: many memory leaks and crases sources.
* Added: DBC locale support that can be set from mangosd.conf.
==== Statistics ====
* Fixed Bugs: 390
* Total number of changes: 923
MaNGOS 0.6 (Jan 29, 2007)
MaNGOS 0.6 - Codename "Black Dragonflight" - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
==== Game Features ====
* Creature and game object respawning has finally been fixed and is considered finished.
* Many improvements to decrease time for saving player data, and transaction support for save operations has been added.
* Many item fixes for using / equipping/ enhancing function (some errors still remain and have to be resolved).
* All professions work now (many fixes have been implemented, you may now enjoy fishing).
* Mail and auction house system has been rewritten, finally should work as it supposed to be.
* Spell system has received a HUGE number of improvements, and should feel much better. (Still many problems are left to be fixed, most notable include procflag spell casting, also many effects and auras are not implemented yet).
* Pet-stable implemented. Many improvements in hunter and warlock pet system (Problems with pet casting exists, various other minor bugs too).
* Rest system can be considered finished.
* Quest system has been rewritten (some problems remain unresolved).
* Implemented PvP system, and support PvE and PvP realm types.
* Duel system has been rewritten and can be considered complete (minor bugs still remain: e.g. characters sometimes may be killed in duels by channeled spells, or after duels finished by pets still attacking).
* Guild system improvements, including guild charter, guild master, and guild tabard work. (Some bugs reported about losing tabard style, etc).
* Some taxi system fixes and improvements. Switched to use DBC only data for taxi system work.
* Group related code has been rewritten, and extended to support raid groups.
* Loot code improvements and implementing group loot modes (except master loot mode).
* Correct implementation for creature skinning has been added.
* Unlearning talents, and unlearning spells with first rank received from unlearned talent implemented.
* Transports (ships/zeppelins) system implemented (still have some synchronization problems).
* Many fixes in combat system (Still have many problems).
* Enchanting in trade slot implemented as last not implemented part of trade system. Many other fixes.
* Rogue stealth for other players implemented and many fixes in druid forms.
==== Server Features ====
* Full support for 1.12.x client branch has been implemented.
* Many GM-commands added and improved including GM mode state and GM invisibility.
* Many cheating preventing checks added and code rewrites.
* DB-based scripting support added for quest emote scripts and spell event scripts.
* Many improvements in less client-server data amount transferring.
==== Statistics ====
* Fixed Bugs: 306
* Total number of changes: 874
MaNGOS 0.5 (Sep 20, 2006)
MaNGOS 0.5 - Codename "Stable Master" - adds further improvements to the
server core as well as to the majority of game classes and the game content
database.
Most noteable changes include cleaning up the database backend, adding proper
support for game clients of version 1.10.2, and closing lots of threading and
memory related bugs. Cross-platform support has been improved as well, MaNGOS
should build and run on FreeBSD as well.
Feature-wise, support for pets, totems, more spells, talents, etc. have been
added, as well as lots of quest related features.
==== Statistics ====
* Fixed Bugs: 544
* Total number of changes: 1828.
MaNGOS 0.1 (Dec 04, 2005)
MaNGOS 0.1 - Codename "Lightbringer" -adds further improvements to the server
core as well as to the majority of game classes and the game content database.
A complete list of all updated items follows below:
=== Game Features ===
* Add all AI files to the build process on Windows
* Added: Better item information updates.
* Added: Check on death for invalid duel status.
* Added: Client now shows full Creature information.
* Added: Creature::_RealtimSetCreatureInfo procedure which only sets changed values for realtime usage.
* Added: DEBUG_LOG for logging debug messages. Works with --debug-info switch on Linux and debug build on Windows.
* Added: Extra information for NPC and item information transmissions.
* Added: GM command .modify spell spellflatID,val,mark.
* Added: Guild structures, creation, saving data to DB.
* Added: Initial support for binding heart stones to a location.
* Added: Initial support for Guilds. Loading from DB, class, creation and management functions, plus some opcodes supported.
* Added: Initial support for item stacks.
* Added item page text display for detailed item info.
* Added: Level 3 command for Guild creation.
* Added: Linux Makefiles will now install mangosd.conf to sysconfdir when running "make install" after build.
* Added pragma's to disable stupid compiler warnings. Code now compiles cleanly.
* Added: Random generation of damage values for weapons based on their level.
* Added: RandomMovementGenerator. Template not yet implemented.
* Added SharedDefines.h (and updated some enums with more values).
* Added: Sheath code.
* Added: Some DB cleaning tools, hard-coded damage can be removed now.
* Added: some movement related classes.
* Added: SQL tables for guilds.
* Added: Support for additional spells.
* Added support for AIM system ( Artificial Intelligence and Movement ).
* Added: Support for client 1.8.3.
* Added support for Guild System, still has some bugs, about 85% done.
* Added support for Honor System, initial support is done, calculations need love.
* Added support for IP logging of players.
* Added: Support for page texts.
* Added: Support for QuestAreaPoints.
* Added support for reputation.
* Added: Support for tutorials.
* added the opcode name in the world.log for bether cheking
* Added: Weapon damage genrator now adds extra damage types for some items.
* Add Tools,DBC Editer,you can use it to edit all .dbc File,
* AI delivery
* Fix duel flag object position
* Fixed and sped up the players array code.
* Fixed: Armor settings.
* Fixed: Bug fixes for crash and other stuff.
* Fixed: Character bug on login closed.
* Fixed character creation bug
* Fixed: Commented wrong lines in last commit. Now correct ones commented.
* Fixed: Creation of item spells.
* Fixed: Creature::SaveToDB() code fixed. I messed it up while trying to sort out NPC corpse issue. Now back to normal.
* Fixed dead NPC issue.
* Fixed: Double Jump bug fixed with a temporary solution.
* Fixed: Fixed duplicate inclusion of Opcodes.cpp and Opcodes_1_7_x.cpp in game and mangosd directory for VC7 build.
* Fixed: Friendly NPCs attacking.
* Fixed Game Objects, now signs other objects all display.
* fixed gametickets at last,added error handling,character can have only 1 gmticket
* Fixed: Handle the bad data for guid and LOW/HIGH GUID.
* Fixed: Intel C++ VC project now compiles.
* Fixed: Item query code fixed. Item now display most stats (90%).
* Fixed: ItemQuery opcode. This prevents a crash when talking to some vendors.
* Fixed: Minor fixes for Creatures health, added some comments.
* Fixed: NPC texts.
* Fixed: One of the lines in ObjectAccessor.cpp wa removed by accident in changeset #356, causing nearby creatures not roaming, thus not attacking for aggressors.
* Fixed: Proper comparison for maxhealth.
* Fixed: Release build for 1.8 and default Grid ON
* Fixed: Resolve dead NPCs, maxhealth setting.
* Fixed Skill check for equiping Items.
* Fixed: Small fix for Windows build in ObjectAccessor::Update(const uint32 &diff).
* Fixed: Talent modifiers.
* Fixed: Talent percent work.
* Fixed: Vendors now load and display items.
* Fix: now the player can only equip item, if have the proper skill
* Fix two player in the same zone cores. Fix mem leaks in 1.8 mask deletion. And fix core dump for npc handler due to GUI only takes lower part.
* Function _ApplyItemMods() is protected... then i created a public function ApplyItemMods() that calls it... Object Oriented Project, guys!
* Function SetStanding() has been created. Now needs to put it on places where the standing of the reputation is increased.
* Initial delivery of the AI framework..
* Major CPU usage improvements with grid system disabled.
* msg of ignore list fixed
* Now Faction.dbc is being loaded.
* Progress bar code enhanced.
* Put back compression. Apparently the core problem of two players is NOT solved cuz I can still replicate it.
* Removed: All ENABLE_GRID_SYSTEM defines removed.
* Removed: Some operation out of Creature::Updated. Resolve dead NPCs.
* Reputation: first step. List of factions has been created. Some opcodes are working now.
* Reputation: second step. _LoadReputation, _SaveReputation, LoadReputationFromDBC functions have been created. Now all reputation factions are into factions list.
* Reputation System is now fixed. All functions are fixed. Load and save to DB are fine. The file reputation.sql has been updated.
* Reputation table has been created... update your Data Base!
* Resolved: Outstanding issues in phase 2 of grid system, still some left.
* Small reputation table sql fix for compatability. Remove latin character requirement.
* Started adding Enchant spell code.
* Started writing local items cache. (disabled)
* Still working on reputation... now FactionTemplate.dbc is loaded.
* Trainer code fixed. Items now disappear when you learn them.
* Trainer code update.
* Updated: Added guild sql files to Linux Makefile.
* Updated: Adjusted Item Query code.
* Updated: AtWar flag will now bet set for hostile fractions by LoadReputationFromDBC function.
* Updated: Changed transmission of item information.
* Updated: Creature display updates.
* Updated: Deliver Grid system phase 2 for VC7. The Grid System (TGS) completed.
* Updated: Display nicer statistics on daemon startup.
* Updated: FactionTemplate now hashed.
* Updated Game Objects. Looting works, loot template missing, support for Herbs, Mines, Locks missing.
* Updated: Item text pages now display additional information.
* Updated mail support. Now fully works.
* Updated: More debug cleanings.
* Updated: More grid optimizations.
* Updated: only updated creatures/objects near adjacent cell of where player stands. Also intersection of cell between player should update once.
* Updated: On Quest completion your faction reputation will increase properly.
* Updated: Quest and NPC text loading modified to suit the new tables.
* Updated: Quest code will now read the Creature_ID from the table.
* Updated: Removed some obsolete code.
* Updated: Rewrote urand() procedure to fix conflicted SVN.
* Updated: _SetCreatureTemplate() must be run in an update. When set on creation, it has no effect.
* Updated: Spell time recution talents now fully work.
* Updated: The Grid System (TGS) is now on by default. Not support grid off. Next, (1) deliver phase 2 stuff and (2) remove ifdef and ALL old classes.
* Updated: TRUNCATE is faster than DELETE
=== Server Features ===
* Added CLI interface for server. Needs to be enabled on compile-time.
* Reorganized Spell System, separated effects to a diferent file, for better fixing.
==== Statistics ====
* Fixed Bugs: #14, #17, #20, #22, #23, #24, #25, #26
* Total number of changes: 193.
MaNGOS 0.0.3 (Nov 15, 2005)
MaNGOS 0.0.3 - Codename "Mango Carpet" - was mainly a bug fix release, which
never was published on the web, and just marks a point in development where
a damn lot of bugs had been fixed, but we still felt the need for further work
to be done before a release could be pushed to the world.
MaNGOS 0.0.2 (Oct 31, 2005)
MaNGOS 0.0.2 - Codename "Library" - adds another bunch of improvements, bug
fixes and major enhancements to the overall functionality of the daemon. A
complete list of all updated items follows below:
==== Game Features ====
* Added support for area exploration.
* Added support for duels.
* Added support for ticket system.
* Added support for trading.
* Added support for NPC movement when there are no waypoints defined.
* Added support for NPC gossip, now handling options, and providing default options.
* Added attack code for creatures.
* Added default data for realm list.
* Fixed character logout. Players can only log out when not in combat.
* Fixed friends and ignore lists.
* Fixed game objects to have proper sizes.
* Fixed item swapping.
* Fixed player factions.
* Fixed vendors. They now work without requiring gossip texts defined, as long as they have objects to sell.
* Updated command descriptions to be more meaningful.
* Updated default data for player creation. Actions, items, skills and spells moved to database.
==== Server Features ====
* Added support for building with Intel C++ compiler on Windows.
* Added support for building with debug info on Linux. Use --with-debug-info switch to include debug info.
* Added support for building with 1.8.x protocol as default protocol. Use the 1.8.x build configurations in Visual Studio or --enable-18x switch on Linux.
* Added support for building with 1.7.x protocol. Use the 1.7.x build configurations in Visual Studio or --enable-17x switch on Linux.
* Added support for internal httpd server added for those not running Apache. --enable-httpd-integrated will add it. Windows solution available.
* Added support for displaying progress bars for daemon startup loading.
* Added support for on demand Grid Loading/Unloading system, which is disabled by default.
* Added core application framework.
* Added support for console commands (setgm,ban,create,info)
* Added command line switch -c for pointing to a custom configuration file. By default file from _MANGOSD_CONFIG (defined in src/mangosd/Master.h.in) will be used.
* Fixed ZThread build process.
* Fixed segmentation fault on zone map test due to access of array out of bound. Also, change m_ZoneIDmap to use bitset instead of the 4 bytes bool.
* Fixed memory leak problems. The creation of new TYPE[] must delete with [] for correctness otherwise n-1 members are leaked.
==== Statistics ====
* Fixed Bugs: #4, #7, #12, #13, #16, #18, #19
* Total number of changes: 225.
MaNGOS 0.0.1 (Sept 13, 2005)
MaNGOS 0.0.1 - Codename "Endeavour" - contains a great number of new features,
improvements and bug fixes. The following list contains all of them:
* NPC gossips now hash by Guid instead of ID. ID is meaningless and we should revisit its usage.
* Fixed client crash issue. GameObject still not interactive. Flags issues.
* Introduced new gameobjecttemplate table as well new map files.
* Added SCP-to-SQL converter to contrib/scp-to-sql/.
* MySQL 4.0 branch now is minimum requirement.
* Server causes client to core on unintialized memory. Also, remove some debug statement which causes problem when the DB is large
* Creature loot now reads from the creatureloot table. Use a new algorithm to select loot items that mimic the probabilities assigned in each item.
* Fixed configuration file, added proper settings for packet logging.
* Added default data for player creation and command help.
* Added GM command: .addspw #entry-id. Spawns a creature from creaturetemplate table by given #entry-id.
* Server randomly cores if DBC file failed to load. Fixes by intializing all DBC class internal variables.
* Daemon version and path to daemon configuration now set by build system on compile time.
* Allow connections from client release 4544
* Update solution and project files for latest Visual Studio .NET 2005 Beta 2 release.
* Fixed compiler error for gcc 4.0 or higher. Calling templated base class methods has to be explicit from 4.0 or higher on.
* Added contrib/ subdirectory for third-party tools.
* Applied MaNGOS code indention schema.
* Initial code checked into repository.
==== Statistics ====
* Fixed Bugs: #2, #3, #9, #10, #11
* Total number of changes: 53.

58
Makefile.am Normal file
View file

@ -0,0 +1,58 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
SUBDIRS = dep doc sql src
## Additional files to include when running 'make dist'
# Win32 project workspace for Visual Studio .NET 2003
EXTRA_DIST = \
win/mangosdVC71.sln \
win/VC71/framework.vcproj \
win/VC71/game.vcproj \
win/VC71/mangosd.vcproj \
win/VC71/realmd.vcproj \
win/VC71/shared.vcproj \
win/VC71/zlib.vcproj \
win/VC71/g3dlite.vcproj \
win/VC71/zthread.vcproj
# Win32 project workspace for Visual Studio .NET 2005
EXTRA_DIST += \
win/mangosdVC80.sln \
win/VC80/framework.vcproj \
win/VC80/game.vcproj \
win/VC80/mangosd.vcproj \
win/VC80/realmd.vcproj \
win/VC80/shared.vcproj \
win/VC80/zlib.vcproj \
win/VC80/g3dlite.vcproj \
win/VC80/zthread.vcproj
# Win32 project workspace for Visual Studio .NET 2008
EXTRA_DIST += \
win/mangosdVC90.sln \
win/VC90/framework.vcproj \
win/VC90/game.vcproj \
win/VC90/mangosd.vcproj \
win/VC90/realmd.vcproj \
win/VC90/shared.vcproj \
win/VC90/zlib.vcproj \
win/VC90/g3dlite.vcproj \
win/VC90/zthread.vcproj

107
NEWS Normal file
View file

@ -0,0 +1,107 @@
= MaNGOS -- History of visible changes =
Copyright (c) 2005-2008 MaNGOS project <http://getmangos.com/>
See the COPYING file for copying conditions.
Visit our project website for documentation, and more:
http://getmangos.com/
Visit our forums for support:
http://getmangos.com/community/
Please submit bug reports at:
http://mangos.lighthouseapp.com/
Version 0.12
* Under discussion.
* Upgrade to client version 2.4.3 (build 8606).
Version 0.11
* Lots of improvements in the spell system.
* Now use Mersenne Twister random number generator.
* MySQL client libs updated to 5.0.56.
* Upgrade to client version 2.4.2 (build 8278).
Version 0.10
* master looter lot mode,
* FFA PvP zones and FFA PvP server type support,
* Guild Banks,
* unique equipped items support, including gems,
* talent inspecting,
* PostgreSql support,
* sockets library updated to v.2.2.9 version,
* 64-bit binaries building at Windows,
* Upgrade to client version 2.3.0 (build 7561).
Version 0.9
* recipes discovery system support,
* more auras, effects, spells, and talents working,
* players queue at login support,
* mangosd/realmd as Windows services support,
* autogeneration mangosd/realmd crash reports (Windows only),
* Visual Studio 2008 Express and Pro support,
* division Mangos DataBase to MangosDB(WorldDB) and CharactersDB.
* Upgrade to client version 2.2.3 (build 7359).
Version 0.8
* battleground support,
* gender specific creatures,
* game objects triggering more scripts,
* more auras, effects, spells, and talents working,
* dungeon specific data,
* localization support for data,
* vmaps for line of sight handling,
* build support for OpenBSD and FreeBSD,
* Upgrade to client version 2.1.3 (build 6898).
Version 0.7, Codename "Eye of the Storm"
* Full rewrite of the GNU autotools based build system, in order to
smooth and clean up the build process.
* Full rewrite of the Windows build system, allowing MaNGOS to be built
from Visual C++ 2003 Toolkit, Visual C++ 2003, Visual C++ 2005.
* Upgrade to client version 2.0.12 (build 6546).
Version 0.6, Codename "Black Dragonflight"
* MaNGOS development moved to http://sourceforge.net/projects/mangos/
* A lots of speed improvements to data handling and data transfer have been
completed.
* Mail, auction house, profession, creature, and game object systems have seen
a lot of improvements and can be considered feature complete. Some minor bugs
still are left.
* Rest system has been finished.
* Initial pet stable support has been added.
* PvP and duel system have seen lots of improvements
* Guilds are not just a myth anymore. Coming closer to full guild support.
* Taxi and transport system is close to a fully working system.
* A lot more has been added.
Version 0.5, Codename "Stable Master"
* Core stability improvements, lots of threading and memory usage related
bugs have been resolved.
* MySQL Database backend has been cleaned up.
* Proper support for game clients of version 1.10.2 has been added.
* Support for auras, pets, spells, talents, totems, etc. has been added
or improved.
* Cross-platform issues have been resolved, MaNGOS should now build on
more platforms, including FreeBSD.
Version 0.1, Codename "Lightbringer"
* AI system
* Grid system
* Lots a game features working.
* Lovely optimizations for the beloved server.
Version 0.0.3, Codename "Mango Carpet"
* Interim release, not gone public.
Version 0.0.2, Codename "Library"
* Most data conversions working.
* Database cleanup.
* More features working.
* Many bugs fixed.
Version 0.0.1, Codename "Endeavour"
* Data converter added.
* Build system improvements.
* Bug fixing and code cleaning.

35
THANKS Normal file
View file

@ -0,0 +1,35 @@
The THANKS file:
All distributions should contain a `THANKS' file containing a two column list
of the contributors, one per line, alphabetically sorted. The left column gives
the contributor's name, while the right column gives the last known good email
address for this contributor. This list should be introduced with a wording
similar to this one:
MaNGOS THANKS file
MaNGOS has originally been written by Team Python and WoW Daemon Team. Many
people further contributed to MaNGOS by reporting problems, suggesting various
improvements or submitting actual code.
Here is a list of these people. Help me keep it complete and exempt of errors.
Special thanks should also go out to the WowwoW team. We have gained help from
them many times in the creation of this project. Keep up the good work guys.
Thanks should also go out to the Ludmilla team, who are also providing the
community with a great server. We have not gained too much help from them,
but we have recieved some.
The easiest policy with this file is to thank everyone who contributes to the
project, without judging the value of the contribution.
Unlike `AUTHORS', the `THANKS' file is not maintained for legal reasons. It is
maintained to thank all the contributors that helped you out in your project.
The `AUTHORS' file can not be used for this purpose because certain
contributions, like bug reports or ideas and suggestions do not require legal
paper exchanges.
You can also decide to send some kind of special greeting when you initially
add a name to your `THANKS' file. The mere presense of a name in `THANKS' is
then a flag to you that the initial greeting has been sent.

333
configure.ac Normal file
View file

@ -0,0 +1,333 @@
# Copyright (C) 2005-2008 MaNGOS project <http://getmangos.com/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## Process this file with autoconf to produce a configure script.
# TODO: create m4 directory and put the checks there, because this file got realy poluted ( by Derex )
## Prelude, basic settings for Autoconf
# PACKAGE: mangos
# VERSION: 0.12.0 (trunk)
# BUG-REPORT-ADDRESS: mangos-devs@lists.sourceforge.net
AC_INIT( [mangos], [0.12.0], [mangos-devs@lists.sourceforge.net])
AC_CONFIG_SRCDIR([src/shared/Base.cpp])
## Prelude, basic settings for Automake
# Turn on all warnings and error messages, and enforce GNU
# standards for the package.
AM_INIT_AUTOMAKE([-Wall -Werror gnu tar-pax])
AM_MAINTAINER_MODE
## Prevent the configure script from continuing any further if
# configuration is being performed in the top-level directory.
# The idea is to prevent this ,because some maintainers tend
# to break parallel build trees (a.k.a. VPATH builds).
if test "$srcdir" = "." && test "$enable_maintainer_mode" != "yes"; then
AC_MSG_ERROR(
[
Please configure and build in a directory other than the
top-level source directory. This is needed because a lot
of maintainers tend to break parallel build trees
(a.k.a. VPATH builds). This is kinda real ensurance they
will not do it (by enforcing everybody to do VPATH builds).
For example, try the following from the top-level source
directory:
mkdir objdir
cd objdir
../configure
make
This will create a build space in the directory `objdir' and
start a build in that directory.
If however you realy want to disable this error,
use --enable-maintainer-mode switch.
])
fi
## Disable building of static libraries by default
AC_DISABLE_STATIC
## Check for required dependencies.
## Check for a valid build environment.
# Valid equals having:
# - a C++ compiler compliant with the ISO98 C++ specification.
# - a working library tool for creating convenience libraries.
# - a working linker for creating static and shared libraries.
AC_PROG_CC
AC_PROG_CXX
AM_PROG_CC_C_O
AC_PROG_LIBTOOL
AC_PROG_INSTALL
# Check for doxygen
AC_ARG_ENABLE(doxygen, AC_HELP_STRING([--enable-doxygen], [turn on generating documentation]))
enable_doxygen_support=no
if test "x$enable_doxygen" = "xyes";
then
AC_PATH_PROG(DOXYGEN, doxygen, no)
if test "x$DOXYGEN" = "xno"; then
AC_MSG_ERROR([You need to install the doxygen package])
fi
enable_doxygen_support=yes
fi
AM_CONDITIONAL(DOXYGEN_ENABLED, test x$enable_doxygen_support = xyes)
## Check for required libraries.
AC_CHECK_LIB( pthread, pthread_create, [],
[LDFLAGS="-pthread $LDFLAGS"
AC_TRY_LINK([char pthread_create();],
pthread_create();,
[], [AC_MSG_ERROR([Missing pthread])])
])
AC_CHECK_LIB( z, compress, [ZLIB=-lz],[AC_MSG_ERROR([Missing zlib])] )
AC_CHECK_LIB( compat, ftime, [COMPATLIB=-lcompat] )
AC_CHECK_LIB( crypto, SHA1_Init, [SSLLIB=-lssl], [AC_MSG_ERROR([Missing openssl])])
AC_ARG_WITH(postgresql,
[ --with-postgresql Use PostgreSQL as a backend (default: no)],
[case "${withval}" in
yes) DO_POSTGRESQL=yes ;;
no) DO_POSTGRESQL=no ;;
maybe) DO_POSTGRESQL=maybe ;;
*) AC_MSG_ERROR(Bad value ${withval} for --with-postgresql) ;;
esac],
[DO_POSTGRESQL=no])
AC_ARG_WITH(mysql,
[ --with-mysql Use MySQL as a backend (default: yes)],
[case "${withval}" in
yes) DO_MYSQL=yes ;;
no) DO_MYSQL=no ;;
maybe) DO_MYSQL=maybe ;;
*) AC_MSG_ERROR(Bad value ${withval} for --with-mysql) ;;
esac],
[DO_MYSQL=yes])
# here Postgre
AC_MSG_CHECKING(whether to build/link POSTGRESQL)
if test "x$DO_POSTGRESQL" = "xyes"; then
DO_MYSQL=no
POSTGRE_INCLUDES="-I/usr/include/postgresql $POSTGRE_INCLUDES"
POSTGRE_LIBS="-L/usr/lib/postresql -lpq -lz -lpthread -lcrypt -lnsl -lm -lpthread -L/usr/lib -lssl -lcrypto $POSTGRE_LIBS "
CXXFLAGS="-DDO_POSTGRESQL $CXXFLAGS"
fi
AC_MSG_RESULT($DO_POSTGRESQL)
# here mysql
AC_MSG_CHECKING(whether to build/link MYSQL)
if test "x$DO_MYSQL" = "xyes"; then
AC_MSG_RESULT($DO_MYSQL)
AC_PATH_PROGS(MYSQL_CONFIG, mysql_config, mysql_config, $PATH)
if test -x "$MYSQL_CONFIG"
then
# MySQL v4 uses --include while v3 uses --cflags
MYSQL_INCLUDES="`$MYSQL_CONFIG --include`" || \
MYSQL_INCLUDES="`$MYSQL_CONFIG --cflags`"
MYSQL_LIBS="`$MYSQL_CONFIG --libs_r`"
CXXFLAGS="-DDO_MYSQL $CXXFLAGS"
fi
else
AC_MSG_RESULT($DO_MYSQL)
fi
## Check for options
# Include debug info in library?
AC_MSG_CHECKING(whether to include debug info in library)
MANGOSD_DEBUG_INFO=no
AC_ARG_WITH(debug-info,
[
Debugging options:
--with-debug-info Include debug info in library],
[
if test "$withval" = "yes" ; then
CFLAGS="-g -DMANGOS_DEBUG $CFLAGS"
CXXFLAGS="-g -DMANGOS_DEBUG $CXXFLAGS"
MANGOSD_DEBUG_INFO=yes
elif test "$withval" != "no" ; then
AC_MSG_ERROR(Please choose yes or no)
fi
])
AC_MSG_RESULT($MANGOSD_DEBUG_INFO)
# Enable CLI console?
AC_MSG_CHECKING(whether cli console is enabled)
MANGOSD_ENABLE_CLI=no
AC_ARG_ENABLE(cli,
[ --enable-cli Turn on command console system],
[
if test "$enableval" = "yes" ; then
CFLAGS="-DENABLE_CLI $CFLAGS"
CXXFLAGS="-DENABLE_CLI $CXXFLAGS"
MANGOSD_ENABLE_CLI=yes
elif test "$withval" != "no" ; then
AC_MSG_ERROR(Please choose yes or no)
fi
])
AC_MSG_RESULT($MANGOSD_ENABLE_CLI)
# Enable remote console?
AC_MSG_CHECKING(whether remote console is enabled)
MANGOSD_ENABLE_RA=no
AC_ARG_ENABLE(ra,
[ --enable-ra Turn on remote console system],
[
if test "$enableval" = "yes" ; then
CFLAGS="-DENABLE_RA $CFLAGS"
CXXFLAGS="-DENABLE_RA $CXXFLAGS"
MANGOSD_ENABLE_RA=yes
elif test "$withval" != "no" ; then
AC_MSG_ERROR(Please choose yes or no)
fi
])
AC_MSG_RESULT($MANGOSD_ENABLE_RA)
## Check for required header files.
AC_HEADER_STDC
AC_HEADER_DIRENT
AC_CHECK_HEADERS([ arpa/inet.h fcntl.h limits.h locale.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/timeb.h sys/time.h termios.h unistd.h ])
AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([openssl/md5.h openssl/rand.h openssl/ssl.h openssl/sha.h openssl/bn.h])
AC_CHECK_HEADERS([mysql.h mysql/mysql.h])
AC_CHECK_HEADERS([libpq-fe.h])
AC_CHECK_HEADERS([zlib.h])
## Check for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_STRUCT_TM
AC_TYPE_UINT64_T
AC_C_VOLATILE
AC_CHECK_TYPES([ptrdiff_t])
## Check for required library functions.
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_ERROR_AT_LINE
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_REALLOC
AC_FUNC_SELECT_ARGTYPES
AC_TYPE_SIGNAL
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([atexit ftime gethostbyaddr gethostbyname gethostname gettimeofday memmove memset pow realpath select socket sqrt strchr strdup strerror strstr])
## Check what to do with ACE library
AC_LANG_PUSH([C++])
AC_CHECK_HEADER([ace/Reactor.h], [have_ace_headers=yes], [have_ace_headers=no])
AC_CHECK_LIB([ACE], [main], [have_ace_lib=yes], [have_ace_lib=no])
AC_LANG_POP([C++])
AC_MSG_CHECKING([whether to build ACE])
if test X$have_ace_headers = Xyes -a X$have_ace_lib = Xyes;
then
need_to_build_ace=no
AC_MSG_RESULT([no])
else
if test X$have_ace_headers = Xno -a X$have_ace_lib = Xno; then
need_to_build_ace=yes
AC_MSG_RESULT([yes])
else
if test X$have_ace_headers = Xyes; then
AC_MSG_ERROR([looks like you have ACE headers, but you do not have ACE libs installed])
else
need_to_build_ace=yes
AC_MSG_RESULT([yes, over-install])
fi
fi
fi
if test X$need_to_build_ace = Xyes; then
MANGOS_INCLUDES="-I\$(top_srcdir)/dep/ACE_wrappers -I\$(top_builddir)/dep/ACE_wrappers $MANGOS_INCLUDES"
MANGOS_LIBS="\$(top_builddir)/dep/ACE_wrappers/ace/libACE.la $MANGOS_LIBS"
else
MANGOS_LIBS="-lACE $MANGOS_LIBS"
fi
AM_CONDITIONAL([MANGOS_BUILD_ACE], [test X$need_to_build_ace = Xyes])
## Unify all additional includes/libs in one variable.
# TODO this looks kinda ugly, but when we add m4 folder I will make it look very pritey ( by Derex ).
MANGOS_INCLUDES="$POSTGRE_INCLUDES $MYSQL_INCLUDES $MANGOS_INCLUDES"
MANGOS_LIBS="$POSTGRE_LIBS $MYSQL_LIBS $ZLIB $COMPATLIB $SSLLIB $MANGOS_LIBS"
## Export defined variables
AC_SUBST(DOXYGEN)
AC_SUBST(MANGOSD_DEBUG_INFO)
AC_SUBST(MANGOSD_ENABLE_CLI)
AC_SUBST(MANGOSD_ENABLE_RA)
## Additional CPPFLAGS and LDFLAGS.
AC_SUBST(MANGOS_INCLUDES)
AC_SUBST(MANGOS_LIBS)
## Set output files.
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
dep/include/Makefile
dep/lib/Makefile
dep/src/Makefile
dep/src/g3dlite/Makefile
dep/src/sockets/Makefile
dep/src/zlib/Makefile
dep/src/zthread/Makefile
dep/Makefile
doc/Doxyfile
doc/Makefile
Makefile
sql/Makefile
sql/tools/Makefile
sql/updates/Makefile
src/Makefile
src/tools/Makefile
src/tools/gensvnrevision/Makefile
src/framework/Makefile
src/shared/Makefile
src/shared/Auth/Makefile
src/shared/Config/Makefile
src/shared/Database/Makefile
src/shared/vmap/Makefile
src/shared/SystemConfig.h
src/game/Makefile
src/realmd/Makefile
src/realmd/realmd.conf.dist
src/mangosd/Makefile
src/mangosd/mangosd.conf.dist
src/bindings/Makefile
src/bindings/universal/Makefile
])
## Configure ACE, if needed
if test X$need_to_build_ace = Xyes; then
AC_CONFIG_SUBDIRS([dep/ACE_wrappers])
fi
AC_CONFIG_COMMANDS([default],[
echo ""
echo "Configuration of MaNGOS $PACKAGE_VERSION is now complete."
echo ""
],[PACKAGE_VERSION=$PACKAGE_VERSION])
## Disabled Makefiles, until they are ready for a successful make and
# make dist run.
## Output files.
AC_OUTPUT

23
contrib/Makefile.am Normal file
View file

@ -0,0 +1,23 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
SUBDIRS = extractor
## Additional files to include when running 'make dist'
# Nothing yet.

View file

@ -0,0 +1,34 @@
[TaxiNodes.dbc]
ColType2=0
ColType3=1
ColType4=1
[SpellRange.dbc]
ColType2=0
ColType3=0
ColType1=0
[Talent.dbc]
ColType1=0
ColType5=0
ColType4=0
[test.dbc]
ColType1=0
ColType3=1
ColType2=0
[TalentTab.dbc]
ColType15=2
[TalentTab_new.dbc]
ColType15=2
[SpellIcon.dbc]
ColType2=0
ColType1=0
[FactionGroup.dbc]
ColType12=0
ColType3=2
ColType2=0
ColType8=0
[gtRegenMPPerSpt.dbc]
ColType1=1
[gtOCTRegenMP.dbc]
ColType1=1
[gtOCTRegenHP.dbc]
ColType1=1

View file

@ -0,0 +1,26 @@
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "SearchFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFrmSearch *FrmSearch;
//---------------------------------------------------------------------------
__fastcall TFrmSearch::TFrmSearch(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TFrmSearch::btOkClick(TObject *Sender)
{
ModalResult = mrOk;
}
//---------------------------------------------------------------------------
void __fastcall TFrmSearch::btCancelClick(TObject *Sender)
{
ModalResult = mrCancel;
}
//---------------------------------------------------------------------------

Binary file not shown.

View file

@ -0,0 +1,63 @@
object FrmSearch: TFrmSearch
Left = 261
Top = 194
Width = 324
Height = 215
Caption = 'Seach F3 Seach Next'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object lbseach: TLabel
Left = 48
Top = 16
Width = 57
Height = 17
AutoSize = False
Caption = 'Input:'
end
object rgSI: TRadioGroup
Left = 64
Top = 40
Width = 185
Height = 97
Caption = 'Seach Dir'
ItemIndex = 1
Items.Strings = (
'Seach up'
'Seach down'
'Seach up Current rol'
'Seach down Current rol')
TabOrder = 0
end
object edSeach: TEdit
Left = 120
Top = 16
Width = 121
Height = 21
TabOrder = 1
end
object btOk: TButton
Left = 64
Top = 152
Width = 75
Height = 25
Caption = 'Ok'
TabOrder = 2
OnClick = btOkClick
end
object btCancel: TButton
Left = 176
Top = 152
Width = 75
Height = 25
Caption = 'Cancel'
TabOrder = 3
OnClick = btCancelClick
end
end

View file

@ -0,0 +1,29 @@
//---------------------------------------------------------------------------
#ifndef SearchFrmH
#define SearchFrmH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TFrmSearch : public TForm
{
__published: // IDE-managed Components
TRadioGroup *rgSI;
TEdit *edSeach;
TLabel *lbseach;
TButton *btOk;
TButton *btCancel;
void __fastcall btOkClick(TObject *Sender);
void __fastcall btCancelClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TFrmSearch(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFrmSearch *FrmSearch;
//---------------------------------------------------------------------------
#endif

View file

@ -0,0 +1,26 @@
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TitleFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFrmTitle *FrmTitle;
//---------------------------------------------------------------------------
__fastcall TFrmTitle::TFrmTitle(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TFrmTitle::Button1Click(TObject *Sender)
{
ModalResult = mrOk;
}
//---------------------------------------------------------------------------
void __fastcall TFrmTitle::Button2Click(TObject *Sender)
{
ModalResult = mrCancel;
}
//---------------------------------------------------------------------------

Binary file not shown.

View file

@ -0,0 +1,51 @@
object FrmTitle: TFrmTitle
Left = 328
Top = 252
Width = 235
Height = 112
BorderIcons = [biSystemMenu]
Caption = 'Col Title'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poDesktopCenter
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 8
Top = 24
Width = 65
Height = 13
AutoSize = False
Caption = 'Title:'
end
object edTitle: TEdit
Left = 80
Top = 16
Width = 121
Height = 21
TabOrder = 0
end
object Button1: TButton
Left = 24
Top = 48
Width = 75
Height = 25
Caption = 'Ok'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 136
Top = 48
Width = 75
Height = 25
Caption = 'Cancel'
TabOrder = 2
OnClick = Button2Click
end
end

View file

@ -0,0 +1,27 @@
//---------------------------------------------------------------------------
#ifndef TitleFrmH
#define TitleFrmH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TFrmTitle : public TForm
{
__published: // IDE-managed Components
TLabel *Label1;
TEdit *edTitle;
TButton *Button1;
TButton *Button2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TFrmTitle(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFrmTitle *FrmTitle;
//---------------------------------------------------------------------------
#endif

View file

@ -0,0 +1,313 @@
[FactionGroup.dbc]
ColType3=2
[Spell.dbc]
ColTitle1=Id
ColTitle2=Category
ColTitle3=castUI
ColTitle4=Dispel
ColTitle5=Mechanic
ColTitle6=Attributes
ColTitle7=AttributesEx;
ColTitle8=AttributesEx2;
ColTitle9=AttributesEx3;
ColTitle10=AttributesEx4;
ColTitle11=AttributesEx5;
ColTitle12=AttributesEx6;
ColTitle13=Stances;
ColTitle14=StancesNot;
ColTitle15=Targets;
ColTitle16=TargetCreatureType;
ColTitle17=RequiresSpellFocus;
ColTitle18=FacingCasterFlags;
ColTitle19=CasterAuraState;
ColTitle20=TargetAuraState;
ColTitle21=CasterAuraStateNot;
ColTitle22=TargetAuraStateNot;
ColTitle23=CastingTimeIndex;
ColTitle24=RecoveryTime;
ColTitle25=CategoryRecoveryTime;
ColTitle26=InterruptFlags;
ColTitle27=AuraInterruptFlags;
ColTitle28=ChannelInterruptFlags;
ColTitle29=procFlags;
ColTitle30=procChance;
ColTitle31=procCharges;
ColTitle32=maxLevel;
ColTitle33=baseLevel;
ColTitle34=spellLevel;
ColTitle35=DurationIndex;
ColTitle36=powerType;
ColTitle37=manaCost;
ColTitle38=manaCostPerlevel;
ColTitle39=manaPerSecond;
ColTitle40=manaPerSecondPerLevel;
ColTitle41=rangeIndex;
ColTitle42=floatspeed;
ColTitle43=modalNextSpell;//38
ColTitle44=StackAmount;
ColTitle45=Totem1
ColTitle46=Totem2
ColTitle47=Reagent
ColTitle48=Reagent2
ColTitle49=Reagent3
ColTitle50=Reagent4
ColTitle51=Reagent5
ColTitle52=Reagent6
ColTitle53=Reagent7
ColTitle54=Reagent8
ColTitle55=ReagentCount1
ColTitle56=ReagentCount2
ColTitle57=ReagentCount3
ColTitle58=ReagentCount4
ColTitle59=ReagentCount5
ColTitle60=ReagentCount6
ColTitle61=ReagentCount7
ColTitle62=ReagentCount8
ColTitle63=EqpItemClass
ColTitle64=EquipItemSubClassMask
ColTitle65=ItemInventoryTypeMask
ColTitle66=Effect
ColTitle67=Effect2
ColTitle68=Effect3
ColTitle69=EffectDieSides1
ColTitle70=EffectDieSides2
ColTitle71=EffectDieSides3
ColTitle72=EffectBaseDice1
ColTitle73=EffectBaseDice2
ColTitle74=EffectBaseDice3
ColTitle75=EffectDicePerLevel1
ColTitle76=EffectDicePerLevel2
ColTitle77=EffectDicePerLevel3
ColTitle78=EffectRealPointsPerLevel1
ColTitle79=EffectRealPointsPerLevel2
ColTitle80=EffectRealPointsPerLevel3
ColTitle81=BasePoints1
ColTitle82=BasePoints2
ColTitle83=BasePoints3
ColTitle84=EffectMechanic1
ColTitle85=EffectMechanic2
ColTitle86=EffectMechanic3
ColTitle87=ImplicTargA1
ColTitle88=ImplicTargA2
ColTitle89=ImplicTargA3
ColTitle90=ImplicTargB1
ColTitle91=ImplicTargB2
ColTitle92=ImplicTargB3
ColTitle93=RadiusIndex1
ColTitle94=RadiusIndex2
ColTitle95=RadiusIndex3
ColTitle96=ApplyAuraName1
ColTitle97=ApplyAuraName2
ColTitle98=ApplyAuraName3
ColTitle99=Amplitude1
ColTitle100=Amplitude2
ColTitle101=Amplitude3
ColTitle102=MultiVal1
ColTitle103=MultiVal2
ColTitle104=MultiVal3
ColTitle105=ChainTarg1
ColTitle106=ChainTarg2
ColTitle107=ChainTarg3
ColTitle108=EffectItemType1
ColTitle109=EffectItemType2
ColTitle110=EffectItemType3
ColTitle111=EffectMiscVal1
ColTitle112=EffectMiscVal2
ColTitle113=EffectMiscVal3
ColTitle114=EffectMiscValB1
ColTitle115=EffectMiscValB2
ColTitle116=EffectMiscValB3
ColTitle117=EffectTriggerSpell1
ColTitle118=EffectTriggerSpell2
ColTitle119=EffectTriggerSpell3
ColTitle120=EffectPointsPerComboPoint1
ColTitle121=EffectPointsPerComboPoint2
ColTitle122=EffectPointsPerComboPoint3
ColTitle123=SpellVisual
ColTitle125=SpellIconID
ColTitle126=activeIconID
ColTitle127=spellPriority
ColTitle128=SpellName1
ColTitle129=SpellName2
ColTitle130=SpellName3
ColTitle131=SpellName4
ColTitle132=SpellName5
ColTitle133=SpellName6
ColTitle134=SpellName7
ColTitle135=SpellName8
ColTitle136=SpellName9
ColTitle137=SpellName10
ColTitle138=SpellName11
ColTitle139=SpellName12
ColTitle140=SpellName13
ColTitle141=SpellName14
ColTitle142=SpellName15
ColTitle143=SpellName16
ColTitle144=SpellNameFlag
ColTitle145=Rank1
ColTitle146=Rank2
ColTitle147=Rank3
ColTitle148=Rank4
ColTitle149=Rank5
ColTitle150=Rank6
ColTitle151=Rank7
ColTitle152=Rank8
ColTitle153=Rank9
ColTitle154=Rank10
ColTitle155=Rank11
ColTitle156=Rank12
ColTitle157=Rank13
ColTitle158=Rank14
ColTitle159=Rank15
ColTitle160=Rank16
ColTitle161=RankFlags
ColTitle162=Description1
ColTitle163=Description2
ColTitle164=Description3
ColTitle165=Description4
ColTitle166=Description5
ColTitle167=Description6
ColTitle168=Description7
ColTitle169=Description8
ColTitle170=Description9
ColTitle171=Description10
ColTitle172=Description11
ColTitle173=Description12
ColTitle174=Description13
ColTitle175=Description14
ColTitle176=Description15
ColTitle177=Description16
ColTitle178=DescriptionFlags
ColTitle179=ToolTip1
ColTitle180=ToolTip2
ColTitle181=ToolTip3
ColTitle182=ToolTip4
ColTitle183=ToolTip5
ColTitle184=ToolTip6
ColTitle185=ToolTip7
ColTitle186=ToolTip8
ColTitle187=ToolTip9
ColTitle188=ToolTip10
ColTitle189=ToolTip11
ColTitle190=ToolTip12
ColTitle191=ToolTip13
ColTitle192=ToolTip14
ColTitle193=ToolTip15
ColTitle194=ToolTip16
ColTitle195=ToolTipFlags
ColTitle196=ManaCostPercentage
ColTitle197=StartRecoveryCategory
ColTitle198=StartRecoveryTime
ColTitle199=MaxTargetLevel
ColTitle200=SpellFamilyName
ColTitle201=SpellFamilyFlags1
ColTitle202=SpellFamilyFlags2
ColTitle203=MaxAffectedTargets
ColTitle204=DmgClass
ColTitle205=PreventionType
ColTitle206=StanceBarOrder
ColTitle207=DmgMultiplier1
ColTitle208=DmgMultiplier2
ColTitle209=DmgMultiplier3
ColTitle210=MinFactionId
ColTitle211=MinReputation
ColTitle212=RequiredAuraVision
ColTitle213=TotemCategory1
ColTitle214=TotemCategory2
ColTitle215=AreaId
ColTitle216=SchoolMask
ColType102=1
ColType103=1
ColType104=1
ColType128=2
ColType129=2
ColType130=2
ColType131=2
ColType132=2
ColType133=2
ColType134=2
ColType135=2
ColType136=2
ColType137=2
ColType138=2
ColType139=2
ColType140=2
ColType141=2
ColType142=2
ColType143=2
ColType145=2
ColType146=2
ColType147=2
ColType148=2
ColType149=2
ColType150=2
ColType151=2
ColType152=2
ColType153=2
ColType154=2
ColType155=2
ColType157=2
ColType156=2
ColType158=2
ColType159=2
ColType160=2
ColType162=2
ColType163=2
ColType164=2
ColType165=2
ColType166=2
ColType167=2
ColType168=2
ColType169=2
ColType170=2
ColType171=2
ColType172=2
ColType173=2
ColType174=2
ColType175=2
ColType176=2
ColType177=2
ColType179=2
ColType180=2
ColType181=2
ColType182=2
ColType183=2
ColType184=2
ColType185=2
ColType186=2
ColType187=2
ColType188=2
ColType189=2
ColType190=2
ColType191=2
ColType192=2
ColType193=2
ColType194=2
ColType208=1
ColType209=1
ColType207=1
[Map.dbc]
ColType2=2
ColType8=0
[AreaTrigger.dbc]
ColTitle3=x
ColTitle4=y
ColTitle5=z
ColTitle1=id
ColTitle2=map
ColType3=1
ColType4=1
ColType5=1
ColType6=1
ColType7=1
ColType8=1
ColType9=1
ColType10=1
ColTitle6=radius
ColTitle7=box x
ColTitle8=box y
ColTitle9=box z
ColTitle10=box orientation

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,11 @@
1.4版更新
1.修正退出时有时退不出的bug
2.加入可查找的功能
3.加入列切换类型后立即刷新
4.加入可以当前单元格写入打开文件的功能
5.加入每一列的宽度可调整
6.加入支持文本显示,但不能修改,文本修改后不会存入
1.41版
1.可以固定和取消第一列以方便查看Spell ID
2.可以行存,列存,行清,列清,调用计算器

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,769 @@
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "dbcedit.h"
#include "stdio.h"
#include "IdGlobal.hpp"
#include <inifiles.hpp>
#include "TitleFrm.h"
#include <dir.h>
#include "thOpenSource.h"
#include "SearchFrm.h"
//#include "SysUtils.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFrmMain *FrmMain;
//---------------------------------------------------------------------------
__fastcall TFrmMain::TFrmMain(TComponent* Owner)
: TForm(Owner)
{
OpenOk=false;
Term=false;
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btOpenClick(TObject *Sender)
{
if(OpenDialog1->Execute()){
if (FileExists(OpenDialog1->FileName)){
OpenOk=false;
if(thOpen){
thOpen->Terminate();
}
thOpen = new thOpenFile(false);
//thOpen->Priority = tpTimeCritical;
pnFileName->Caption = OpenDialog1->FileName;
}else{
OpenOk=false;
pnFileName->Caption = "";
}
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btSaveClick(TObject *Sender)
{
//CurrentOpenFile;
if(OpenOk){
SaveToFile(CurrentOpenFile.c_str());
}else{
ShowMessage("文件未打开完成!");
}
}
//---------------------------------------------------------------------------
void TFrmMain::SaveToFile(const char * pszFileName)
{
char szFileName[255];
FILE *stream;
fnsplit(pszFileName, 0, 0, szFileName, 0);
strcat(szFileName, "_new.dbc");
AnsiString NewFileName=ExtractFilePath(Application->ExeName)+szFileName;//=pszFileName;
int iFileHandle; //文件句柄
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
DWORD w;
CopyFileTo(pszFileName,NewFileName);
iFileHandle = FileOpen(NewFileName, fmOpenRead|fmOpenWrite);//打开文件
if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
== NULL)
{
ShowMessage("打开文件出错");
return;
}
int iVal;
float fVal;
bool isFloat;
int ColType;
FileSeek(iFileHandle,0x14,0);
TIniFile *ini;
ini = new TIniFile( iniSetFile );
for(int i=1; i<sgEdit->RowCount; i++)
{
for(int j=1; j<sgEdit->ColCount; j++)
{
if(j==1){ //ID
iVal=StrToInt(sgEdit->Cells[j][i]);
FileWrite(iFileHandle, &iVal, 4);
}else{
//ColType= ini->ReadInteger(SectionName,"ColType"+IntToStr(j-1),0);
//thOpen->ColType[10000];
switch (thOpen->ColType[j])
{
case 0: //整型
iVal=StrToFloat(sgEdit->Cells[j][i]);
FileWrite(iFileHandle, &iVal, 4);
break;
case 1: //浮点
fVal=StrToFloat(sgEdit->Cells[j][i]);
FileWrite(iFileHandle, &fVal, 4);
break;
case 2: //文本
fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(j-1))*4, 0);
fread(&iVal, 4, 1, stream);
FileWrite(iFileHandle, &iVal, 4);
break;
default: //整型
iVal=StrToFloat(sgEdit->Cells[j][i]);
FileWrite(iFileHandle, &iVal, 4);
}
}
}
}
FileClose(iFileHandle);
fclose(stream);
delete ini;
ShowMessage("Save To File:"+NewFileName);
}
void __fastcall TFrmMain::btIntTypeClick(TObject *Sender)
{
if(OpenOk==true){
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
TIniFile *ini;
ini = new TIniFile( iniSetFile );
ini->WriteInteger(SectionName,"ColType"+IntToStr(sgEdit->Col),0);
delete ini;
thOpen->ColType[sgEdit->Col]=0;
//重新打开对应列的值
//OpenFileCol(AnsiString FileName,int ColType);
OpenFileCol(CurrentOpenFile,sgEdit->Col,0);
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btFloatTypeClick(TObject *Sender)
{
if(OpenOk==true){
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
TIniFile *ini;
ini = new TIniFile( iniSetFile );
ini->WriteInteger(SectionName,"ColType"+IntToStr(sgEdit->Col),1);
delete ini;
thOpen->ColType[sgEdit->Col]=1;
OpenFileCol(CurrentOpenFile,sgEdit->Col,1);
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::PopupMenu1Popup(TObject *Sender)
{
if(OpenOk==true){
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
int ColType;
TIniFile *ini;
ini = new TIniFile( iniSetFile );
ColType=ini->ReadInteger(SectionName,"ColType"+IntToStr(sgEdit->Col),0);
delete ini;
switch (ColType)
{
case 0:
btIntType->Checked=true;
btFloatType->Checked=false;
btTxtType->Checked=false;
break;
case 1:
btIntType->Checked=false;
btFloatType->Checked=true;
btTxtType->Checked=false;
break;
case 2:
btIntType->Checked=false;
btFloatType->Checked=false;
btTxtType->Checked=true;
break;
default:
btIntType->Checked=true;
btFloatType->Checked=false;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::N1Click(TObject *Sender)
{
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
int ColType;
FrmTitle->edTitle->Text=sgEdit->Cells[sgEdit->Col][0];
if(FrmTitle->ShowModal()==mrOk){
TIniFile *ini;
ini = new TIniFile( iniSetFile );
ini->WriteString(SectionName,"ColTitle"+IntToStr(sgEdit->Col),FrmTitle->edTitle->Text);
delete ini;
sgEdit->Cells[sgEdit->Col][0]=FrmTitle->edTitle->Text;
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::FormDestroy(TObject *Sender)
{
if(thOpen){
thOpen->Terminate();
SleepEx(200,0);
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::ToolButton1Click(TObject *Sender)
{
bool SeFlag=true;
if(FrmSearch->ShowModal()==mrOk){
switch (FrmSearch->rgSI->ItemIndex)
{
case 0: //向上找;
for(int i=sgEdit->ColCount*sgEdit->Row+sgEdit->Col-1;i>sgEdit->ColCount;i--){
if(i%sgEdit->ColCount!=0){
if( 0==CompareStr(sgEdit->Cells[i-sgEdit->ColCount*(i/sgEdit->ColCount)][i/sgEdit->ColCount],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Col=i-sgEdit->ColCount*i/sgEdit->ColCount;
sgEdit->Row=i/sgEdit->ColCount;
SeFlag=false;
break;
}
}
}
if(SeFlag) ShowMessage("Seach TopFind Nothing.");
break;
case 1: //向下找;
for(int i=sgEdit->ColCount*sgEdit->Row+sgEdit->Col+1;i<sgEdit->ColCount*sgEdit->RowCount;i++){
if(i%sgEdit->ColCount!=0){
if( 0==CompareStr(sgEdit->Cells[i-sgEdit->ColCount*(i/sgEdit->ColCount)][i/sgEdit->ColCount],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Col=i-sgEdit->ColCount*(i/sgEdit->ColCount);
sgEdit->Row=i/sgEdit->ColCount;
SeFlag=false;
break;
}
}
}
if(SeFlag) ShowMessage("Seach EndFind Nothing");
break;
case 2: //当前列向上找;
for(int i=sgEdit->Row;i>1;i--){
if( 0==CompareStr(sgEdit->Cells[sgEdit->Col][i],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Row=i;
SeFlag=false;
break;
}
}
if(SeFlag) ShowMessage("Seach col topFind Nothing");
break;
case 3: //当前列向下找;
for(int i=sgEdit->Row;i<sgEdit->RowCount;i++){
if( 0==CompareStr(sgEdit->Cells[sgEdit->Col][i],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Row=i;
SeFlag=false;
break;
}
}
if(SeFlag) ShowMessage("Seach col endFind Nothing.");
break;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::sgEditKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
bool SeFlag=true;
if(Key==VK_F3){
switch (FrmSearch->rgSI->ItemIndex)
{
case 0: //向上找;
for(int i=sgEdit->ColCount*sgEdit->Row+sgEdit->Col-1;i>sgEdit->ColCount;i--){
if(i%sgEdit->ColCount!=0){
if( 0==CompareStr(sgEdit->Cells[i-sgEdit->ColCount*(i/sgEdit->ColCount)][i/sgEdit->ColCount],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Col=i-sgEdit->ColCount*i/sgEdit->ColCount;
sgEdit->Row=i/sgEdit->ColCount;
SeFlag=false;
break;
}
}
}
if(SeFlag) ShowMessage("Seach TopFind Nothing.");
break;
case 1: //向下找;
for(int i=sgEdit->ColCount*sgEdit->Row+sgEdit->Col+1;i<sgEdit->ColCount*sgEdit->RowCount;i++){
if(i%sgEdit->ColCount!=0){
if( 0==CompareStr(sgEdit->Cells[i-sgEdit->ColCount*(i/sgEdit->ColCount)][i/sgEdit->ColCount],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Col=i-sgEdit->ColCount*(i/sgEdit->ColCount);
sgEdit->Row=i/sgEdit->ColCount;
SeFlag=false;
break;
}
}
}
if(SeFlag) ShowMessage("Seach EndFind Nothing.");
break;
case 2: //当前列向上找;
for(int i=sgEdit->Row;i>1;i--){
if( 0==CompareStr(sgEdit->Cells[sgEdit->Col][i],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Row=i;
SeFlag=false;
break;
}
}
if(SeFlag) ShowMessage("Seach col TopFind Nothing.");
break;
case 3: //当前列向下找;
for(int i=sgEdit->Row;i<sgEdit->RowCount;i++){
if( 0==CompareStr(sgEdit->Cells[sgEdit->Col][i],
FrmSearch->edSeach->Text)){ //找到了
sgEdit->Row=i;
SeFlag=false;
break;
}
}
if(SeFlag) ShowMessage("Seach col endFind Nothing.");
break;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::sgEditSelectCell(TObject *Sender, int ACol,
int ARow, bool &CanSelect)
{
//
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::OpenFileCol(AnsiString FileName,int ColIndex,int ColType)
{
int iFileHandle; //文件句柄
char Txtbuf[255];
int iVal;
float fVal;
FILE *stream;
long curpos, length;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
DWORD dwTextStartPos;
char* pTextPtr ;
if ((stream = fopen(FileName.c_str(), "r+"))
== NULL)
{
ShowMessage("Open File Error");
return;
}
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
switch (ColType)
{
case 0: //整型值 Int
for(int i=0;i<sgEdit->RowCount-1;i++){
fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(ColIndex-1))*4, 0);
fread(&iVal, 4, 1, stream);
sgEdit->Cells[ColIndex][i+1]=IntToStr(iVal);
}
break;
case 1: //浮点值 Float
for(int i=0;i<sgEdit->RowCount-1;i++){
fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(ColIndex-1))*4, 0);
fread(&fVal, 4, 1, stream);
sgEdit->Cells[ColIndex][i+1]=FloatToStr(fVal);
}
break;
case 2: //文本 Text
fseek(stream,0x4,0);
fread(&iVal, 4, 1, stream);
dwRows= iVal;
fread(&iVal, 4, 1, stream);
dwCols = iVal;
fread(&iVal, 4, 1, stream);
dwRowLen = iVal;
fread(&iVal, 4, 1, stream);
dwTextLen = iVal;
dwTextStartPos = dwRows*dwRowLen+20;
for(int i=0;i<sgEdit->RowCount-1;i++){
fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(ColIndex-1))*4, 0);
fread(&iVal, 4, 1, stream);
sgEdit->Cells[ColIndex][i+1]=IntToStr(iVal);
if(dwTextStartPos + iVal < length){
fseek(stream,dwTextStartPos + iVal,0);
fread(Txtbuf, 1, 255, stream);
//pTextPtr = pBuff + dwTextStartPos + lTemp;
sgEdit->Cells[ColIndex][i+1]=Txtbuf;
}else{
sgEdit->Cells[ColIndex][i+1]="This Col Not Text!";
}
}
break;
}
fclose(stream);
}
void __fastcall TFrmMain::Timer1Timer(TObject *Sender)
{
if(OpenOk){
lbOpState->Caption = "Open File Ok.";
}else{
lbOpState->Caption = "Open Now.....";
}
}
//---------------------------------------------------------------------------
//当前格子写入修改文件中
void __fastcall TFrmMain::N4Click(TObject *Sender)
{
if(!thOpen) return;
int iFileHandle; //文件句柄
char buf[4];
int iVal;
float fVal;
FILE *stream;
/*
if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
== NULL)
{
ShowMessage("打开文件出错");
return;
}
*/
iFileHandle = FileOpen(CurrentOpenFile, fmOpenRead|fmOpenWrite);//打开文件
switch (thOpen->ColType[sgEdit->Col])
{
case 0: //整型值
//for(int i=0;i<sgEdit->RowCount-1;i++){
/*
fseek(stream, 0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4, 0);
iVal=StrToInt(sgEdit->Cells[sgEdit->Col][sgEdit->Row]);
memcpy(buf, &iVal, 4);
for(int i=0;i<4;i++)
fwrite(buf+i, 1, 1, stream);
*/
iVal=StrToInt(sgEdit->Cells[sgEdit->Col][sgEdit->Row]);
memcpy(buf, &iVal, 4);
FileSeek(iFileHandle,0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4,0);
FileWrite(iFileHandle,buf,4);
//}
break;
case 1: //浮点值
//fseek(stream, 0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4, 0);
//fVal=StrToFloat(sgEdit->Cells[sgEdit->Col][sgEdit->Row]);
//fwrite(&fVal, 4, 1, stream);
fVal=StrToFloat(sgEdit->Cells[sgEdit->Col][sgEdit->Row]);
memcpy(buf, &fVal, 4);
FileSeek(iFileHandle,0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4,0);
FileWrite(iFileHandle,buf,4);
break;
case 2: //文本不写入
break;
}
// fclose(stream);
FileClose(iFileHandle);
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btTxtTypeClick(TObject *Sender)
{
if(OpenOk==true){
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(CurrentOpenFile);
TIniFile *ini;
ini = new TIniFile( iniSetFile );
ini->WriteInteger(SectionName,"ColType"+IntToStr(sgEdit->Col),2);
delete ini;
thOpen->ColType[sgEdit->Col]=2;
OpenFileCol(CurrentOpenFile,sgEdit->Col,2);
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::ToolButton3Click(TObject *Sender)
{
int OldCol;
int OldRow;
OldRow=sgEdit->Row;
OldCol=sgEdit->Col;
if(sgEdit->FixedCols==1){
sgEdit->FixedCols =2;
if(OldCol!=1)
sgEdit->Col=OldCol;
sgEdit->Row=OldRow;
}else{
sgEdit->FixedCols =1;
sgEdit->Row=OldRow;
if(OldCol!=2)
sgEdit->Col=OldCol;
}
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btRowSaveClick(TObject *Sender)
{
if(OpenOk==false) return;
int iFileHandle; //文件句柄
char Txtbuf[255];
int iVal;
char buf[4];
float fVal;
FILE *stream;
long curpos, length;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
DWORD dwTextStartPos;
char* pTextPtr ;
//if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
// == NULL)
//{
// ShowMessage("打开文件出错");
// return;
//}
//curpos = ftell(stream);
//fseek(stream, 0L, SEEK_END);
//length = ftell(stream);
iFileHandle = FileOpen(CurrentOpenFile, fmOpenRead|fmOpenWrite);//打开文件
for(int i=0;i<sgEdit->ColCount-1;i++){
switch (thOpen->ColType[i])
{
case 0: //整型值 sgEdit->Row
//fseek(stream, 0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+i)*4, 0);
//iVal=StrToInt(sgEdit->Cells[i+1][sgEdit->Row]);
//fwrite(&iVal, 4, 1, stream);
iVal=StrToInt(sgEdit->Cells[i+1][sgEdit->Row]);
memcpy(buf, &iVal, 4);
FileSeek(iFileHandle,0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+i)*4,0);
FileWrite(iFileHandle,buf,4);
break;
case 1: //浮点值
//fseek(stream, 0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+i)*4, 0);
//fVal=StrToFloat(sgEdit->Cells[i+1][sgEdit->Row]);
//fwrite(&fVal, 4, 1, stream);
fVal=StrToFloat(sgEdit->Cells[i+1][sgEdit->Row]);
memcpy(buf, &fVal, 4);
FileSeek(iFileHandle,0x14+((sgEdit->Row-1)*(sgEdit->ColCount-1)+i)*4,0);
FileWrite(iFileHandle,buf,4);
break;
case 2: //文本 不存
break;
}
}
//fclose(stream);
FileClose(iFileHandle);
ShowMessage("The "+IntToStr(sgEdit->Row)+" Row Write Ok!");
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btColSaveClick(TObject *Sender)
{
if(OpenOk==false) return;
int iFileHandle; //文件句柄
char Txtbuf[255];
int iVal;
char buf[4];
float fVal;
FILE *stream;
long curpos, length;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
DWORD dwTextStartPos;
char* pTextPtr ;
iFileHandle = FileOpen(CurrentOpenFile, fmOpenRead|fmOpenWrite);//打开文件
//if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
// == NULL)
//{
// ShowMessage("打开文件出错");
// return;
//}
//curpos = ftell(stream);
//fseek(stream, 0L, SEEK_END);
//length = ftell(stream);
switch (thOpen->ColType[sgEdit->Col])
{
case 0: //整型值
for(int i=0;i<sgEdit->RowCount-1;i++){
//fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4, 0);
//iVal=StrToInt(sgEdit->Cells[sgEdit->Col][i+1]);
//fwrite(&iVal, 4, 1, stream);
iVal=StrToInt(sgEdit->Cells[sgEdit->Col][i+1]);
memcpy(buf, &iVal, 4);
FileSeek(iFileHandle,0x14+(i*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4,0);
FileWrite(iFileHandle,buf,4);
}
break;
case 1: //浮点值
for(int i=0;i<sgEdit->RowCount-1;i++){
//fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4, 0);
//fVal=StrToFloat(sgEdit->Cells[sgEdit->Col][i+1]);
//fwrite(&fVal, 4, 1, stream);
fVal=StrToFloat(sgEdit->Cells[sgEdit->Col][i+1]);
memcpy(buf, &fVal, 4);
FileSeek(iFileHandle,0x14+(i*(sgEdit->ColCount-1)+(sgEdit->Col-1))*4,0);
FileWrite(iFileHandle,buf,4);
}
break;
case 2: //文本 不存
break;
}
//fclose(stream);
FileClose(iFileHandle);
ShowMessage("The "+IntToStr(sgEdit->Col)+"Col Write Ok!");
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btRowClearClick(TObject *Sender)
{
if(OpenOk==false) return;
int iFileHandle; //文件句柄
char Txtbuf[255];
int iVal;
float fVal;
FILE *stream;
long curpos, length;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
DWORD dwTextStartPos;
char* pTextPtr ;
if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
== NULL)
{
ShowMessage("Open File Error!");
return;
}
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
for(int i=1;i<sgEdit->ColCount-1;i++){
switch (thOpen->ColType[i])
{
case 0: //整型值 sgEdit->Row
//fseek(stream, 0x14+(sgEdit->Row*(sgEdit->ColCount-1)+i)*4, 0);
//iVal=StrToInt(sgEdit->Cells[i+1][sgEdit->Row]);
//fwrite(&iVal, 4, 1, stream);
sgEdit->Cells[i+1][sgEdit->Row]="0";
break;
case 1: //浮点值
//fseek(stream, 0x14+(sgEdit->Row*(sgEdit->ColCount-1)+i)*4, 0);
//fVal=StrToFloat(sgEdit->Cells[i+1][sgEdit->Row]);
//fwrite(&fVal, 4, 1, stream);
sgEdit->Cells[i+1][sgEdit->Row]="0";
break;
case 2: //文本 不存
break;
}
}
fclose(stream);
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::btColClearClick(TObject *Sender)
{
if(OpenOk==false) return;
int iFileHandle; //文件句柄
char Txtbuf[255];
int iVal;
float fVal;
FILE *stream;
long curpos, length;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
DWORD dwTextStartPos;
char* pTextPtr ;
if ((stream = fopen(CurrentOpenFile.c_str(), "r+"))
== NULL)
{
ShowMessage("Open File Error!");
return;
}
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
switch (thOpen->ColType[sgEdit->Col])
{
case 0: //整型值
for(int i=0;i<sgEdit->RowCount-1;i++){
//fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(ColIndex-1))*4, 0);
//iVal=StrToInt(sgEdit->Cells[ColIndex][i+1]);
//fwrite(&iVal, 4, 1, stream);
sgEdit->Cells[sgEdit->Col][i+1]="0";
}
break;
case 1: //浮点值
for(int i=0;i<sgEdit->RowCount-1;i++){
//fseek(stream, 0x14+(i*(sgEdit->ColCount-1)+(ColIndex-1))*4, 0);
//fVal=StrToFloat(sgEdit->Cells[ColIndex][i+1]);
//fwrite(&fVal, 4, 1, stream);
sgEdit->Cells[sgEdit->Col][i+1]="0";
}
break;
case 2: //文本 不存
break;
}
fclose(stream);
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::ToolButton4Click(TObject *Sender)
{
AnsiString Cmd;
Cmd = "calc.exe";
WinExec(Cmd.c_str(), SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------

Binary file not shown.

File diff suppressed because it is too large Load diff

105
contrib/dbcEditer/dbcedit.h Normal file
View file

@ -0,0 +1,105 @@
//---------------------------------------------------------------------------
#ifndef dbceditH
#define dbceditH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include <ToolWin.hpp>
#include <Grids.hpp>
#include <Dialogs.hpp>
#include <Menus.hpp>
#include <ImgList.hpp>
#include "thOpenSource.h"
union TypePtr
{
long* l;
DWORD* dw;
WORD* w;
char* c;
void* p;
float* f;
TypePtr(void* in) :p(in)
{
}
};
#define TAG(x) (DWORD)( (((DWORD)x&0x0000ff00)<<8)+(((DWORD)x&0x000000ff)<<24)+(((DWORD)x&0x00ff0000)>>8)+(((DWORD)x&0xff000000)>>24) )
//---------------------------------------------------------------------------
class TFrmMain : public TForm
{
__published: // IDE-managed Components
TPanel *Panel1;
TCoolBar *CoolBar1;
TToolBar *ToolBar1;
TToolButton *btOpen;
TToolButton *btSave;
TStringGrid *sgEdit;
TOpenDialog *OpenDialog1;
TPopupMenu *PopupMenu1;
TMenuItem *N1;
TMenuItem *N2;
TMenuItem *btIntType;
TMenuItem *btFloatType;
TMenuItem *btTxtType;
TImageList *ImageList1;
TPanel *pnFileName;
TToolButton *ToolButton1;
TToolButton *ToolButton2;
TTimer *Timer1;
TLabel *lbOpState;
TMenuItem *N4;
TToolButton *ToolButton3;
TMenuItem *btRowSave;
TMenuItem *btColSave;
TMenuItem *btRowClear;
TMenuItem *btColClear;
TToolButton *ToolButton4;
TToolButton *ToolButton5;
void __fastcall btOpenClick(TObject *Sender);
void __fastcall btSaveClick(TObject *Sender);
void __fastcall btIntTypeClick(TObject *Sender);
void __fastcall btFloatTypeClick(TObject *Sender);
void __fastcall PopupMenu1Popup(TObject *Sender);
void __fastcall N1Click(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
void __fastcall ToolButton1Click(TObject *Sender);
void __fastcall sgEditKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift);
void __fastcall sgEditSelectCell(TObject *Sender, int ACol,
int ARow, bool &CanSelect);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall N4Click(TObject *Sender);
void __fastcall btTxtTypeClick(TObject *Sender);
void __fastcall ToolButton3Click(TObject *Sender);
void __fastcall btRowSaveClick(TObject *Sender);
void __fastcall btColSaveClick(TObject *Sender);
void __fastcall btRowClearClick(TObject *Sender);
void __fastcall btColClearClick(TObject *Sender);
void __fastcall ToolButton4Click(TObject *Sender);
private: // User declarations
thOpenFile *thOpen;
bool Term;
public: // User declarations
bool OpenOk;
AnsiString CurrentOpenFile;
__fastcall TFrmMain(TComponent* Owner);
void SaveToFile(const char * pszFileName);
void __fastcall OpenFileCol(AnsiString FileName,int ColIndex,int ColType);
};
//---------------------------------------------------------------------------
extern PACKAGE TFrmMain *FrmMain;
//---------------------------------------------------------------------------
#endif

View file

@ -0,0 +1,124 @@
<?xml version='1.0' encoding='utf-8' ?>
<!-- C++Builder XML Project -->
<PROJECT>
<MACROS>
<VERSION value="BCB.06.00"/>
<PROJECT value="pjDbcEditer.exe"/>
<OBJFILES value="pjDbcEditer.obj dbcedit.obj TitleFrm.obj thOpenSource.obj SearchFrm.obj"/>
<RESFILES value="pjDbcEditer.res"/>
<IDLFILES value=""/>
<IDLGENFILES value=""/>
<DEFFILE value=""/>
<RESDEPEN value="$(RESFILES) dbcedit.dfm TitleFrm.dfm SearchFrm.dfm"/>
<LIBFILES value=""/>
<LIBRARIES value=""/>
<SPARELIBS value="vcl.lib rtl.lib indy.lib"/>
<PACKAGES value="vcl.bpi rtl.bpi dbrtl.bpi adortl.bpi vcldb.bpi vclx.bpi bdertl.bpi
vcldbx.bpi ibxpress.bpi dsnap.bpi cds.bpi bdecds.bpi qrpt.bpi teeui.bpi
teedb.bpi tee.bpi dss.bpi teeqr.bpi visualclx.bpi visualdbclx.bpi
dsnapcrba.bpi dsnapcon.bpi bcbsmp.bpi vclie.bpi xmlrtl.bpi inet.bpi
inetdbbde.bpi inetdbxpress.bpi inetdb.bpi nmfast.bpi webdsnap.bpi
bcbie.bpi websnap.bpi soaprtl.bpi dclocx.bpi dbexpress.bpi dbxcds.bpi
indy.bpi bcb2kaxserver.bpi dclusr.bpi"/>
<PATHCPP value=".;"/>
<PATHPAS value=".;"/>
<PATHRC value=".;"/>
<PATHASM value=".;"/>
<DEBUGLIBPATH value="$(BCB)\lib\debug"/>
<RELEASELIBPATH value="$(BCB)\lib\release"/>
<LINKER value="ilink32"/>
<USERDEFINES value="_DEBUG"/>
<SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
<MAINSOURCE value="pjDbcEditer.cpp"/>
<INCLUDEPATH value="&quot;C:\Program Files\Borland\CBuilder6\Projects&quot;;E:\moshou\dbcEdit;$(BCB)\include;$(BCB)\include\vcl"/>
<LIBPATH value="&quot;C:\Program Files\Borland\CBuilder6\Projects&quot;;E:\moshou\dbcEdit;$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
<WARNINGS value="-w-par"/>
<OTHERFILES value=""/>
</MACROS>
<OPTIONS>
<IDLCFLAGS value="-I&quot;C:\Program Files\Borland\CBuilder6\Projects&quot; -IE:\moshou\dbcEdit
-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
<CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
-tW -tWM"/>
<PFLAGS value="-$Y+ -$W -$O- -$A8 -v -JPHNE -M"/>
<RFLAGS value=""/>
<AFLAGS value="/mx /w2 /zi"/>
<LFLAGS value="-D&quot;&quot; -aa -Tpe -x -Gn -v"/>
<OTHERFILES value=""/>
</OPTIONS>
<LINKER>
<ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
<ALLRES value="$(RESFILES)"/>
<ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
<OTHERFILES value=""/>
</LINKER>
<FILELIST>
<FILE FILENAME="pjDbcEditer.res" FORMNAME="" UNITNAME="pjDbcEditer.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="pjDbcEditer.cpp" FORMNAME="" UNITNAME="pjDbcEditer" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="dbcedit.cpp" FORMNAME="FrmMain" UNITNAME="dbcedit" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="TitleFrm.cpp" FORMNAME="FrmTitle" UNITNAME="TitleFrm" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="thOpenSource.cpp" FORMNAME="" UNITNAME="thOpenSource" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="SearchFrm.cpp" FORMNAME="FrmSearch" UNITNAME="SearchFrm" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
</FILELIST>
<BUILDTOOLS>
</BUILDTOOLS>
<IDEOPTIONS>
[Version Info]
IncludeVerInfo=0
AutoIncBuild=0
MajorVer=1
MinorVer=0
Release=0
Build=0
Debug=0
PreRelease=0
Special=0
Private=0
DLL=0
Locale=2052
CodePage=936
[Version Info Keys]
CompanyName=
FileDescription=
FileVersion=1.0.0.0
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=1.0.0.0
Comments=
[Debugging]
DebugSourceDirs=$(BCB)\source\vcl
[Parameters]
RunParams=
Launcher=
UseLauncher=0
DebugCWD=
HostApplication=
RemoteHost=
RemotePath=
RemoteLauncher=
RemoteCWD=
RemoteDebug=0
[Compiler]
ShowInfoMsgs=0
LinkDebugVcl=0
LinkCGLIB=0
[CORBA]
AddServerUnit=1
AddClientUnit=1
PrecompiledHeaders=1
[Language]
ActiveLang=
ProjectLang=
RootDir=
</IDEOPTIONS>
</PROJECT>

View file

@ -0,0 +1,37 @@
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("dbcedit.cpp", FrmMain);
USEFORM("TitleFrm.cpp", FrmTitle);
USEFORM("SearchFrm.cpp", FrmSearch);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TFrmMain), &FrmMain);
Application->CreateForm(__classid(TFrmTitle), &FrmTitle);
Application->CreateForm(__classid(TFrmSearch), &FrmSearch);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,182 @@
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "thOpenSource.h"
#include "dbcedit.h"
#include "stdio.h"
#include <dir.h>
#include <inifiles.hpp>
#include <process.h>
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall thOpenFile::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//---------------------------------------------------------------------------
__fastcall thOpenFile::thOpenFile(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall thOpenFile::Execute()
{
//---- Place thread code here ----
//if(!Terminated){
// FrmMain->LoadAndModify(FrmMain->OpenDialog1->FileName.c_str());
// FrmMain->OpenOk=true;
//}
thEnd=false;
RunOpen();
FrmMain->OpenOk=true;
thEnd=true;
}
//---------------------------------------------------------------------------
void __fastcall thOpenFile::RunOpen()
{
LoadAndModify(FrmMain->OpenDialog1->FileName.c_str());
//OpenOk=true;
}
void thOpenFile::ReadAndModifyFromBuff(char *pBuff, DWORD dwSize, const char* pszFileName)
{
char szErrorMsg[MAX_PATH];
char szNewFileName[MAX_PATH];
DWORD w;
TIniFile *ini;
TypePtr p(pBuff);
if('WDBC' != TAG(*p.dw))
{
_snprintf(szErrorMsg, 512, "[%s]Not Wow's dbc file!", pszFileName);
ShowMessage(szErrorMsg);
return;
}
p.dw++;
DWORD dwRows, dwCols, dwRowLen, dwTextLen;
dwRows = *p.dw++;
dwCols = *p.dw++;
dwRowLen = *p.dw++;
dwTextLen = *p.dw++;
FrmMain->sgEdit->RowCount = dwRows+1;
FrmMain->sgEdit->ColCount = dwCols+1;
for(int i=0; i<FrmMain->sgEdit->RowCount; i++){
FrmMain->sgEdit->Cells[0][i]=IntToStr(i);
if(Terminated) return;
}
//设定列标题
AnsiString iniSetFile=ExtractFilePath(Application->ExeName)+"BcdEditer.ini";
AnsiString SectionName=ExtractFileName(FrmMain->CurrentOpenFile);
ini = new TIniFile( iniSetFile );
for(int j=0; j<FrmMain->sgEdit->ColCount; j++){
FrmMain->sgEdit->Cells[j][0]= ini->ReadString(SectionName,"ColTitle"+IntToStr(j),IntToStr(j));
//sgEdit->Cells[j][0]=IntToStr(j);
ColType[j]=ini->ReadInteger(SectionName,"ColType"+IntToStr(j),0);
if(Terminated) return;
}
delete ini;
//int *ColType = new int[dwCols];
DWORD dwTextStartPos = dwRows*dwRowLen+20;
char* pTextPtr = pBuff + dwTextStartPos;
char pszTemp[MAX_PATH];
float fTemp;
long lTemp;
DWORD i, j;
BOOL* pbString = new BOOL[dwRows*dwCols];
float newTmp;
//int ColType;
ini = new TIniFile( iniSetFile );
for(i=0; i<dwRows; i++)
{
for(j=0; j<dwCols; j++)
{
//SleepEx(0,0);
if(Terminated) return;
lTemp = *p.l;
newTmp = *p.f;
memcpy(&fTemp, &newTmp, 4);
if(j==0) //ID
FrmMain->sgEdit->Cells[j+1][i+1]=IntToStr(lTemp);
else{
//ColType= ini->ReadInteger(SectionName,"ColType"+IntToStr(j),0);
switch (ColType[j+1])
{
case 0: //整型
FrmMain->sgEdit->Cells[j+1][i+1]=IntToStr(lTemp);
break;
case 1: //浮点
FrmMain->sgEdit->Cells[j+1][i+1]=FloatToStr(fTemp);
break;
case 2: //文本 文本类型只能看,不能编辑
if(dwTextStartPos + lTemp < dwSize){
pTextPtr = pBuff + dwTextStartPos + lTemp;
FrmMain->sgEdit->Cells[j+1][i+1]=pTextPtr;
}else{
FrmMain->sgEdit->Cells[j+1][i+1]="该列不是文本";
}
break;
default: //整型
FrmMain->sgEdit->Cells[j+1][i+1]=IntToStr(lTemp);
}
}
p.c += 4;
}
}
delete [] pbString;
//delete [] ColType;
delete ini;
}
void thOpenFile::LoadAndModify(const char * pszFileName)
{
HANDLE hFile = NULL;
hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)return;
DWORD r = 0, nFileSize = 0;
nFileSize = GetFileSize(hFile, NULL);
char* pTmpBuf = new char[nFileSize];
if(pTmpBuf==NULL)
{
CloseHandle(hFile);
return;
}
ReadFile(hFile, pTmpBuf, nFileSize, &r, NULL);
FrmMain->CurrentOpenFile=pszFileName;
FrmMain->btSave->Enabled=true;
ReadAndModifyFromBuff(pTmpBuf, nFileSize, pszFileName);
//SAFE_DELETE_ARRAY(pTmpBuf);
delete [] pTmpBuf;
CloseHandle(hFile);
}

View file

@ -0,0 +1,24 @@
//---------------------------------------------------------------------------
#ifndef thOpenSourceH
#define thOpenSourceH
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
class thOpenFile : public TThread
{
private:
protected:
void __fastcall Execute();
void __fastcall RunOpen();
public:
bool thEnd;
int ColType[10000];
__fastcall thOpenFile(bool CreateSuspended);
void LoadAndModify(const char * pszFileName);
void ReadAndModifyFromBuff(char *pBuff, DWORD dwSize, const char* pszFileName);
};
//---------------------------------------------------------------------------
#endif

BIN
contrib/dbcformat/DBC Store.exe Executable file

Binary file not shown.

241
contrib/dbcformat/dbc.desc Normal file
View file

@ -0,0 +1,241 @@
ENTRY ItemSetEntry
UNUSED INDEX setid
UNUSED STR setname
UNKNOWN[7]
UNUSED UINT flags//, const
UNUSED UINT required_item_id[8]
UNKNOWN[48]
UINT spells[8]
UINT items_to_triggerspell[8] //items_to_triggerspell[0] -- for spells[0]
UINT required_skill_id//only 2 items sets have requirements
UINT required_skill_value
ENDENTRY
ENTRY TalentEntry
INDEX TalentID
UINT TalentTree
UNKNOWN [2]
UINT RankID[5]
UNKNOWN[12]
ENDENTRY
ENTRY emoteentry
INDEX Id
UNUSED STR name
UINT textid
UNUSED UINT textid2
UNUSED UINT textid3
UNUSED UINT textid4
UNKNOWN
UNUSED UINT textid5
UNKNOWN
UNUSED UINT textid6
UNKNOWN[9]
ENDENTRY
ENTRY SpellEntry
INDEX Id
UINT School
UNKNOWN [2]
UINT Category
UNKNOWN
UINT Attributes
UINT AttributesEx
UNKNOWN [3]
UINT Targets
UINT TargetCreatureType
UINT RequiresSpellFocus
UNKNOWN
UINT CasterAuraState
UINT CastingTimeIndex
UINT RecoveryTime
UINT CategoryRecoveryTime
UINT InterruptFlags
UINT AuraInterruptFlags
UINT ChannelInterruptFlags
UINT procFlags
UINT procChance
UINT procCharges
UINT maxLevel
UINT baseLevel
UINT spellLevel
UINT DurationIndex
UINT powerType
UINT manaCost
UINT manaCostPerlevel
UINT manaPerSecond
UINT manaPerSecondPerLevel
UINT rangeIndex
FLOAT speed
UINT modalNextSpell
UNKNOWN
UINT Totem[2]
UINT Reagent[8]
UINT ReagentCount[8]
UINT EquippedItemClass
UINT EquippedItemSubClass
UINT Effect[3] // 59 - 61
UINT EffectDieSides[3]
UINT EffectBaseDice[3]
FLOAT EffectDicePerLevel[3]
FLOAT EffectRealPointsPerLevel[3]
INT EffectBasePoints[3] // 74 - 76
UNKNOWN [3]
UINT EffectImplicitTargetA[3] // 80 - 82
UINT EffectImplicitTargetB[3] // 83 - 85
UINT EffectRadiusIndex[3]
UINT EffectApplyAuraName[3] // 89 - 91
UINT EffectAmplitude[3]
UINT Effectunknown[3]
UINT EffectChainTarget[3]
UINT EffectItemType[3]
UINT EffectMiscValue[3] // 104 - 106
UINT EffectTriggerSpell[3]
FLOAT EffectPointsPerComboPoint[3]
UINT SpellVisual
UNKNOWN
UINT SpellIconID
UINT activeIconID
UINT spellPriority
UNUSED STR Name
UNUSED STR NameAlt1
UNUSED STR NameAlt2
UNUSED STR NameAlt3
UNUSED STR NameAlt4
UNUSED STR NameAlt5
UNUSED STR NameAlt6
UNUSED STR NameAlt7
UNUSED STR NameFlags
UINT Rank
UINT RankAlt1
UINT RankAlt2
UINT RankAlt3
UINT RankAlt4
UINT RankAlt5
UINT RankAlt6
UINT RankAlt7
UINT RankFlags
UNUSED STR Description
UNUSED STR DescriptionAlt1
UNUSED STR DescriptionAlt2
UNUSED STR DescriptionAlt3
UNUSED STR DescriptionAlt4
UNUSED STR DescriptionAlt5
UNUSED STR DescriptionAlt6
UNUSED STR DescriptionAlt7
UNUSED UINT DescriptionFlags
UNUSED STR BuffDescription
UNUSED STR BuffDescriptionAlt1
UNUSED STR BuffDescriptionAlt2
UNUSED STR BuffDescriptionAlt3
UNUSED STR BuffDescriptionAlt4
UNUSED STR BuffDescriptionAlt5
UNUSED STR BuffDescriptionAlt6
UNUSED STR BuffDescriptionAlt7
UINT ManaCostPercentage
UINT StartRecoveryCategory
UINT StartRecoveryTime
UINT field156 //nice name
UNKNOWN[2]
UINT SpellFamilyName
UNKNOWN[11]
ENDENTRY
ENTRY SpellCastTime
INDEX ID
UINT CastTime
UNKNOWN[2]
ENDENTRY
ENTRY SpellRadius
INDEX ID
FLOAT Radius
UNKNOWN
FLOAT Radius2
ENDENTRY
ENTRY SpellRange
INDEX ID
FLOAT minRange
FLOAT maxRange
UNKNOWN[18]
UNKNOWN//some flag
ENDENTRY
ENTRY SpellDuration
INDEX ID
UINT Duration1
UINT Duration2
UINT Duration3
ENDENTRY
ENTRY AreaTableEntry
UINT ID
UNUSED UINT map
UINT zone
INDEX exploreFlag
UNKNOWN[6]
UINT area_level
UNUSED STR name
UNKNOWN[9]
ENDENTRY
ENTRY FactionEntry
INDEX ID
INT reputationListID
UNKNOWN[7]
UINT something1
UINT something2
UINT something3
UINT something4
UINT something5
UINT something6
UINT something7
UINT something8
UINT something9
UINT faction
UNUSED STR name
UNKNOWN[17]
ENDENTRY
ENTRY FactionTemplateEntry
INDEX ID
UINT faction
UNKNOWN
UINT fightsupport
UINT friendly
UINT hostile
UNKNOWN[8]
ENDENTRY
ENTRY ItemDisplayTemplateEntry
UINT ID
UNUSED STR modelFile
UNKNOWN
UNUSED STR imageFile
UNKNOWN
UNUSED STR invImageFile
UNKNOWN[5]
UINT seed
UNKNOWN [10]
UINT randomPropertyID
ENDENTRY

View file

@ -0,0 +1,10 @@
# The top-level input Makefile for mpq-tools
# Any directories which should be built and installed.
SUBDIRS = libmpq
# The directories which are part of the distribution.
DIST_SUBDIRS = $(SUBDIRS)
EXTRA_DIST = \
README.linux

View file

@ -0,0 +1,13 @@
Linux instructions
------------------
1. Configure and build MaNGOS.
2. cd contrib/map_extractor/libmpq/
3. make
4. cd ..
5. make
6. run ad
if there are any problems create folder named .deps in contrib/map_extractor/
it is old bug from first extractor and i am too lasy to fix it :)

View file

@ -0,0 +1,320 @@
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <deque>
#include <set>
#ifdef WIN32
#include "direct.h"
#else
#include <sys/stat.h>
#endif
#include "dbcfile.h"
#include "mpq_libmpq.h"
extern unsigned int iRes;
extern ArchiveSet gOpenArchives;
bool ConvertADT(char*,char*);
typedef struct{
char name[64];
unsigned int id;
}map_id;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
map_id * map_ids;
uint16 * areas;
char output_path[128]=".";
char input_path[128]=".";
enum Extract
{
EXTRACT_MAP = 1,
EXTRACT_DBC = 2
};
int extract = EXTRACT_MAP | EXTRACT_DBC;
static char* const langs[]={"deDE", "enGB", "enUS", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
#define LANG_COUNT 12
#define ADT_RES 64
void CreateDir( const std::string& Path )
{
#ifdef WIN32
_mkdir( Path.c_str());
#else
mkdir( Path.c_str(), 0777 );
#endif
}
bool FileExists( const char* FileName )
{
if( FILE* fp = fopen( FileName, "rb" ) )
{
fclose( fp );
return true;
}
return false;
}
void Usage(char* prg)
{
printf("Usage:\n%s -[var] [value]\n-i set input path\n-o set output path\n-r set resolution\n-e extract only MAP(1)/DBC(2) - standard: both(3)\nExample: %s -r 256 -i \"c:\\games\\game\"",
prg,prg);
exit(1);
}
void HandleArgs(int argc, char * arg[])
{
for(int c=1;c<argc;c++)
{
//i - input path
//o - output path
//r - resolution, array of (r * r) heights will be created
//e - extract only MAP(1)/DBC(2) - standard both(3)
if(arg[c][0] != '-')
Usage(arg[0]);
switch(arg[c][1])
{
case 'i':
if(c+1<argc)//all ok
strcpy(input_path,arg[(c++) +1]);
else
Usage(arg[0]);
break;
case 'o':
if(c+1<argc)//all ok
strcpy(output_path,arg[(c++) +1]);
else
Usage(arg[0]);
break;
case 'r':
if(c+1<argc)//all ok
iRes=atoi(arg[(c++) +1]);
else
Usage(arg[0]);
break;
case 'e':
if(c+1<argc)//all ok
{
extract=atoi(arg[(c++) +1]);
if(!(extract > 0 && extract < 4))
Usage(arg[0]);
}
else
Usage(arg[0]);
break;
}
}
}
uint32 ReadMapDBC()
{
printf("Read Map.dbc file... ");
DBCFile dbc("DBFilesClient\\Map.dbc");
dbc.open();
uint32 map_count=dbc.getRecordCount();
map_ids=new map_id[map_count];
for(unsigned int x=0;x<map_count;x++)
{
map_ids[x].id=dbc.getRecord(x).getUInt(0);
strcpy(map_ids[x].name,dbc.getRecord(x).getString(1));
}
printf("Done! (%u maps loaded)\n", map_count);
return map_count;
}
void ReadAreaTableDBC()
{
printf("Read AreaTable.dbc file... ");
DBCFile dbc("DBFilesClient\\AreaTable.dbc");
dbc.open();
unsigned int area_count=dbc.getRecordCount();
uint32 maxid = dbc.getMaxId();
areas=new uint16[maxid + 1];
memset(areas, 0xff, sizeof(areas));
for(unsigned int x=0; x<area_count;++x)
areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
printf("Done! (%u areas loaded)\n", area_count);
}
void ExtractMapsFromMpq()
{
char mpq_filename[1024];
char output_filename[1024];
printf("Extracting maps...\n");
uint32 map_count = ReadMapDBC();
ReadAreaTableDBC();
unsigned int total=map_count*ADT_RES*ADT_RES;
unsigned int done=0;
std::string path = output_path;
path += "/maps/";
CreateDir(path);
for(int x = 0; x < ADT_RES; ++x)
{
for(int y = 0; y < ADT_RES; ++y)
{
for(int z = 0; z < map_count; ++z)
{
sprintf(mpq_filename,"World\\Maps\\%s\\%s_%u_%u.adt",map_ids[z].name,map_ids[z].name,x,y);
sprintf(output_filename,"%s/maps/%03u%02u%02u.map",output_path,map_ids[z].id,y,x);
ConvertADT(mpq_filename,output_filename);
done++;
}
//draw progess bar
printf("Processing........................%d%%\r",(100*done)/total);
}
}
delete [] areas;
delete [] map_ids;
}
//bool WMO(char* filename);
void ExtractDBCFiles()
{
printf("Extracting dbc files...\n");
set<string> dbcfiles;
// get DBC file list
for(ArchiveSet::iterator i = gOpenArchives.begin(); i != gOpenArchives.end();++i)
{
vector<string> files = (*i)->GetFileList();
for (vector<string>::iterator iter = files.begin(); iter != files.end(); ++iter)
if (iter->rfind(".dbc") == iter->length() - strlen(".dbc"))
dbcfiles.insert(*iter);
}
std::string path = output_path;
path += "/dbc/";
CreateDir(path);
// extract DBCs
int count = 0;
for (set<string>::iterator iter = dbcfiles.begin(); iter != dbcfiles.end(); ++iter)
{
string filename = output_path;
filename += "/dbc/";
filename += (iter->c_str() + strlen("DBFilesClient\\"));
//cout << filename << endl;
FILE *output=fopen(filename.c_str(),"wb");
if(!output)
{
printf("Can't create the output file '%s'\n",filename.c_str());
continue;
}
MPQFile m(iter->c_str());
if(!m.isEof())
fwrite(m.getPointer(),1,m.getSize(),output);
fclose(output);
++count;
}
printf("Extracted %u DBC files\n", count);
}
int GetLocale()
{
for (int i = 0; i < LANG_COUNT; i++)
{
char tmp1[512];
sprintf(tmp1, "%s/Data/%s/locale-%s.MPQ", input_path, langs[i], langs[i]);
if (FileExists(tmp1))
{
printf("Detected locale: %s\n", langs[i]);
return i;
}
}
printf("Could not detect locale.\n");
return -1;
}
void LoadMPQFiles(int const locale)
{
char filename[512];
sprintf(filename,"%s/Data/%s/locale-%s.MPQ",input_path,langs[locale],langs[locale]);
new MPQArchive(filename);
for(int i = 1; i < 5; ++i)
{
char ext[3] = "";
if(i > 1)
sprintf(ext, "-%i", i);
sprintf(filename,"%s/Data/%s/patch-%s%s.MPQ",input_path,langs[locale],langs[locale],ext);
if(!FileExists(filename))
break;
new MPQArchive(filename);
}
//need those files only if extract maps
if(extract & EXTRACT_MAP)
{
sprintf(filename,"%s/Data/common.MPQ",input_path);
new MPQArchive(filename);
sprintf(filename,"%s/Data/expansion.MPQ",input_path);
new MPQArchive(filename);
for(int i = 1; i < 5; ++i)
{
char ext[3] = "";
if(i > 1)
sprintf(ext, "-%i", i);
sprintf(filename,"%s/Data/patch%s.MPQ",input_path,ext);
if(!FileExists(filename))
break;
new MPQArchive(filename);
}
}
}
int main(int argc, char * arg[])
{
printf("Map & DBC Extractor\n");
printf("===================\n");
HandleArgs(argc, arg);
int const locale = GetLocale();
if(locale < 0)
return 1;
LoadMPQFiles(locale);
if(extract & EXTRACT_DBC)
ExtractDBCFiles();
if(extract & EXTRACT_MAP)
ExtractMapsFromMpq();
//Close MPQs
for(ArchiveSet::iterator i = gOpenArchives.begin(); i != gOpenArchives.end();++i)
(*i)->close();
gOpenArchives.clear();
return 0;
}

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 8.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ad", "VC71_ad.vcproj", "{D7552D4F-408F-4F8E-859B-366659150CF4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.ActiveCfg = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.Build.0 = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.ActiveCfg = Release|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="ad"
ProjectGUID="{D7552D4F-408F-4F8E-859B-366659150CF4}"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="."
IntermediateDirectory=".\debug\"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="ad debug.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./debug/"
IgnoreDefaultLibraryNames="LIBCD.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="./ad debug.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="."
IntermediateDirectory=".\release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="./ad.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./release/"
IgnoreDefaultLibraryNames="LIBC.lib"
ProgramDatabaseFile="./ad.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\adt.cpp"
>
</File>
<File
RelativePath=".\libmpq\common.cpp"
>
</File>
<File
RelativePath=".\dbcfile.cpp"
>
</File>
<File
RelativePath=".\libmpq\explode.cpp"
>
</File>
<File
RelativePath=".\libmpq\extract.cpp"
>
</File>
<File
RelativePath=".\libmpq\huffman.cpp"
>
</File>
<File
RelativePath=".\libmpq\mpq.cpp"
>
</File>
<File
RelativePath=".\mpq_libmpq.cpp"
>
</File>
<File
RelativePath=".\libmpq\parser.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath=".\libmpq\wave.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\libmpq\common.h"
>
</File>
<File
RelativePath=".\dbcfile.h"
>
</File>
<File
RelativePath=".\libmpq\explode.h"
>
</File>
<File
RelativePath=".\libmpq\huffman.h"
>
</File>
<File
RelativePath=".\libmpq\mpq.h"
>
</File>
<File
RelativePath=".\mpq_libmpq.h"
>
</File>
<File
RelativePath=".\libmpq\wave.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ad", "VC80_ad.vcproj", "{D7552D4F-408F-4F8E-859B-366659150CF4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.ActiveCfg = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.Build.0 = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.ActiveCfg = Release|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,339 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="ad"
ProjectGUID="{D7552D4F-408F-4F8E-859B-366659150CF4}"
RootNamespace="ad"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="."
IntermediateDirectory=".\debug\"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4018"
Optimization="0"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="ad debug.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./debug/"
IgnoreDefaultLibraryNames="LIBCD.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="./ad debug.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="."
IntermediateDirectory=".\release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4018"
Optimization="3"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="./ad.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./release/"
IgnoreDefaultLibraryNames="LIBC.lib"
ProgramDatabaseFile="./ad.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\adt.cpp"
>
</File>
<File
RelativePath=".\dbcfile.cpp"
>
</File>
<File
RelativePath=".\mpq_libmpq.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<Filter
Name="libmpq"
>
<File
RelativePath=".\libmpq\common.cpp"
>
</File>
<File
RelativePath=".\libmpq\explode.cpp"
>
</File>
<File
RelativePath=".\libmpq\extract.cpp"
>
</File>
<File
RelativePath=".\libmpq\huffman.cpp"
>
</File>
<File
RelativePath=".\libmpq\mpq.cpp"
>
</File>
<File
RelativePath=".\libmpq\parser.cpp"
>
</File>
<File
RelativePath=".\libmpq\wave.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\adt.h"
>
</File>
<File
RelativePath=".\dbcfile.h"
>
</File>
<File
RelativePath=".\mpq_libmpq.h"
>
</File>
<Filter
Name="libmpq"
>
<File
RelativePath=".\libmpq\common.h"
>
</File>
<File
RelativePath=".\libmpq\explode.h"
>
</File>
<File
RelativePath=".\libmpq\huffman.h"
>
</File>
<File
RelativePath=".\libmpq\mpq.h"
>
</File>
<File
RelativePath=".\libmpq\wave.h"
>
</File>
<File
RelativePath=".\libmpq\zconf.h"
>
</File>
<File
RelativePath=".\libmpq\zlib.h"
>
</File>
</Filter>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ad", "VC90_ad.vcproj", "{D7552D4F-408F-4F8E-859B-366659150CF4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.ActiveCfg = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Debug|Win32.Build.0 = Debug|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.ActiveCfg = Release|Win32
{D7552D4F-408F-4F8E-859B-366659150CF4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,315 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="ad"
ProjectGUID="{D7552D4F-408F-4F8E-859B-366659150CF4}"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="."
IntermediateDirectory=".\debug\"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="ad debug.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./debug/"
IgnoreDefaultLibraryNames="LIBCD.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="./ad debug.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="."
IntermediateDirectory=".\release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName="./ad.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="libmpq"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="c:\windows\temp/ad.pch"
AssemblerListingLocation="c:\windows\temp/"
ObjectFile="c:\windows\temp/"
ProgramDataBaseFileName="c:\windows\temp/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1049"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="zlib.lib"
OutputFile="./ad.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories="./release/"
IgnoreDefaultLibraryNames="LIBC.lib"
ProgramDatabaseFile="./ad.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\adt.cpp"
>
</File>
<File
RelativePath=".\libmpq\common.cpp"
>
</File>
<File
RelativePath=".\dbcfile.cpp"
>
</File>
<File
RelativePath=".\libmpq\explode.cpp"
>
</File>
<File
RelativePath=".\libmpq\extract.cpp"
>
</File>
<File
RelativePath=".\libmpq\huffman.cpp"
>
</File>
<File
RelativePath=".\libmpq\mpq.cpp"
>
</File>
<File
RelativePath=".\mpq_libmpq.cpp"
>
</File>
<File
RelativePath=".\libmpq\parser.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath=".\libmpq\wave.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\libmpq\common.h"
>
</File>
<File
RelativePath=".\dbcfile.h"
>
</File>
<File
RelativePath=".\libmpq\explode.h"
>
</File>
<File
RelativePath=".\libmpq\huffman.h"
>
</File>
<File
RelativePath=".\libmpq\mpq.h"
>
</File>
<File
RelativePath=".\mpq_libmpq.h"
>
</File>
<File
RelativePath=".\libmpq\wave.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

BIN
contrib/extractor/ad Executable file

Binary file not shown.

BIN
contrib/extractor/ad.exe Executable file

Binary file not shown.

500
contrib/extractor/adt.cpp Normal file
View file

@ -0,0 +1,500 @@
#define _CRT_SECURE_NO_DEPRECATE
#ifdef WIN32
#include <windows.h>
#endif
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <string>
#include <map>
#include <vector>
#include <set>
#include "adt.h"
#include "mpq_libmpq.h"
//#include <windows.h>
unsigned int iRes=256;
extern uint16*areas;
vec wmoc;
Cell * cell;
uint32 wmo_count;
mcell *mcells;
int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
bool LoadADT(char* filename)
{
size_t size;
MPQFile mf(filename);
if(mf.isEof())
{
//printf("No such file.\n");
return false;
}
mcells=new mcell;
wmoc.x =65*TILESIZE;
wmoc.z =65*TILESIZE;
size_t mcnk_offsets[256], mcnk_sizes[256];
wmo_count=0;
bool found=false;
//uint32 fs=mf.getSize()-3;
//while (mf.getPos()<fs)
while (!mf.isEof())
{
uint32 fourcc;
mf.read(&fourcc,4);
mf.read(&size, 4);
size_t nextpos = mf.getPos() + size;
switch(fourcc)
{
case 0x4d43494e: // MCIN
{
//printf("Found chunks info\n");
// mapchunk offsets/sizes
for (int i=0; i<256; i++)
{
mf.read(&mcnk_offsets[i],4);
mf.read(&mcnk_sizes[i],4);
mf.seekRelative(8);
}
break;
}
case 0x4d4f4446: // MODF
{
/*
if(size)
{
//printf("\nwmo count %d\n",size/64);
wmo_count =size/64;
for (int i=0; i<wmo_count; i++)
{
int id;
mf.read(&id, 4);
WMO *wmo = (WMO*)wmomanager.items[wmomanager.get(wmos[id])];
WMOInstance inst(wmo, mf);
wmois.push_back(inst);
}
}*/
break;
}
case 0x4d574d4f: // MWMO
{
/*
if (size)
{
char *buf = new char[size];
mf.read(buf, size);
char *p=buf;
while (p<buf+size)
{
std::string path(p);
p+=strlen(p)+1;
fixname(path);
wmomanager.add(path);
wmos.push_back(path);
}
delete[] buf;
}*/
break;
}
case 0x4d564552: // MVER
case 0x4d484452: // MHDR header
case 0x4d434e4b: // MCNK
case 0x4d544558: // MTEX textures (strings)
case 0x4d4d4458: // MMDX m2 models (strings)
case 0x4d4d4944: // MMID offsets for strings in MMDX
case 0x4d574944: // MWID offsets for strings in MWMO
case 0x4d444446: // MDDF
case 0x4d46424f: // MFBO new in BC
case 0x4d48324f: // MH2O new in WotLK
case 0x4D545846: // MTXF new in WotLK
break;
default:
{
// mf.seekRelative(-3);
printf("Unhandled map chunk: %u\n",fourcc);
break;
}
}
mf.seek(nextpos);
}
//printf("Loading chunks info\n");
// read individual map chunks
for (int j=0; j<16; j++)
for (int i=0; i<16; i++)
{
mf.seek((int)mcnk_offsets[j*16+i]);
LoadMapChunk(mf,&(mcells->ch[i][j]));
}
/*
for(uint32 t=0;t<wmo_count ;t++)
{
wmois[t].draw();
}*/
mf.close();
return true;
}
struct MapChunkHeader {
uint32 flags;
uint32 ix;
uint32 iy;
uint32 nLayers;
uint32 nDoodadRefs;
uint32 ofsHeight;
uint32 ofsNormal;
uint32 ofsLayer;
uint32 ofsRefs;
uint32 ofsAlpha;
uint32 sizeAlpha;
uint32 ofsShadow;
uint32 sizeShadow;
uint32 areaid;
uint32 nMapObjRefs;
uint32 holes;
uint16 s1;
uint16 s2;
uint32 d1;
uint32 d2;
uint32 d3;
uint32 predTex;
uint32 nEffectDoodad;
uint32 ofsSndEmitters;
uint32 nSndEmitters;
uint32 ofsLiquid;
uint32 sizeLiquid;
float zpos;
float xpos;
float ypos;
uint32 textureId;
uint32 props;
uint32 effectId;
};
bool isHole(int holes, int i, int j)
{
int testi = i/2;
int testj = j/4;
if(testi>3) testi = 3;
if(testj>3) testj = 3;
return (holes & holetab_h[testi] & holetab_v[testj])!=0;
}
inline
void LoadMapChunk(MPQFile & mf, chunk*_chunk)
{
float h;
uint32 fourcc;
uint32 size;
MapChunkHeader header;
mf.seekRelative(4);
mf.read(&size, 4);
size_t lastpos = mf.getPos() + size;
mf.read(&header, 0x80);
_chunk->area_id =header.areaid ;
_chunk->flag =0;
float xbase = header.xpos;
float ybase = header.ypos;
float zbase = header.zpos;
zbase = TILESIZE*32-zbase;
xbase = TILESIZE*32-xbase;
if(wmoc.x >xbase)wmoc.x =xbase;
if(wmoc.z >zbase)wmoc.z =zbase;
int chunkflags = header.flags;
float zmin=999999999.0f;
float zmax=-999999999.0f;
//must be there, bl!zz uses some crazy format
int nTextures;
while (mf.getPos() < lastpos)
{
mf.read(&fourcc,4);
mf.read(&size, 4);
//if(size!=580)
// printf("\n sz=%d",size);
size_t nextpos = mf.getPos() + size;
if(fourcc==0x4d435654) // MCVT
{
for (int j=0; j<17; j++)
for (int i=0; i<((j%2)?8:9); i++)
{
mf.read(&h,4);
float z=h+ybase;
if (j%2)
{
if(isHole(header.holes,i,j))
_chunk->v8[i][j/2] = -1000;
else
_chunk->v8[i][j/2] = z;
}
else
{
if(isHole(header.holes,i,j))
_chunk->v9[i][j/2] = -1000;
else
_chunk->v9[i][j/2] = z;
}
if(z>zmax)zmax=z;
//if(z<zmin)zmin=z;
}
}
else if(fourcc==0x4d434e52) // MCNR
{
nextpos = mf.getPos() + 0x1C0; // size fix
}
else if(fourcc==0x4d434c51) // MCLQ
{
// liquid / water level
//bool haswater;
char fcc1[5];
mf.read(fcc1,4);
flipcc(fcc1);
fcc1[4]=0;
if (!strcmp(fcc1,"MCSE"))
{
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
_chunk->waterlevel[i][j]=-999999; // no liquid/water
}
else
{
float maxheight;
mf.read(&maxheight, 4);
for(int j=0;j<9;j++)
for(int i=0;i<9;i++)
{
mf.read(&h, 4);
mf.read(&h, 4);
if(h > maxheight)
_chunk->waterlevel[i][j]=-999999;
else
_chunk->waterlevel[i][j]=h;
}
if(chunkflags & 4 || chunkflags & 8)
_chunk->flag |=1;
if(chunkflags & 16)
_chunk->flag |=2;
}
break;
}
else if (fourcc==0x4d434c59) // MCLY
{
// texture info
nTextures = (int)size;
}
else if (fourcc==0x4d43414c) // MCAL
{
if (nTextures<=0)
continue;
}
mf.seek(nextpos);
}
}
double solve (vec *v,vec *p)
{
double a = v[0].y *(v[1].z - v[2].z) + v[1].y *(v[2].z - v[0].z) + v[2].y *(v[0].z - v[1].z);
double b = v[0].z *(v[1].x - v[2].x) + v[1].z *(v[2].x - v[0].x) + v[2].z *(v[0].x - v[1].x);
double c = v[0].x *(v[1].y - v[2].y) + v[1].x *(v[2].y - v[0].y) + v[2].x *(v[0].y - v[1].y);
double d = v[0].x *(v[1].y*v[2].z - v[2].y*v[1].z) + v[1].x* (v[2].y*v[0].z - v[0].y*v[2].z) + v[2].x* (v[0].y*v[1].z - v[1].y*v[0].z);
//-d
//plane equation ax+by+cz+d=0
return ((a*p->x+c*p->z-d)/b);
}
inline
double GetZ(double x,double z)
{
vec v[3];
vec p;
//bool inWMO=false;
//if(!inWMO)
{
//find out quadrant
int xc=(int)(x/UNITSIZE);
int zc=(int)(z/UNITSIZE);
if(xc>127)xc=127;
if(zc>127)zc=127;
double lx=x-xc*UNITSIZE;
double lz=z-zc*UNITSIZE;
p.x=lx;
p.z=lz;
v[0].x=UNITSIZE/2;
v[0].y =cell->v8[xc][zc];
v[0].z=UNITSIZE/2;
if(lx>lz)
{
v[1].x=UNITSIZE;
v[1].y =cell->v9[xc+1][zc];
v[1].z=0;
}
else
{
v[1].x=0.0;
v[1].y =cell->v9[xc][zc+1];
v[1].z=UNITSIZE;
}
if(lz>UNITSIZE-lx)
{
v[2].x=UNITSIZE;
v[2].y =cell->v9[xc+1][zc+1];
v[2].z=UNITSIZE;
}
else
{
v[2].x=0;
v[2].y=cell->v9[xc][zc];
v[2].z=0;
}
return -solve(v,&p);
}
}
inline
void TransformWaterData()
{
cell= new Cell;
for(int x=0;x<128;x++)
for(int y=0;y<128;y++)
cell->v9[x][y] = mcells->ch[x/8][y/8].waterlevel[x%8][y%8];
//and the last 1
cell->v9[128][128] = mcells->ch[15][15].waterlevel[8][8];
}
inline
void TransformData()
{
cell= new Cell;
for(int x=0;x<128;x++)
{
for(int y=0;y<128;y++)
{
cell->v8[x][y] = (float)mcells->ch[x/8][y/8].v8[x%8][y%8];
cell->v9[x][y] = (float)mcells->ch[x/8][y/8].v9[x%8][y%8];
}
//extra 1 point on bounds
cell->v9[x][128] = (float)mcells->ch[x/8][15].v9[x%8][8];
//x==y
cell->v9[128][x] = (float)mcells->ch[15][x/8].v9[8][x%8];
}
//and the last 1
cell->v9[128][128] = (float)mcells->ch[15][15].v9[8][8];
delete mcells;
}
const char MAP_MAGIC[] = "MAP_2.00";
bool ConvertADT(char * filename,char * filename2)
{
//if(!strstr(filename,"oth_32_48"))return false;
if(!LoadADT(filename))
return false;
FILE *output=fopen(filename2,"wb");
if(!output)
{
printf("Can't create the output file '%s'\n",filename2);
return false;
}
// write magic header
fwrite(MAP_MAGIC,1,8,output);
for(unsigned int x=0;x<16;x++)
{
for(unsigned int y=0;y<16;y++)
{
if(mcells->ch[y][x].area_id && mcells->ch[y][x].area_id < 0x102D)
{
if(areas[mcells->ch[y][x].area_id]==0xffff)
printf("\nCan't find area flag for areaid %u.\n",mcells->ch[y][x].area_id);
fwrite(&areas[mcells->ch[y][x].area_id],1,2,output);
}
else
{
uint16 flag=0xffff;
fwrite(&flag,1,2,output);
}
}
}
for(unsigned int x=0;x<16;x++)
for(unsigned int y=0;y<16;y++)
fwrite(&mcells->ch[y][x].flag,1,1,output);
TransformWaterData();
for(unsigned int x=0;x<128;x++)
for(unsigned int y=0;y<128;y++)
fwrite(&cell->v9[y][x],1,sizeof(float),output);
delete cell;
TransformData();
for(unsigned int x=0;x<iRes;x++)
for(unsigned int y=0;y<iRes;y++)
{
float z=(float)GetZ(
(((double)(y))*TILESIZE)/((double)(iRes-1)),
(((double)(x))*TILESIZE)/((double)(iRes-1)));
fwrite(&z,1,sizeof(z),output);
}
fclose(output);
delete cell;
/*
for (std::vector<std::string>::iterator it = wmos.begin(); it != wmos.end(); ++it)
wmomanager.delbyname(*it);
wmos.clear();
wmois.clear();
for (std::vector<model>::iterator it = wmomodel.begin(); it != wmomodel.end(); ++it)
{
it->tr.clear();
}
//printf("\n %d \n",in);
wmomodel.clear();
//polygons.clear();*/
return true;
}

53
contrib/extractor/adt.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef ADT_H
#define ADT_H
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
#define UNITSIZE (CHUNKSIZE / 8.0f)
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
class Liquid;
typedef struct {
float x;
float y;
float z;
}svec;
typedef struct {
double x;
double y;
double z;
}vec;
typedef struct{
vec v[3];
}triangle;
typedef struct{
float v9[16*8+1][16*8+1];
float v8[16*8][16*8];
}Cell;
typedef struct{
double v9[9][9];
double v8[8][8];
uint16 area_id;
//Liquid *lq;
float waterlevel[9][9];
uint8 flag;
}chunk;
class WMO;
class WMOManager;
void fixname(std::string &name);
typedef struct
{
chunk ch[16][16];
}mcell;
class MPQFile;
void LoadMapChunk(MPQFile &,chunk*);
bool LoadWMO(char* filename);
#endif

View file

@ -0,0 +1,69 @@
#define _CRT_SECURE_NO_DEPRECATE
#include "dbcfile.h"
#include "mpq_libmpq.h"
DBCFile::DBCFile(const std::string &filename):
filename(filename),
data(0)
{
}
void DBCFile::open()
{
MPQFile f(filename.c_str());
char header[4];
unsigned int na,nb,es,ss;
f.read(header,4); // Number of records
assert(header[0]=='W' && header[1]=='D' && header[2]=='B' && header[3] == 'C');
f.read(&na,4); // Number of records
f.read(&nb,4); // Number of fields
f.read(&es,4); // Size of a record
f.read(&ss,4); // String size
recordSize = es;
recordCount = na;
fieldCount = nb;
stringSize = ss;
assert(fieldCount*4 == recordSize);
data = new unsigned char[recordSize*recordCount+stringSize];
stringTable = data + recordSize*recordCount;
f.read(data,recordSize*recordCount+stringSize);
f.close();
}
DBCFile::~DBCFile()
{
delete [] data;
}
DBCFile::Record DBCFile::getRecord(size_t id)
{
assert(data);
return Record(*this, data + id*recordSize);
}
size_t DBCFile::getMaxId()
{
assert(data);
size_t maxId = 0;
for(size_t i = 0; i < getRecordCount(); ++i)
{
if(maxId < getRecord(i).getUInt(0))
maxId = getRecord(i).getUInt(0);
}
return maxId;
}
DBCFile::Iterator DBCFile::begin()
{
assert(data);
return Iterator(*this, data);
}
DBCFile::Iterator DBCFile::end()
{
assert(data);
return Iterator(*this, stringTable);
}

118
contrib/extractor/dbcfile.h Normal file
View file

@ -0,0 +1,118 @@
#ifndef DBCFILE_H
#define DBCFILE_H
#include <cassert>
#include <string>
class DBCFile
{
public:
DBCFile(const std::string &filename);
~DBCFile();
// Open database. It must be openened before it can be used.
void open();
// Database exceptions
class Exception
{
public:
Exception(const std::string &message): message(message)
{ }
virtual ~Exception()
{ }
const std::string &getMessage() {return message;}
private:
std::string message;
};
class NotFound: public Exception
{
public:
NotFound(): Exception("Key was not found")
{ }
};
// Iteration over database
class Iterator;
class Record
{
public:
float getFloat(size_t field) const
{
assert(field < file.fieldCount);
return *reinterpret_cast<float*>(offset+field*4);
}
unsigned int getUInt(size_t field) const
{
assert(field < file.fieldCount);
return *reinterpret_cast<unsigned int*>(offset+field*4);
}
int getInt(size_t field) const
{
assert(field < file.fieldCount);
return *reinterpret_cast<int*>(offset+field*4);
}
const char *getString(size_t field) const
{
assert(field < file.fieldCount);
size_t stringOffset = getUInt(field);
assert(stringOffset < file.stringSize);
return reinterpret_cast<char*>(file.stringTable + stringOffset);
}
private:
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
unsigned char *offset;
DBCFile &file;
friend class DBCFile;
friend class DBCFile::Iterator;
};
/** Iterator that iterates over records
*/
class Iterator
{
public:
Iterator(DBCFile &file, unsigned char *offset):
record(file, offset) {}
/// Advance (prefix only)
Iterator & operator++() {
record.offset += record.file.recordSize;
return *this;
}
/// Return address of current instance
Record const & operator*() const { return record; }
const Record* operator->() const {
return &record;
}
/// Comparison
bool operator==(const Iterator &b) const
{
return record.offset == b.record.offset;
}
bool operator!=(const Iterator &b) const
{
return record.offset != b.record.offset;
}
private:
Record record;
};
// Get record by id
Record getRecord(size_t id);
/// Get begin iterator over records
Iterator begin();
/// Get begin iterator over records
Iterator end();
/// Trivial
size_t getRecordCount() const { return recordCount;}
size_t getFieldCount() const { return fieldCount; }
size_t getMaxId();
private:
std::string filename;
size_t recordSize;
size_t recordCount;
size_t fieldCount;
size_t stringSize;
unsigned char *data;
unsigned char *stringTable;
};
#endif

Binary file not shown.

View file

@ -0,0 +1,23 @@
# The input Makefile for the main mpq-tools
lib_LTLIBRARIES = libmpq.la
noinst_HEADERS = explode.h huffman.h wave.h common.h
# The directory where the include files will be installed.
libmpq_includedir = $(includedir)/libmpq
# Which header files to install.
libmpq_include_HEADERS = mpq.h
libmpq_la_SOURCES = $(GENERAL_SRCS)
libmpq_la_LDFLAGS = -release $(LIBMPQ_VERSION)
libmpq_la_LIBADD = @Z_LIBS@
GENERAL_SRCS = \
common.c \
huffman.c \
extract.c \
explode.c \
mpq.c \
parser.c \
wave.c

View file

@ -0,0 +1,801 @@
/*
* common.c -- shared functions used by mpq-tools.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: common.c,v 1.12 2004/02/12 00:42:54 mbroemme Exp $
*/
#define _CRT_SECURE_NO_DEPRECATE
//#include <dirent.h>
#include <sys/stat.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mpq.h"
#include "common.h"
#include <ctype.h>
/*
* This function decrypts a MPQ block.
*/
int libmpq_decrypt_block(mpq_archive *mpq_a, unsigned int *block, unsigned int length, unsigned int seed1) {
unsigned int seed2 = 0xEEEEEEEE;
unsigned int ch;
/* Round to unsigned int's */
length >>= 2;
while (length-- > 0) {
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
ch = *block ^ (seed1 + seed2);
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
*block++ = ch;
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function decrypts the hashtable for the
* file informations.
*/
int libmpq_decrypt_hashtable(mpq_archive *mpq_a, unsigned char *pbKey) {
unsigned int seed1 = 0x7FED7FED;
unsigned int seed2 = 0xEEEEEEEE;
unsigned int ch; /* One key character */
unsigned int *pdwTable = (unsigned int *)(mpq_a->hashtable);
unsigned int length = mpq_a->header->hashtablesize * 4;
/* Prepare seeds */
while (*pbKey != 0) {
ch = toupper(*pbKey++);
seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
/* Decrypt it */
seed2 = 0xEEEEEEEE;
while (length-- > 0) {
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
ch = *pdwTable ^ (seed1 + seed2);
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
*pdwTable++ = ch;
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function decrypts the blocktable.
*/
int libmpq_decrypt_blocktable(mpq_archive *mpq_a, unsigned char *pbKey) {
unsigned int seed1 = 0x7FED7FED;
unsigned int seed2 = 0xEEEEEEEE;
unsigned int ch; /* One key character */
unsigned int *pdwTable = (unsigned int *)(mpq_a->blocktable);
unsigned int length = mpq_a->header->blocktablesize * 4;
/* Prepare seeds */
while(*pbKey != 0) {
ch = toupper(*pbKey++);
seed1 = mpq_a->buf[0x300 + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
/* Decrypt it */
seed2 = 0xEEEEEEEE;
while(length-- > 0) {
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
ch = *pdwTable ^ (seed1 + seed2);
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
*pdwTable++ = ch;
}
return LIBMPQ_TOOLS_SUCCESS;
}
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp) {
int mpq_size;
int mpq_ht_size;
int mpq_bt_size;
int mpq_blocksize;
int mpq_files;
int mpq_csize;
int mpq_fsize;
int entries;
char listdb_version[10];
char libmpq_version[10];
int listdb_temp_version = 0;
int libmpq_temp_version = 0;
/* first check header and version */
if (libmpq_conf_get_value(fp, "LIBMPQ_VERSION", mpq_a->mpq_l->mpq_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_version))) {
return LIBMPQ_CONF_EFILE_CORRUPT;
} else {
/* copy to temp buffer for removing . characters */
sprintf(listdb_version, (char *)mpq_a->mpq_l->mpq_version);
/* remove . characters from listfile version */
libmpq_conf_delete_char(listdb_version, ".");
/* get libmpq version */
sprintf(libmpq_version, "%i%i%i",LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
/* convert to number */
listdb_temp_version = atoi(listdb_version);
libmpq_temp_version = atoi(libmpq_version);
/* check if installed libmpq version is valid for listfile version */
if ((libmpq_temp_version < listdb_temp_version) || (libmpq_temp_version == 0) || (listdb_temp_version == 0)) {
return LIBMPQ_CONF_EFILE_VERSION;
}
}
/* check listfile header, the following entries must be set */
if (libmpq_conf_get_value(fp, "MPQ_SIZE", &mpq_size, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_HASHTABLE_SIZE", &mpq_ht_size, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_BLOCKTABLE_SIZE", &mpq_bt_size, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_BLOCKSIZE", &mpq_blocksize, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_FILES", &mpq_files, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_COMPRESSED_SIZE", &mpq_csize, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_UNCOMPRESSED_SIZE", &mpq_fsize, LIBMPQ_CONF_TYPE_INT, 0)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_NAME", mpq_a->mpq_l->mpq_name, LIBMPQ_CONF_TYPE_CHAR, PATH_MAX)) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
if (libmpq_conf_get_value(fp, "MPQ_TYPE", mpq_a->mpq_l->mpq_type, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_type))) {
return LIBMPQ_CONF_EFILE_CORRUPT;
}
/* these are optional parameters, if they are empty we set the struct members empty */
libmpq_conf_get_value(fp, "MPQ_GAME", mpq_a->mpq_l->mpq_game, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game));
libmpq_conf_get_value(fp, "MPQ_GAME_VERSION", mpq_a->mpq_l->mpq_game_version, LIBMPQ_CONF_TYPE_CHAR, sizeof(mpq_a->mpq_l->mpq_game_version));
/* check if we found a valid listfile for the given archive */
if (mpq_a->header->hashtablesize == mpq_ht_size && mpq_a->header->blocktablesize == mpq_bt_size && mpq_a->blocksize == mpq_blocksize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_ARCHIVE_SIZE) == mpq_size && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) == mpq_files && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_COMPRESSED_SIZE) == mpq_csize && libmpq_archive_info(mpq_a, LIBMPQ_MPQ_UNCOMPRESSED_SIZE) == mpq_fsize) {
/* check if the filelist is correct */
if (!libmpq_conf_get_array(fp, "FILE_NAMES", (char ***)&mpq_a->mpq_l->mpq_files, &entries)) {
/* we have a corrupt filelist, so return */
return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
} else {
/* now check if filelist entries matches number of files in the archive. */
if (entries != libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES)) {
libmpq_free_listfile((char **)mpq_a->mpq_l->mpq_files);
mpq_a->mpq_l->mpq_files = NULL;
return LIBMPQ_CONF_EFILE_LIST_CORRUPT;
}
}
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function frees up the space reserved by libmpq_get_listfile()
*/
int libmpq_free_listfile(char **filelist) {
int i = 0;
while (filelist[i]) {
free(filelist[i++]);
}
free(filelist);
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function reads the directory and the subdirectories
* of the listfile database and adds a entry to the lisfile
* array.
*/
/*int libmpq_detect_listfile_rec(char path[PATH_MAX], char ***filelist, int *fl_count, int *fl_size) {
char nextpath[PATH_MAX];
DIR *dp = opendir(path);
FILE *fp;
struct dirent *entry;
struct stat statbuf;
char buf[LIBMPQ_CONF_BUFSIZE];
if (dp == NULL) {
return LIBMPQ_CONF_EOPEN_DIR;
} else {
while ((entry = readdir(dp)) != NULL) {
if (strncmp(entry->d_name, ".", 1) == 0 || strncmp(entry->d_name, "..", 2) == 0) {
continue;
}
if (strnlen(path, PATH_MAX) + strnlen(entry->d_name, PATH_MAX) + 2 > sizeof nextpath) {
continue;
}
snprintf(nextpath, PATH_MAX, "%s/%s", path, entry->d_name);
// check if file extension matches listdb file extension
if (strncmp(&entry->d_name[strlen(entry->d_name) - strlen(LIBMPQ_CONF_EXT)], LIBMPQ_CONF_EXT, strlen(LIBMPQ_CONF_EXT)) == 0) {
// check if it is really a listdb file
if ((fp = fopen(nextpath, "r")) != NULL ) {
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
char *line;
buf[strlen(buf) - 1] = '\0';
// skip whitespace
for (line = buf; isspace(*line); line++) {
continue;
}
// skip empty line
if (line[0] == '\0') {
continue;
}
// skip comments
if (line[0] == '#') {
continue;
}
//search for listdb header; dirty but works :)
if (!strncasecmp(line, LIBMPQ_CONF_HEADER, strlen(LIBMPQ_CONF_HEADER))) {
// set the next filelist entry to a copy of the file path
(*filelist)[(*fl_count)++] = strdup(nextpath);
// increase the array size
if ((*fl_count) == (*fl_size)) {
(*filelist) = realloc((*filelist), ((*fl_size) + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
(*fl_size) += LIBMPQ_CONF_FL_INCREMENT;
}
// header found so we could stop reading the file.
break;
}
}
fclose(fp);
}
}
if (stat(nextpath, &statbuf) < 0) {
continue;
}
// if entry ia a subdirectory, read it
if (S_ISDIR(statbuf.st_mode)) {
libmpq_detect_listfile_rec(nextpath, filelist, fl_count, fl_size);
}
}
closedir(dp);
}
return LIBMPQ_TOOLS_SUCCESS;
}
*/
/*
* This functions tries to get file decryption key. The trick comes from block
* positions which are stored at the begin of each compressed file. We know the
* file size, that means we know number of blocks that means we know the first
* int value in block position. And if we know encrypted and decrypted value,
* we can find the decryption key.
*/
int libmpq_detect_fileseed(mpq_archive *mpq_a, unsigned int *block, unsigned int decrypted) {
unsigned int saveseed1;
unsigned int temp = *block ^ decrypted; /* temp = seed1 + seed2 */
int i = 0;
temp -= 0xEEEEEEEE; /* temp = seed1 + mpq_a->buf[0x400 + (seed1 & 0xFF)] */
for (i = 0; i < 0x100; i++) { /* Try all 255 possibilities */
unsigned int seed1;
unsigned int seed2 = 0xEEEEEEEE;
unsigned int ch;
/* Try the first unsigned int's (We exactly know the value) */
seed1 = temp - mpq_a->buf[0x400 + i];
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
ch = block[0] ^ (seed1 + seed2);
if (ch != decrypted) {
continue;
}
/* Add 1 because we are decrypting block positions */
saveseed1 = seed1 + 1;
/*
* If OK, continue and test the second value. We don't know exactly the value,
* but we know that the second one has lower 16 bits set to zero
* (no compressed block is larger than 0xFFFF bytes)
*/
seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
seed2 = ch + seed2 + (seed2 << 5) + 3;
seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
ch = block[1] ^ (seed1 + seed2);
if ((ch & 0xFFFF0000) == 0) {
return saveseed1;
}
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function initialize the decryption buffer
*/
int libmpq_init_buffer(mpq_archive *mpq_a) {
unsigned int seed = 0x00100001;
unsigned int index1 = 0;
unsigned int index2 = 0;
int i;
memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
/* Initialize the decryption buffer. */
for (index1 = 0; index1 < 0x100; index1++) {
for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
unsigned int temp1, temp2;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp1 = (seed & 0xFFFF) << 0x10;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp2 = (seed & 0xFFFF);
mpq_a->buf[index2] = (temp1 | temp2);
}
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This functions fills the mpq_hash structure with the
* hashtable found in the MPQ file. The hashtable will
* be decrypted for later use.
*/
int libmpq_read_hashtable(mpq_archive *mpq_a) {
unsigned int bytes = 0;
int rb = 0;
/*
* Allocate memory. Note that the block table should be as large as the
* hash table. (for later file additions)
*/
mpq_a->hashtable = (mpq_hash *)malloc(sizeof(mpq_hash) * mpq_a->header->hashtablesize);
if (!mpq_a->hashtable) {
return LIBMPQ_EALLOCMEM;
}
/* Read the hash table into the buffer */
bytes = mpq_a->header->hashtablesize * sizeof(mpq_hash);
#ifdef WIN32
_lseeki64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
#else
lseek64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
#endif
rb = _read(mpq_a->fd, mpq_a->hashtable, bytes);
if (rb != bytes) {
return LIBMPQ_EFILE_CORRUPT;
}
/* Decrypt hash table and check if it is correctly decrypted */
mpq_hash *mpq_h_end = mpq_a->hashtable + mpq_a->header->hashtablesize;
mpq_hash *mpq_h = NULL;
libmpq_decrypt_hashtable(mpq_a, (unsigned char *)"(hash table)");
/* Check hash table if is correctly decrypted */
for (mpq_h = mpq_a->hashtable; mpq_h < mpq_h_end; mpq_h++) {
if (mpq_h->locale != 0xFFFFFFFF && (mpq_h->locale & 0xFFFF0000) != 0) {
return LIBMPQ_EFILE_FORMAT;
}
/* Remember the highest block table entry */
if (mpq_h->blockindex < LIBMPQ_HASH_ENTRY_DELETED && mpq_h->blockindex > 0) {
mpq_a->maxblockindex = mpq_h->blockindex;
}
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This functions fills the mpq_block structure with the
* blocktable found in the MPQ file. The blocktable will
* be decrypted for later use.
*
* NOTICE: Some MPQs have decrypted block table, e.g.
* cracked Diablo versions.
*/
int libmpq_read_blocktable(mpq_archive *mpq_a) {
unsigned int bytes = 0;
int rb = 0;
/*
* Allocate memory. Note that the block table should be as large as the
* hash table. (for later file additions)
*/
mpq_a->blocktable = (mpq_block *)malloc(sizeof(mpq_block) * mpq_a->header->hashtablesize);
mpq_a->blockbuf = (unsigned char *)malloc(mpq_a->blocksize);
if (!mpq_a->blocktable || !mpq_a->blockbuf) {
return LIBMPQ_EALLOCMEM;
}
/* Read the block table into the buffer */
bytes = mpq_a->header->blocktablesize * sizeof(mpq_block);
memset(mpq_a->blocktable, 0, mpq_a->header->blocktablesize * sizeof(mpq_block));
#ifdef WIN32
_lseeki64(mpq_a->fd, mpq_a->header->blocktablepos, SEEK_SET);
#else
lseek64(mpq_a->fd, mpq_a->header->blocktablepos, SEEK_SET);
#endif
rb = _read(mpq_a->fd, mpq_a->blocktable, bytes);
if (rb != bytes) {
return LIBMPQ_EFILE_CORRUPT;
}
/*
* Decrypt block table. Some MPQs don't have encrypted block table,
* e.g. cracked Diablo version. We have to check if block table is
* already decrypted
*/
mpq_block *mpq_b_end = mpq_a->blocktable + mpq_a->maxblockindex + 1;
mpq_block *mpq_b = NULL;
unsigned int archivesize = mpq_a->header->archivesize + mpq_a->mpqpos;
if (mpq_a->header->offset != mpq_a->blocktable->filepos) {
libmpq_decrypt_blocktable(mpq_a, (unsigned char *)"(block table)");
}
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
if (mpq_b->filepos > archivesize || mpq_b->csize > archivesize) {
if ((mpq_a->flags & LIBMPQ_FLAG_PROTECTED) == 0) {
return LIBMPQ_EFILE_FORMAT;
}
}
mpq_b->filepos += mpq_a->mpqpos;
}
return LIBMPQ_TOOLS_SUCCESS;
}
int libmpq_file_read_block(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes) {
unsigned char *tempbuf = NULL; /* Buffer for reading compressed data from the file */
unsigned int readpos; /* Reading position from the file */
unsigned int toread = 0; /* Number of bytes to read */
unsigned int blocknum; /* Block number (needed for decrypt) */
unsigned int bytesread = 0; /* Total number of bytes read */
unsigned int nblocks; /* Number of blocks to load */
unsigned int i;
/* Test parameters. Block position and block size must be block-aligned, block size nonzero */
if ((blockpos & (mpq_a->blocksize - 1)) || blockbytes == 0) {
return 0;
}
/* Check the end of file */
if ((blockpos + blockbytes) > mpq_f->mpq_b->fsize) {
blockbytes = mpq_f->mpq_b->fsize - blockpos;
}
blocknum = blockpos / mpq_a->blocksize;
nblocks = blockbytes / mpq_a->blocksize;
if (blockbytes % mpq_a->blocksize) {
nblocks++;
}
/* If file has variable block positions, we have to load them */
if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) && mpq_f->blockposloaded == FALSE) {
unsigned int nread;
if (mpq_f->mpq_b->filepos != mpq_a->filepos) {
#ifdef WIN32
_lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
#else
lseek64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
#endif
}
/* Read block positions from begin of file. */
nread = (mpq_f->nblocks + 1) * sizeof(int);
nread = _read(mpq_a->fd, mpq_f->blockpos, nread);
/*
* If the archive is protected some way, perform additional check
* Sometimes, the file appears not to be encrypted, but it is.
*/
/*if (mpq_f->blockpos[0] != nread) {
mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED;
}*/
if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_HAS_METADATA) == 0) {
if (mpq_f->blockpos[0] != nread) {
mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED;
}
}
/* Decrypt loaded block positions if necessary */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
/* If we don't know the file seed, try to find it. */
if (mpq_f->seed == 0) {
mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
}
/* If we don't know the file seed, sorry but we cannot extract the file. */
if (mpq_f->seed == 0) {
return 0;
}
/* Decrypt block positions */
libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
/*
* Check if the block positions are correctly decrypted
* I don't know why, but sometimes it will result invalid
* block positions on some files.
*/
if (mpq_f->blockpos[0] != nread) {
/* Try once again to detect file seed and decrypt the blocks */
#ifdef WIN32
_lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
#else
lseek64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
#endif
nread = _read(mpq_a->fd, mpq_f->blockpos, (mpq_f->nblocks + 1) * sizeof(int));
mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
/* Check if the block positions are correctly decrypted. */
if (mpq_f->blockpos[0] != nread) {
return 0;
}
}
}
/* Update mpq_f's variables */
mpq_f->blockposloaded = TRUE;
mpq_a->filepos = mpq_f->mpq_b->filepos + nread;
}
/* Get file position and number of bytes to read */
readpos = blockpos;
toread = blockbytes;
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
readpos = mpq_f->blockpos[blocknum];
toread = mpq_f->blockpos[blocknum + nblocks] - readpos;
}
readpos += mpq_f->mpq_b->filepos;
/* Get work buffer for store read data */
if ((tempbuf = (unsigned char *)malloc(toread)) == NULL) {
/* Hmmm... We should add a better error handling here :) */
return 0;
}
/* Set file pointer, if necessary. */
if (mpq_a->filepos != readpos) {
#ifdef WIN32
mpq_a->filepos = _lseeki64(mpq_a->fd, readpos, SEEK_SET);
#else
mpq_a->filepos = lseek64(mpq_a->fd, readpos, SEEK_SET);
#endif
}
/* 15018F87 - Read all requested blocks. */
bytesread = _read(mpq_a->fd, tempbuf, toread);
mpq_a->filepos = readpos + bytesread;
/* Block processing part. */
unsigned int blockstart = 0; /* Index of block start in work buffer. */
unsigned int blocksize = min(blockbytes, mpq_a->blocksize);
unsigned int index = blocknum; /* Current block index. */
bytesread = 0; /* Clear read byte counter */
/* Walk through all blocks. */
for (i = 0; i < nblocks; i++, index++) {
int outlength = mpq_a->blocksize;
/* Get current block length */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
blocksize = mpq_f->blockpos[index + 1] - mpq_f->blockpos[index];
}
/* If block is encrypted, we have to decrypt it. */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
if (mpq_f->seed == 0) {
return 0;
}
libmpq_decrypt_block(mpq_a, (unsigned int *)&tempbuf[blockstart], blocksize, mpq_f->seed + index);
}
/*
* If the block is really compressed, recompress it.
* WARNING: Some block may not be compressed, it can
* only be determined by comparing uncompressed and
* compressed size!
*/
if (blocksize < blockbytes) {
/* Is the file compressed with PKWARE Data Compression Library? */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
libmpq_pkzip_decompress(buffer, &outlength, (char *)&tempbuf[blockstart], blocksize);
}
/*
* Is it a file compressed by Blizzard's multiple compression ?
* Note that Storm.dll v 1.0.9 distributed with Warcraft III
* passes the full path name of the opened archive as the new
* last parameter.
*/
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
libmpq_multi_decompress(buffer, &outlength, (char *)&tempbuf[blockstart], blocksize);
}
bytesread += outlength;
buffer += outlength;
} else {
memcpy(buffer, tempbuf, blocksize);
bytesread += blocksize;
buffer += blocksize;
}
blockstart += blocksize;
}
/* Delete input buffer, if necessary. */
free(tempbuf);
return bytesread;
}
int libmpq_file_read_file(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int filepos, char *buffer, unsigned int toread) {
unsigned int bytesread = 0; /* Number of bytes read from the file */
unsigned int blockpos; /* Position in the file aligned to the whole blocks */
unsigned int loaded = 0;
/* File position is greater or equal to file size? */
if (filepos >= mpq_f->mpq_b->fsize) {
return 0;
}
/* If to few bytes in the file remaining, cut them */
if ((mpq_f->mpq_b->fsize - filepos) < toread) {
toread = (mpq_f->mpq_b->fsize - filepos);
}
/* Block position in the file */
blockpos = filepos & ~(mpq_a->blocksize - 1);
/*
* Load the first block, if noncomplete. It may be loaded in the cache buffer.
* We have to check if this block is loaded. If not, load it.
*/
if ((filepos % mpq_a->blocksize) != 0) {
/* Number of bytes remaining in the buffer */
unsigned int tocopy;
unsigned int loaded = mpq_a->blocksize;
/* Check if data are loaded in the cache */
if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {
/* Load one MPQ block into archive buffer */
loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char *)mpq_a->blockbuf, mpq_a->blocksize);
if (loaded == 0) {
return 0;
}
/* Save lastly accessed file and block position for later use */
mpq_f->accessed = TRUE;
mpq_a->blockpos = blockpos;
mpq_a->bufpos = filepos % mpq_a->blocksize;
}
tocopy = loaded - mpq_a->bufpos;
if (tocopy > toread) {
tocopy = toread;
}
/* Copy data from block buffer into target buffer */
memcpy(buffer, mpq_a->blockbuf + mpq_a->bufpos, tocopy);
/* Update pointers */
toread -= tocopy;
bytesread += tocopy;
buffer += tocopy;
blockpos += mpq_a->blocksize;
mpq_a->bufpos += tocopy;
/* If all, return. */
if (toread == 0) {
return bytesread;
}
}
/* Load the whole ("middle") blocks only if there are more or equal one block */
if (toread > mpq_a->blocksize) {
unsigned int blockbytes = toread & ~(mpq_a->blocksize - 1);
loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, buffer, blockbytes);
if (loaded == 0) {
return 0;
}
/* Update pointers */
toread -= loaded;
bytesread += loaded;
buffer += loaded;
blockpos += loaded;
/* If all, return. */
if (toread == 0) {
return bytesread;
}
}
/* Load the terminating block */
if (toread > 0) {
unsigned int tocopy = mpq_a->blocksize;
/* Check if data are loaded in the cache */
if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {
/* Load one MPQ block into archive buffer */
tocopy = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char *)mpq_a->blockbuf, mpq_a->blocksize);
if (tocopy == 0) {
return 0;
}
/* Save lastly accessed file and block position for later use */
mpq_f->accessed = TRUE;
mpq_a->blockpos = blockpos;
}
mpq_a->bufpos = 0;
/* Check number of bytes read */
if (tocopy > toread) {
tocopy = toread;
}
memcpy(buffer, mpq_a->blockbuf, tocopy);
bytesread += tocopy;
mpq_a->bufpos = tocopy;
}
/* Return what we've read */
return bytesread;
}

View file

@ -0,0 +1,66 @@
/*
* common.h -- defines and structs used by the config files.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: common.h,v 1.4 2004/02/12 00:41:55 mbroemme Exp $
*/
#define LIBMPQ_CONF_FL_INCREMENT 512 /* i hope we did not need more :) */
#define LIBMPQ_CONF_EXT ".conf" /* listdb file seems to be valid with this extension */
#define LIBMPQ_CONF_HEADER "LIBMPQ_VERSION" /* listdb file must include this entry to be valid */
#define LIBMPQ_CONF_BUFSIZE 4096 /* maximum number of bytes a line in the file could contain */
#define LIBMPQ_CONF_TYPE_CHAR 1 /* value in config file is from type char */
#define LIBMPQ_CONF_TYPE_INT 2 /* value in config file is from type int */
#define LIBMPQ_CONF_EOPEN_DIR -1 /* error on open directory */
#define LIBMPQ_CONF_EVALUE_NOT_FOUND -2 /* value for the option was not found */
#if defined( __GNUC__ )
#include <sys/types.h>
#include <unistd.h>
#define _lseek lseek
#define _read read
#define _open open
#define _write write
#define _close close
#define _strdup strdup
#ifndef O_BINARY
#define O_BINARY 0
#endif
#else
#include <io.h>
#endif
#ifndef min
#define min(a, b) ((a < b) ? a : b)
#endif
int libmpq_init_buffer(mpq_archive *mpq_a);
int libmpq_read_hashtable(mpq_archive *mpq_a);
int libmpq_read_blocktable(mpq_archive *mpq_a);
int libmpq_file_read_file(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int filepos, char *buffer, unsigned int toread);
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp);
int libmpq_conf_get_value(FILE *fp, char *search_value, void *return_value, int type, int size);
char *libmpq_conf_delete_char(char *buf, char *chars);
int libmpq_conf_get_array(FILE *fp, char *search_value, char ***filelist, int *entries);
int libmpq_free_listfile(char **filelist);
int libmpq_read_listfile(mpq_archive *mpq_a, FILE *fp);

View file

@ -0,0 +1,428 @@
/*
* explode.c -- explode function of PKWARE data compression library.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of pkware.cpp included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <assert.h>
#include <string.h>
#include "mpq.h"
#include "explode.h"
/* Tables */
static unsigned char pkzip_dist_bits[] = {
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
static unsigned char pkzip_dist_code[] = {
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A,
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00
};
static unsigned char pkzip_clen_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
};
static unsigned short pkzip_len_base[] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106
};
static unsigned char pkzip_slen_bits[] = {
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07
};
static unsigned char pkzip_len_code[] = {
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00
};
static unsigned char pkzip_bits_asc[] = {
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08,
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B,
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06,
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08,
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05,
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C,
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D,
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
};
static unsigned short pkzip_code_asc[] = {
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0,
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0,
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360,
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60,
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8,
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098,
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C,
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710,
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8,
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E,
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8,
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088,
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A,
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D,
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078,
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0,
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040,
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380,
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180,
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280,
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080,
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300,
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0,
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320,
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220,
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0,
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0,
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340,
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900,
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600,
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200,
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
};
/* Local variables */
static char copyright[] = "PKWARE Data Compression Library for Win32\r\n"
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n"
"Patent No. 5,051,745\r\n"
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n"
"Version 1.11\r\n";
/* Local functions */
static void libmpq_pkzip_gen_decode_tabs(long count, unsigned char *bits, unsigned char *code, unsigned char *buf2) {
long i;
for (i = count-1; i >= 0; i--) { /* EBX - count */
unsigned long idx1 = code[i];
unsigned long idx2 = 1 << bits[i];
do {
buf2[idx1] = (unsigned char)i;
idx1 += idx2;
} while (idx1 < 0x100);
}
}
static void libmpq_pkzip_gen_asc_tabs(pkzip_data_cmp *mpq_pkzip) {
unsigned short *code_asc = &pkzip_code_asc[0xFF];
unsigned long acc, add;
unsigned short count;
for (count = 0x00FF; code_asc >= pkzip_code_asc; code_asc--, count--) {
unsigned char *bits_asc = mpq_pkzip->bits_asc + count;
unsigned char bits_tmp = *bits_asc;
if (bits_tmp <= 8) {
add = (1 << bits_tmp);
acc = *code_asc;
do {
mpq_pkzip->offs_2c34[acc] = (unsigned char)count;
acc += add;
} while (acc < 0x100);
} else {
if ((acc = (*code_asc & 0xFF)) != 0) {
mpq_pkzip->offs_2c34[acc] = 0xFF;
if (*code_asc & 0x3F) {
bits_tmp -= 4;
*bits_asc = bits_tmp;
add = (1 << bits_tmp);
acc = *code_asc >> 4;
do {
mpq_pkzip->offs_2d34[acc] = (unsigned char)count;
acc += add;
} while (acc < 0x100);
} else {
bits_tmp -= 6;
*bits_asc = bits_tmp;
add = (1 << bits_tmp);
acc = *code_asc >> 6;
do {
mpq_pkzip->offs_2e34[acc] = (unsigned char)count;
acc += add;
} while (acc < 0x80);
}
} else {
bits_tmp -= 8;
*bits_asc = bits_tmp;
add = (1 << bits_tmp);
acc = *code_asc >> 8;
do {
mpq_pkzip->offs_2eb4[acc] = (unsigned char)count;
acc += add;
} while (acc < 0x100);
}
}
}
}
/*
* Skips given number of bits in bit buffer. Result is stored in mpq_pkzip->bit_buf
* If no data in input buffer, returns true
*/
static int libmpq_pkzip_skip_bits(pkzip_data_cmp *mpq_pkzip, unsigned long bits) {
/* If number of bits required is less than number of (bits in the buffer) ? */
if (bits <= mpq_pkzip->extra_bits) {
mpq_pkzip->extra_bits -= bits;
mpq_pkzip->bit_buf >>= bits;
return 0;
}
/* Load input buffer if necessary */
mpq_pkzip->bit_buf >>= mpq_pkzip->extra_bits;
if (mpq_pkzip->in_pos == mpq_pkzip->in_bytes) {
mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
if ((mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param)) == 0) {
return 1;
}
mpq_pkzip->in_pos = 0;
}
/* Update bit buffer */
mpq_pkzip->bit_buf |= (mpq_pkzip->in_buf[mpq_pkzip->in_pos++] << 8);
mpq_pkzip->bit_buf >>= (bits - mpq_pkzip->extra_bits);
mpq_pkzip->extra_bits = (mpq_pkzip->extra_bits - bits) + 8;
return 0;
}
/*
* Decompress the imploded data using coded literals.
* Returns: 0x000 - 0x0FF : One byte from compressed file.
* 0x100 - 0x305 : Copy previous block (0x100 = 1 byte)
* 0x306 : Out of buffer (?)
*/
static unsigned long libmpq_pkzip_explode_lit(pkzip_data_cmp *mpq_pkzip) {
unsigned long bits; /* Number of bits to skip */
unsigned long value; /* Position in buffers */
/* Test the current bit in byte buffer. If is not set, simply return the next byte. */
if (mpq_pkzip->bit_buf & 1) {
/* Skip current bit in the buffer. */
if (libmpq_pkzip_skip_bits(mpq_pkzip, 1)) {
return 0x306;
}
/* The next bits are position in buffers. */
value = mpq_pkzip->pos2[(mpq_pkzip->bit_buf & 0xFF)];
/* Get number of bits to skip */
if (libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->slen_bits[value])) {
return 0x306;
}
if ((bits = mpq_pkzip->clen_bits[value]) != 0) {
unsigned long val2 = mpq_pkzip->bit_buf & ((1 << bits) - 1);
if (libmpq_pkzip_skip_bits(mpq_pkzip, bits)) {
if ((value + val2) != 0x10E) {
return 0x306;
}
}
value = mpq_pkzip->len_base[value] + val2;
}
return value + 0x100; /* Return number of bytes to repeat */
}
/* Skip one bit */
if (libmpq_pkzip_skip_bits(mpq_pkzip, 1)) {
return 0x306;
}
/* If the binary compression type, read 8 bits and return them as one byte. */
if (mpq_pkzip->cmp_type == LIBMPQ_PKZIP_CMP_BINARY) {
value = mpq_pkzip->bit_buf & 0xFF;
if (libmpq_pkzip_skip_bits(mpq_pkzip, 8)) {
return 0x306;
}
return value;
}
/* When ASCII compression ... */
if (mpq_pkzip->bit_buf & 0xFF) {
value = mpq_pkzip->offs_2c34[mpq_pkzip->bit_buf & 0xFF];
if (value == 0xFF) {
if (mpq_pkzip->bit_buf & 0x3F) {
if (libmpq_pkzip_skip_bits(mpq_pkzip, 4)) {
return 0x306;
}
value = mpq_pkzip->offs_2d34[mpq_pkzip->bit_buf & 0xFF];
} else {
if (libmpq_pkzip_skip_bits(mpq_pkzip, 6)) {
return 0x306;
}
value = mpq_pkzip->offs_2e34[mpq_pkzip->bit_buf & 0x7F];
}
}
} else {
if (libmpq_pkzip_skip_bits(mpq_pkzip, 8)) {
return 0x306;
}
value = mpq_pkzip->offs_2eb4[mpq_pkzip->bit_buf & 0xFF];
}
return libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->bits_asc[value]) ? 0x306 : value;
}
/*
* Retrieves the number of bytes to move back.
*/
static unsigned long libmpq_pkzip_explode_dist(pkzip_data_cmp *mpq_pkzip, unsigned long length) {
unsigned long pos = mpq_pkzip->pos1[(mpq_pkzip->bit_buf & 0xFF)];
unsigned long skip = mpq_pkzip->dist_bits[pos]; /* Number of bits to skip */
/* Skip the appropriate number of bits */
if (libmpq_pkzip_skip_bits(mpq_pkzip, skip) == 1) {
return 0;
}
if (length == 2) {
pos = (pos << 2) | (mpq_pkzip->bit_buf & 0x03);
if (libmpq_pkzip_skip_bits(mpq_pkzip, 2) == 1) {
return 0;
}
} else {
pos = (pos << mpq_pkzip->dsize_bits) | (mpq_pkzip->bit_buf & mpq_pkzip->dsize_mask);
/* Skip the bits */
if (libmpq_pkzip_skip_bits(mpq_pkzip, mpq_pkzip->dsize_bits) == 1) {
return 0;
}
}
return pos + 1;
}
static unsigned long libmpq_pkzip_expand(pkzip_data_cmp *mpq_pkzip) {
unsigned int copy_bytes; /* Number of bytes to copy */
unsigned long one_byte; /* One byte from compressed file */
unsigned long result;
mpq_pkzip->out_pos = 0x1000; /* Initialize output buffer position */
/* If end of data or error, terminate decompress */
while ((result = one_byte = libmpq_pkzip_explode_lit(mpq_pkzip)) < 0x305) {
/* If one byte is greater than 0x100, means "Repeat n - 0xFE bytes" */
if (one_byte >= 0x100) {
unsigned char *source; /* ECX */
unsigned char *target; /* EDX */
unsigned long copy_length = one_byte - 0xFE;
unsigned long move_back;
/* Get length of data to copy */
if ((move_back = libmpq_pkzip_explode_dist(mpq_pkzip, copy_length)) == 0) {
result = 0x306;
break;
}
/* Target and source pointer */
target = &mpq_pkzip->out_buf[mpq_pkzip->out_pos];
source = target - move_back;
mpq_pkzip->out_pos += copy_length;
while (copy_length-- > 0) {
*target++ = *source++;
}
} else {
mpq_pkzip->out_buf[mpq_pkzip->out_pos++] = (unsigned char)one_byte;
}
/*
* If number of extracted bytes has reached 1/2 of output buffer,
* flush output buffer.
*/
if (mpq_pkzip->out_pos >= 0x2000) {
/* Copy decompressed data into user buffer. */
copy_bytes = 0x1000;
mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], &copy_bytes, mpq_pkzip->param);
/* If there are some data left, keep them alive */
memcpy(mpq_pkzip->out_buf, &mpq_pkzip->out_buf[0x1000], mpq_pkzip->out_pos - 0x1000);
mpq_pkzip->out_pos -= 0x1000;
}
}
copy_bytes = mpq_pkzip->out_pos - 0x1000;
mpq_pkzip->write_buf((char *)&mpq_pkzip->out_buf[0x1000], &copy_bytes, mpq_pkzip->param);
return result;
}
/*
* Main exploding function.
*/
unsigned int libmpq_pkzip_explode(
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
void (*write_buf)(char *buf, unsigned int *size, void *param),
char *work_buf,
void *param) {
pkzip_data_cmp *mpq_pkzip = (pkzip_data_cmp *)work_buf;
/* Set the whole work buffer to zeros */
memset(mpq_pkzip, 0, sizeof(pkzip_data_cmp));
/* Initialize work struct and load compressed data */
mpq_pkzip->read_buf = read_buf;
mpq_pkzip->write_buf = write_buf;
mpq_pkzip->param = param;
mpq_pkzip->in_pos = sizeof(mpq_pkzip->in_buf);
mpq_pkzip->in_bytes = mpq_pkzip->read_buf((char *)mpq_pkzip->in_buf, &mpq_pkzip->in_pos, mpq_pkzip->param);
if (mpq_pkzip->in_bytes <= 4) {
return LIBMPQ_PKZIP_CMP_BAD_DATA;
}
mpq_pkzip->cmp_type = mpq_pkzip->in_buf[0]; /* Get the compression type */
mpq_pkzip->dsize_bits = mpq_pkzip->in_buf[1]; /* Get the dictionary size */
mpq_pkzip->bit_buf = mpq_pkzip->in_buf[2]; /* Initialize 16-bit bit buffer */
mpq_pkzip->extra_bits = 0; /* Extra (over 8) bits */
mpq_pkzip->in_pos = 3; /* Position in input buffer */
/* Test for the valid dictionary size */
if (4 > mpq_pkzip->dsize_bits || mpq_pkzip->dsize_bits > 6) {
return LIBMPQ_PKZIP_CMP_INV_DICTSIZE;
}
mpq_pkzip->dsize_mask = 0xFFFF >> (0x10 - mpq_pkzip->dsize_bits); /* Shifted by 'sar' instruction */
if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_BINARY) {
if (mpq_pkzip->cmp_type != LIBMPQ_PKZIP_CMP_ASCII) {
return LIBMPQ_PKZIP_CMP_INV_MODE;
}
memcpy(mpq_pkzip->bits_asc, pkzip_bits_asc, sizeof(mpq_pkzip->bits_asc));
libmpq_pkzip_gen_asc_tabs(mpq_pkzip);
}
memcpy(mpq_pkzip->slen_bits, pkzip_slen_bits, sizeof(mpq_pkzip->slen_bits));
libmpq_pkzip_gen_decode_tabs(0x10, mpq_pkzip->slen_bits, pkzip_len_code, mpq_pkzip->pos2);
memcpy(mpq_pkzip->clen_bits, pkzip_clen_bits, sizeof(mpq_pkzip->clen_bits));
memcpy(mpq_pkzip->len_base, pkzip_len_base, sizeof(mpq_pkzip->len_base));
memcpy(mpq_pkzip->dist_bits, pkzip_dist_bits, sizeof(mpq_pkzip->dist_bits));
libmpq_pkzip_gen_decode_tabs(0x40, mpq_pkzip->dist_bits, pkzip_dist_code, mpq_pkzip->pos1);
if (libmpq_pkzip_expand(mpq_pkzip) != 0x306) {
return LIBMPQ_PKZIP_CMP_NO_ERROR;
}
return LIBMPQ_PKZIP_CMP_ABORT;
}

View file

@ -0,0 +1,86 @@
/*
* explode.h -- header file for PKWARE data decompression library
* used by mpq-tools.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of pklib.h included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _EXPLODE_H
#define _EXPLODE_H
#define LIBMPQ_PKZIP_EXP_BUFFER_SIZE 12596 /* Size of decompress buffer */
#define LIBMPQ_PKZIP_CMP_BINARY 0 /* Binary compression */
#define LIBMPQ_PKZIP_CMP_ASCII 1 /* Ascii compression */
#define LIBMPQ_PKZIP_CMP_NO_ERROR 0
#define LIBMPQ_PKZIP_CMP_INV_DICTSIZE 1
#define LIBMPQ_PKZIP_CMP_INV_MODE 2
#define LIBMPQ_PKZIP_CMP_BAD_DATA 3
#define LIBMPQ_PKZIP_CMP_ABORT 4
/* Compression structure (size: 12596 bytes on x86-32) */
typedef struct {
unsigned long offs0000; /* 0000 */
unsigned long cmp_type; /* 0004 - Compression type (LIBMPQ_PZIP_CMP_BINARY or LIBMPQ_PKZIP_CMP_ASCII) */
unsigned long out_pos; /* 0008 - Position in output buffer */
unsigned long dsize_bits; /* 000C - Dict size (4, 5, 6 for 0x400, 0x800, 0x1000) */
unsigned long dsize_mask; /* 0010 - Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000) */
unsigned long bit_buf; /* 0014 - 16-bit buffer for processing input data */
unsigned long extra_bits; /* 0018 - Number of extra (above 8) bits in bit buffer */
unsigned int in_pos; /* 001C - Position in in_buf */
unsigned long in_bytes; /* 0020 - Number of bytes in input buffer */
void *param; /* 0024 - Custom parameter */
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); /* 0028 */
void (*write_buf)(char *buf, unsigned int *size, void *param); /* 002C */
unsigned char out_buf[0x2000]; /* 0030 - Output circle buffer. Starting position is 0x1000 */
unsigned char offs_2030[0x204]; /* 2030 - ??? */
unsigned char in_buf[0x800]; /* 2234 - Buffer for data to be decompressed */
unsigned char pos1[0x100]; /* 2A34 - Positions in buffers */
unsigned char pos2[0x100]; /* 2B34 - Positions in buffers */
unsigned char offs_2c34[0x100]; /* 2C34 - Buffer for */
unsigned char offs_2d34[0x100]; /* 2D34 - Buffer for */
unsigned char offs_2e34[0x80]; /* 2EB4 - Buffer for */
unsigned char offs_2eb4[0x100]; /* 2EB4 - Buffer for */
unsigned char bits_asc[0x100]; /* 2FB4 - Buffer for */
unsigned char dist_bits[0x40]; /* 30B4 - Numbers of bytes to skip copied block length */
unsigned char slen_bits[0x10]; /* 30F4 - Numbers of bits for skip copied block length */
unsigned char clen_bits[0x10]; /* 3104 - Number of valid bits for copied block */
unsigned short len_base[0x10]; /* 3114 - Buffer for */
} pkzip_data_cmp;
// __attribute__ ((packed)) pkzip_data_cmp;
typedef struct {
char *in_buf; /* Pointer to input data buffer */
unsigned int in_pos; /* Current offset in input data buffer */
int in_bytes; /* Number of bytes in the input buffer */
char *out_buf; /* Pointer to output data buffer */
unsigned int out_pos; /* Position in the output buffer */
int max_out; /* Maximum number of bytes in the output buffer */
} pkzip_data;
extern unsigned int libmpq_pkzip_explode(
unsigned int (*read_buf)(char *buf, unsigned int *size, void *param),
void (*write_buf)(char *buf, unsigned int *size, void *param),
char *work_buf,
void *param
);
#endif /* _EXPLODE_H */

View file

@ -0,0 +1,262 @@
/*
* extract.c -- global extracting function for all known file compressions
* in a MPQ archive.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define HAVE_LIBZ
#ifdef HAVE_LIBZ
#include <zlib.h>
#endif
#include "mpq.h"
#include "explode.h"
#include "huffman.h"
#include "wave.h"
/*
* Support functions for PKWARE data compression library.
*
* Function loads data from the input buffer. Used by mpq_pkzip
* "implode" and "explode" function as user-defined callback.
* Returns number of bytes loaded.
*
* char * buf - Pointer to a buffer where to store loaded data
* unsigned int * size - Max. number of bytes to read
* void * param - Custom pointer, parameter of implode/explode
*/
static unsigned int libmpq_pkzip_read_input_data(char *buf, unsigned int *size, void *param) {
pkzip_data *info = (pkzip_data *)param;
unsigned int max_avail = (info->in_bytes - info->in_pos);
unsigned int to_read = *size;
/* Check the case when not enough data available */
if (to_read > max_avail) {
to_read = max_avail;
}
/* Load data and increment offsets */
memcpy(buf, info->in_buf + info->in_pos, to_read);
info->in_pos += to_read;
return to_read;
}
/*
* Support functions for PKWARE data compression library.
*
* Function for store output data. Used by mpq_pkzip "implode" and
* "explode" as user-defined callback.
*
* char * buf - Pointer to data to be written
* unsigned int * size - Number of bytes to write
* void * param - Custom pointer, parameter of implode/explode
*/
static void libmpq_pkzip_write_output_data(char *buf, unsigned int *size, void *param) {
pkzip_data *info = (pkzip_data *)param;
unsigned int max_write = (info->max_out - info->out_pos);
unsigned int to_write = *size;
/* Check the case when not enough space in the output buffer */
if (to_write > max_write) {
to_write = max_write;
}
/* Write output data and increments offsets */
memcpy(info->out_buf + info->out_pos, buf, to_write);
info->out_pos += to_write;
}
int libmpq_pkzip_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
pkzip_data info; /* Data information */
char *work_buf = (char *)malloc(LIBMPQ_PKZIP_EXP_BUFFER_SIZE); /* mpq_pkzip work buffer */
/* Fill data information structure */
info.in_buf = in_buf;
info.in_pos = 0;
info.in_bytes = in_length;
info.out_buf = out_buf;
info.out_pos = 0;
info.max_out = *out_length;
/* Do the decompression */
libmpq_pkzip_explode(libmpq_pkzip_read_input_data, libmpq_pkzip_write_output_data, work_buf, &info);
*out_length = info.out_pos;
free(work_buf);
return 0;
}
int libmpq_wave_decompress_mono(char *out_buf, int *out_length, char *in_buf, int in_length) {
*out_length = libmpq_wave_decompress((unsigned char *)out_buf, *out_length, (unsigned char *)in_buf, in_length, 1);
return 1;
}
int libmpq_wave_decompress_stereo(char *out_buf, int *out_length, char *in_buf, int in_length) {
*out_length = libmpq_wave_decompress((unsigned char *)out_buf, *out_length, (unsigned char *)in_buf, in_length, 2);
return 1;
}
int libmpq_zlib_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
#ifdef HAVE_LIBZ
z_stream z; /* Stream information for zlib */
int result;
/* Fill the stream structure for zlib */
z.next_in = (Bytef *)in_buf;
z.avail_in = (uInt)in_length;
z.total_in = in_length;
z.next_out = (Bytef *)out_buf;
z.avail_out = *out_length;
z.total_out = 0;
z.zalloc = NULL;
z.zfree = NULL;
/* Initialize the decompression structure. Storm.dll uses zlib version 1.1.3 */
if ((result = inflateInit(&z)) == 0) {
/* Call zlib to decompress the data */
result = inflate(&z, Z_FINISH);
*out_length = z.total_out;
inflateEnd(&z);
}
return result;
#else
memset(out_buf, '0', *out_length);
return 0;
#endif
}
/*
* Huffmann decompression routine. The in_length parameter is not used, but needs
* to be specified due to compatibility reasons.
*
* 1500F5F0
*/
int libmpq_huff_decompress(char *out_buf, int *out_length, char *in_buf, int in_length) {
struct huffman_tree *ht = (huffman_tree *)malloc(sizeof(struct huffman_tree));
struct huffman_input_stream *is = (huffman_input_stream *)malloc(sizeof(struct huffman_input_stream));
struct huffman_tree_item *hi = (huffman_tree_item *)malloc(sizeof(struct huffman_tree_item));
memset(ht, 0, sizeof(struct huffman_tree));
memset(is, 0, sizeof(struct huffman_input_stream));
memset(hi, 0, sizeof(struct huffman_tree_item));
/* Initialize input stream */
is->bit_buf = *(unsigned long *)in_buf;
in_buf += sizeof(unsigned long);
is->in_buf = (unsigned char *)in_buf;
is->bits = 32;
/* Initialize the Huffmann tree for decompression */
libmpq_huff_init_tree(ht, hi, LIBMPQ_HUFF_DECOMPRESS);
*out_length = libmpq_huff_do_decompress(ht, is, (unsigned char *)out_buf, *out_length);
free(hi);
free(is);
free(ht);
return 0;
}
int libmpq_multi_decompress(char *out_buf, int *pout_length, char *in_buf, int in_length) {
char *temp_buf = NULL; /* Temporary storage for decompressed data */
char *work_buf = NULL; /* Where to store decompressed data */
int out_length = *pout_length; /* For storage number of output bytes */
unsigned fDecompressions1; /* Decompressions applied to the block */
unsigned fDecompressions2; /* Just another copy of decompressions applied to the block */
int count = 0; /* Counter for every use */
int entries = (sizeof(dcmp_table) / sizeof(decompress_table));
int i;
/* If the input length is the same as output, do nothing. */
if (in_length == out_length) {
if (in_buf == out_buf) {
return 1;
}
memcpy(out_buf, in_buf, in_length);
return 1;
}
/* Get applied compression types and decrement data length */
fDecompressions1 = fDecompressions2 = (unsigned char)*in_buf++;
in_length--;
/* Search decompression table type and get all types of compression */
for (i = 0; i < entries; i++) {
/* We have to apply this decompression? */
if (fDecompressions1 & dcmp_table[i].mask) {
count++;
}
/* Clear this flag from temporary variable. */
fDecompressions2 &= ~dcmp_table[i].mask;
}
/*
* Check if there is some method unhandled
* (E.g. compressed by future versions)
*/
if (fDecompressions2 != 0) {
printf("Unknown Compression\n");
return 0;
}
/* If there is more than only one compression, we have to allocate extra buffer */
if (count >= 2) {
temp_buf = (char *)malloc(out_length);
}
/* Apply all decompressions */
for (i = 0, count = 0; i < entries; i++) {
/* If not used this kind of compression, skip the loop */
if (fDecompressions1 & dcmp_table[i].mask) {
/* If odd case, use target buffer for output, otherwise use allocated tempbuf */
work_buf = (count++ & 1) ? temp_buf : out_buf;
out_length = *pout_length;
/* Decompress buffer using corresponding function */
dcmp_table[i].decompress(work_buf, &out_length, in_buf, in_length);
/* Move output length to src length for next compression */
in_length = out_length;
in_buf = work_buf;
}
}
/* If output buffer is not the same like target buffer, we have to copy data */
if (work_buf != out_buf) {
memcpy(out_buf, in_buf, out_length);
}
*pout_length = out_length;
/* Delete temporary buffer, if necessary */
if (temp_buf != NULL) {
free(temp_buf);
}
return 1;
}

View file

@ -0,0 +1,833 @@
/*
* huffman.c -- functions do decompress files in MPQ files which
* uses a modified huffman version.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* Differences between C++ and C version:
*
* - Removed the object oriented stuff.
* - Replaced the goto things with some better C code.
*
* This source was adepted from the C++ version of huffman.cpp included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
* ShadowFlare <BlakFlare@hotmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "mpq.h"
#include "huffman.h"
unsigned char table1502A630[] = {
/* Data for compression type 0x00 */
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00,
/* Data for compression type 0x01 */
0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
0x00, 0x00,
/* Data for compression type 0x02 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
/* Data for compression type 0x03 */
0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
0x00, 0x00,
/* Data for compression type 0x04 */
0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
/* Data for compression type 0x05 */
0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
/* Data for compression type 0x06 */
0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
/* Data for compression type 0x07 */
0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
/* Data for compression type 0x08 */
0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
/* Gets previous Huffman tree item (?) */
struct huffman_tree_item *libmpq_huff_get_prev_item(struct huffman_tree_item *hi, long value) {
if (PTR_INT(hi->prev) < 0) {
return PTR_NOT(hi->prev);
}
if (value < 0) {
value = hi - hi->next->prev;
}
return hi->prev + value;
}
/* 1500BC90 */
static void libmpq_huff_remove_item(struct huffman_tree_item *hi) {
struct huffman_tree_item *temp; /* EDX */
if (hi->next != NULL) {
temp = hi->prev;
if (PTR_INT(temp) <= 0) {
temp = PTR_NOT(temp);
} else {
temp += (hi - hi->next->prev);
}
temp->next = hi->next;
hi->next->prev = hi->prev;
hi->next = hi->prev = NULL;
}
}
static void libmpq_huff_insert_item(struct huffman_tree_item **p_item, struct huffman_tree_item *item, unsigned long where, struct huffman_tree_item *item2) {
struct huffman_tree_item *next = item->next; /* EDI - next to the first item */
struct huffman_tree_item *prev = item->prev; /* ESI - prev to the first item */
struct huffman_tree_item *prev2; /* Pointer to previous item */
long next2; /* Pointer to the next item */
/* The same code like in mpq_huff_remove_item(); */
if (next != 0) { /* If the first item already has next one */
if (PTR_INT(prev) < 0) {
prev = PTR_NOT(prev);
} else {
prev += (item - next->prev);
}
/*
* 150083C1
* Remove the item from the tree
*/
prev->next = next;
next->prev = prev;
/* Invalidate 'prev' and 'next' pointer */
item->next = 0;
item->prev = 0;
}
if (item2 == NULL) { /* EDX - If the second item is not entered, */
item2 = PTR_PTR(&p_item[1]); /* take the first tree item */
}
switch (where) {
case SWITCH_ITEMS: /* Switch the two items */
item->next = item2->next; /* item2->next (Pointer to pointer to first) */
item->prev = item2->next->prev;
item2->next->prev = item;
item2->next = item; /* Set the first item */
return;
case INSERT_ITEM: /* Insert as the last item */
item->next = item2; /* Set next item (or pointer to pointer to first item) */
item->prev = item2->prev; /* Set prev item (or last item in the tree) */
next2 = PTR_INT(p_item[0]); /* Usually NULL */
prev2 = item2->prev; /* Prev item to the second (or last tree item) */
if (PTR_INT(prev2) < 0) {
prev2 = PTR_NOT(prev);
prev2->next = item;
item2->prev = item; /* Next after last item */
return;
}
if (next2 < 0) {
next2 = item2 - item2->next->prev;
}
prev2 += next2;
prev2->next = item;
item2->prev = item; /* Set the next/last item */
return;
default:
return;
}
}
/* Builds Huffman tree. Called with the first 8 bits loaded from input stream. */
static void libmpq_huff_build_tree(struct huffman_tree *ht, unsigned int cmp_type) {
unsigned long max_byte; /* [ESP+10] - The greatest character found in table */
unsigned char *byte_array; /* [ESP+1C] - Pointer to unsigned char in table1502A630 */
unsigned long i; /* egcs in linux doesn't like multiple for loops without an explicit i */
unsigned int found; /* Thats needed to replace the goto stuff from original source :) */
struct huffman_tree_item **p_item; /* [ESP+14] - Pointer to Huffman tree item pointer array */
struct huffman_tree_item *child1;
/* Loop while pointer has a negative value. */
while (PTR_INT(ht->last) > 0) { /* ESI - Last entry */
struct huffman_tree_item *temp; /* EAX */
if (ht->last->next != NULL) { /* ESI->next */
libmpq_huff_remove_item(ht->last);
}
ht->item3058 = PTR_PTR(&ht->item3054);/* [EDI+4] */
ht->last->prev = ht->item3058; /* EAX */
temp = libmpq_huff_get_prev_item(PTR_PTR(&ht->item3054), PTR_INT(&ht->item3050));
temp->next = ht->last;
ht->item3054 = ht->last;
}
/* Clear all pointers in huffman tree item array. */
memset(ht->items306C, 0, sizeof(ht->items306C));
max_byte = 0; /* Greatest character found init to zero. */
p_item = (struct huffman_tree_item **)&ht->items306C; /* Pointer to current entry in huffman tree item pointer array */
/* Ensure we have low 8 bits only */
cmp_type &= 0xFF;
byte_array = table1502A630 + cmp_type * 258; /* EDI also */
for (i = 0; i < 0x100; i++, p_item++) {
struct huffman_tree_item *item = ht->item3058; /* Item to be created */
struct huffman_tree_item *p_item3 = ht->item3058;
unsigned char one_byte = byte_array[i];
/* Skip all the bytes which are zero. */
if (byte_array[i] == 0) {
continue;
}
/* If not valid pointer, take the first available item in the array. */
if (PTR_INT(item) <= 0) {
item = &ht->items0008[ht->items++];
}
/* Insert this item as the top of the tree. */
libmpq_huff_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
item->parent = NULL; /* Invalidate child and parent */
item->child = NULL;
*p_item = item; /* Store pointer into pointer array */
item->dcmp_byte = i; /* Store counter */
item->byte_value = one_byte; /* Store byte value */
if (one_byte >= max_byte) {
max_byte = one_byte;
continue;
}
/* Find the first item which has byte value greater than current one byte */
found = 0;
if (PTR_INT((p_item3 = ht->last)) > 0) {/* EDI - Pointer to the last item */
/* 15006AF7 */
if (p_item3 != NULL) {
do { /* 15006AFB */
if (p_item3->byte_value >= one_byte) {
found = 1;
break;
}
p_item3 = p_item3->prev;
} while (PTR_INT(p_item3) > 0);
}
}
if (found == 0) {
p_item3 = NULL;
}
/* 15006B09 */
if (item->next != NULL) {
libmpq_huff_remove_item(item);
}
/* 15006B15 */
if (p_item3 == NULL) {
p_item3 = PTR_PTR(&ht->first);
}
/* 15006B1F */
item->next = p_item3->next;
item->prev = p_item3->next->prev;
p_item3->next->prev = item;
p_item3->next = item;
}
/* 15006B4A */
for (; i < 0x102; i++) {
struct huffman_tree_item **p_item2 = &ht->items306C[i]; /* EDI */
/* 15006B59 */
struct huffman_tree_item *item2 = ht->item3058; /* ESI */
if (PTR_INT(item2) <= 0) {
item2 = &ht->items0008[ht->items++];
}
libmpq_huff_insert_item(&ht->item305C, item2, INSERT_ITEM, NULL);
/* 15006B89 */
item2->dcmp_byte = i;
item2->byte_value = 1;
item2->parent = NULL;
item2->child = NULL;
*p_item2++ = item2;
}
/* 15006BAA */
if (PTR_INT((child1 = ht->last)) > 0) { /* EDI - last item (first child to item */
struct huffman_tree_item *child2; /* EBP */
struct huffman_tree_item *item; /* ESI */
/* 15006BB8 */
while (PTR_INT((child2 = child1->prev)) > 0) {
if (PTR_INT((item = ht->item3058)) <= 0) {
item = &ht->items0008[ht->items++];
}
/* 15006BE3 */
libmpq_huff_insert_item(&ht->item305C, item, SWITCH_ITEMS, NULL);
/* 15006BF3 */
item->parent = NULL;
item->child = NULL;
/*
* EDX = child2->byte_value + child1->byte_value;
* EAX = child1->byte_value;
* ECX = max_byte; The greatest character (0xFF usually)
*/
item->byte_value = child1->byte_value + child2->byte_value; /* 0x02 */
item->child = child1; /* Prev item in the */
child1->parent = item;
child2->parent = item;
/* EAX = item->byte_value; */
if (item->byte_value >= max_byte) {
max_byte = item->byte_value;
} else {
struct huffman_tree_item *p_item2 = child2->prev; /* EDI */
found = 0;
if (PTR_INT(p_item2) > 0) {
/* 15006C2D */
do {
if (p_item2->byte_value >= item->byte_value) {
found = 1;
break;
}
p_item2 = p_item2->prev;
} while (PTR_INT(p_item2) > 0);
}
if (found == 0) {
p_item2 = NULL;
}
if (item->next != 0) {
struct huffman_tree_item *temp4 = libmpq_huff_get_prev_item(item, -1);
temp4->next = item->next; /* The first item changed */
item->next->prev = item->prev; /* First->prev changed to negative value */
item->next = NULL;
item->prev = NULL;
}
/* 15006C62 */
if (p_item2 == NULL) {
p_item2 = PTR_PTR(&ht->first);
}
item->next = p_item2->next; /* Set item with 0x100 byte value */
item->prev = p_item2->next->prev; /* Set item with 0x17 byte value */
p_item2->next->prev = item; /* Changed prev of item with */
p_item2->next = item;
}
/* 15006C7B */
if (PTR_INT((child1 = child2->prev)) <= 0) {
break;
}
}
}
/* 15006C88 */
ht->offs0004 = 1;
}
/* Gets the whole byte from the input stream. */
static unsigned long libmpq_huff_get_8bits(struct huffman_input_stream *is) {
unsigned long one_byte;
if (is->bits <= 8) {
is->bit_buf |= *(unsigned short *)is->in_buf << is->bits;
is->in_buf += sizeof(unsigned short);
is->bits += 16;
}
one_byte = (is->bit_buf & 0xFF);
is->bit_buf >>= 8;
is->bits -= 8;
return one_byte;
}
/* Gets 7 bits from the stream. */
static unsigned long libmpq_huff_get_7bits(struct huffman_input_stream *is) {
if (is->bits <= 7) {
is->bit_buf |= *(unsigned short *)is->in_buf << is->bits;
is->in_buf += sizeof(unsigned short);
is->bits += 16;
}
/* Get 7 bits from input stream. */
return (is->bit_buf & 0x7F);
}
/* Gets one bit from input stream. */
unsigned long libmpq_huff_get_bit(struct huffman_input_stream *is) {
unsigned long bit = (is->bit_buf & 1);
is->bit_buf >>= 1;
if (--is->bits == 0) {
is->bit_buf = *(unsigned long *)is->in_buf;
is->in_buf += sizeof(unsigned long);
is->bits = 32;
}
return bit;
}
static struct huffman_tree_item *libmpq_huff_call1500E740(struct huffman_tree *ht, unsigned int value) {
struct huffman_tree_item *p_item1 = ht->item3058; /* EDX */
struct huffman_tree_item *p_item2; /* EAX */
struct huffman_tree_item *p_next;
struct huffman_tree_item *p_prev;
struct huffman_tree_item **pp_item;
if (PTR_INT(p_item1) <= 0 || (p_item2 = p_item1) == NULL) {
if((p_item2 = &ht->items0008[ht->items++]) != NULL) {
p_item1 = p_item2;
} else {
p_item1 = ht->first;
}
} else {
p_item1 = p_item2;
}
p_next = p_item1->next;
if (p_next != NULL) {
p_prev = p_item1->prev;
if (PTR_INT(p_prev) <= 0) {
p_prev = PTR_NOT(p_prev);
} else {
p_prev += (p_item1 - p_item1->next->prev);
}
p_prev->next = p_next;
p_next->prev = p_prev;
p_item1->next = NULL;
p_item1->prev = NULL;
}
pp_item = &ht->first; /* ESI */
if (value > 1) {
/* ECX = ht->first->next; */
p_item1->next = *pp_item;
p_item1->prev = (*pp_item)->prev;
(*pp_item)->prev = p_item2;
*pp_item = p_item1;
p_item2->parent = NULL;
p_item2->child = NULL;
} else {
p_item1->next = (struct huffman_tree_item *)pp_item;
p_item1->prev = pp_item[1];
/* EDI = ht->item305C; */
p_prev = pp_item[1]; /* ECX */
if (p_prev <= 0) {
p_prev = PTR_NOT(p_prev);
p_prev->next = p_item1;
p_prev->prev = p_item2;
p_item2->parent = NULL;
p_item2->child = NULL;
} else {
if (PTR_INT(ht->item305C) < 0) {
p_prev += (struct huffman_tree_item *)pp_item - (*pp_item)->prev;
} else {
p_prev += PTR_INT(ht->item305C);
}
p_prev->next = p_item1;
pp_item[1] = p_item2;
p_item2->parent = NULL;
p_item2->child = NULL;
}
}
return p_item2;
}
static void libmpq_huff_call1500E820(struct huffman_tree *ht, struct huffman_tree_item *p_item) {
struct huffman_tree_item *p_item1; /* EDI */
struct huffman_tree_item *p_item2 = NULL; /* EAX */
struct huffman_tree_item *p_item3; /* EDX */
struct huffman_tree_item *p_prev; /* EBX */
for (; p_item != NULL; p_item = p_item->parent) {
p_item->byte_value++;
for (p_item1 = p_item; ; p_item1 = p_prev) {
p_prev = p_item1->prev;
if (PTR_INT(p_prev) <= 0) {
p_prev = NULL;
break;
}
if (p_prev->byte_value >= p_item->byte_value) {
break;
}
}
if (p_item1 == p_item) {
continue;
}
if (p_item1->next != NULL) {
p_item2 = libmpq_huff_get_prev_item(p_item1, -1);
p_item2->next = p_item1->next;
p_item1->next->prev = p_item1->prev;
p_item1->next = NULL;
p_item1->prev = NULL;
}
p_item2 = p_item->next;
p_item1->next = p_item2;
p_item1->prev = p_item2->prev;
p_item2->prev = p_item1;
p_item->next = p_item1;
if ((p_item2 = p_item1) != NULL) {
p_item2 = libmpq_huff_get_prev_item(p_item, -1);
p_item2->next = p_item->next;
p_item->next->prev = p_item->prev;
p_item->next = NULL;
p_item->prev = NULL;
}
if (p_prev == NULL) {
p_prev = PTR_PTR(&ht->first);
}
p_item2 = p_prev->next;
p_item->next = p_item2;
p_item->prev = p_item2->prev;
p_item2->prev = p_item;
p_prev->next = p_item;
p_item3 = p_item1->parent->child;
p_item2 = p_item->parent;
if (p_item2->child == p_item) {
p_item2->child = p_item1;
}
if (p_item3 == p_item1) {
p_item1->parent->child = p_item;
}
p_item2 = p_item->parent;
p_item->parent = p_item1->parent;
p_item1->parent = p_item2;
ht->offs0004++;
}
}
int libmpq_huff_do_decompress(struct huffman_tree *ht, struct huffman_input_stream *is, unsigned char *out_buf, unsigned int out_length) {
unsigned int n8bits; /* 8 bits loaded from input stream */
unsigned int n7bits; /* 7 bits loaded from input stream */
unsigned int found; /* Thats needed to replace the goto stuff from original source :) */
unsigned int dcmp_byte = 0;
unsigned long bit_count;
struct huffman_decompress *qd;
unsigned int has_qd; /* Can we use quick decompression? */
struct huffman_tree_item *p_item1;
struct huffman_tree_item *p_item2;
unsigned char *out_pos = out_buf;
/* Test the output length. Must not be non zero. */
if (out_length == 0) {
return 0;
}
/* Get the compression type from the input stream. */
n8bits = libmpq_huff_get_8bits(is);
/* Build the Huffman tree */
libmpq_huff_build_tree(ht, n8bits);
ht->cmp0 = (n8bits == 0) ? TRUE : FALSE;
for(;;) {
n7bits = libmpq_huff_get_7bits(is); /* Get 7 bits from input stream */
/*
* Try to use quick decompression. Check huffman_decompress array for corresponding item.
* If found, use the result byte instead.
*/
qd = &ht->qd3474[n7bits];
/* If there is a quick-pass possible (ebx) */
has_qd = (qd->offs00 >= ht->offs0004) ? TRUE : FALSE;
/* If we can use quick decompress, use it. */
if (has_qd) {
found = 0;
if (qd->bits > 7) {
is->bit_buf >>= 7;
is->bits -= 7;
p_item1 = qd->p_item;
found = 1;
}
if (found == 0) {
is->bit_buf >>= qd->bits;
is->bits -= qd->bits;
dcmp_byte = qd->dcmp_byte;
}
} else {
found = 1;
p_item1 = ht->first->next->prev;
if (PTR_INT(p_item1) <= 0) {
p_item1 = NULL;
}
}
if (found == 1) {
bit_count = 0;
p_item2 = NULL;
do {
p_item1 = p_item1->child; /* Move down by one level */
if (libmpq_huff_get_bit(is)) { /* If current bit is set, move to previous */
p_item1 = p_item1->prev;
}
if (++bit_count == 7) { /* If we are at 7th bit, save current huffman tree item. */
p_item2 = p_item1;
}
} while (p_item1->child != NULL); /* Walk until tree has no deeper level */
if (has_qd == FALSE) {
if (bit_count > 7) {
qd->offs00 = ht->offs0004;
qd->bits = bit_count;
qd->p_item = p_item2;
} else {
unsigned long index = n7bits & (0xFFFFFFFF >> (32 - bit_count));
unsigned long add = (1 << bit_count);
for (qd = &ht->qd3474[index]; index <= 0x7F; index += add, qd += add) {
qd->offs00 = ht->offs0004;
qd->bits = bit_count;
qd->dcmp_byte = p_item1->dcmp_byte;
}
}
}
dcmp_byte = p_item1->dcmp_byte;
}
if (dcmp_byte == 0x101) { /* Huffman tree needs to be modified */
n8bits = libmpq_huff_get_8bits(is);
p_item1 = (ht->last <= 0) ? NULL : ht->last;
p_item2 = libmpq_huff_call1500E740(ht, 1);
p_item2->parent = p_item1;
p_item2->dcmp_byte = p_item1->dcmp_byte;
p_item2->byte_value = p_item1->byte_value;
ht->items306C[p_item2->dcmp_byte] = p_item2;
p_item2 = libmpq_huff_call1500E740(ht, 1);
p_item2->parent = p_item1;
p_item2->dcmp_byte = n8bits;
p_item2->byte_value = 0;
ht->items306C[p_item2->dcmp_byte] = p_item2;
p_item1->child = p_item2;
libmpq_huff_call1500E820(ht, p_item2);
if (ht->cmp0 == 0) {
libmpq_huff_call1500E820(ht, ht->items306C[n8bits]);
}
dcmp_byte = n8bits;
}
if (dcmp_byte == 0x100) {
break;
}
*out_pos++ = (unsigned char)dcmp_byte;
if (--out_length == 0) {
break;
}
if (ht->cmp0) {
libmpq_huff_call1500E820(ht, ht->items306C[dcmp_byte]);
}
}
return (out_pos - out_buf);
}
int libmpq_huff_init_tree(struct huffman_tree *ht, struct huffman_tree_item *hi, unsigned int cmp) {
int count;
/* Clear links for all the items in the tree */
for (hi = ht->items0008, count = 0x203; count != 0; hi++, count--) {
hi->next = hi->prev = NULL;
}
ht->item3050 = NULL;
ht->item3054 = PTR_PTR(&ht->item3054);
ht->item3058 = PTR_NOT(ht->item3054);
ht->item305C = NULL;
ht->first = PTR_PTR(&ht->first);
ht->last = PTR_NOT(ht->first);
ht->offs0004 = 1;
ht->items = 0;
/* Clear all huffman_decompress items. Do this only if preparing for decompression */
if (cmp == LIBMPQ_HUFF_DECOMPRESS) {
for (count = 0; count < sizeof(ht->qd3474) / sizeof(struct huffman_decompress); count++) {
ht->qd3474[count].offs00 = 0;
}
}
return 0;
}

View file

@ -0,0 +1,105 @@
/*
* huffman.h -- structures used for huffman compression.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of huffman.h included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
* ShadowFlare <BlakFlare@hotmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _HUFFMAN_H
#define _HUFFMAN_H
#define PTR_NOT(ptr) (struct huffman_tree_item *)(~(unsigned long)(ptr))
#define PTR_PTR(ptr) ((struct huffman_tree_item *)(ptr))
#define PTR_INT(ptr) (long)(ptr)
#define INSERT_ITEM 1
#define SWITCH_ITEMS 2 /* Switch the item1 and item2 */
/*
* Input stream for Huffmann decompression
*/
struct huffman_input_stream {
unsigned char *in_buf; /* 00 - Input data */
unsigned long bit_buf; /* 04 - Input bit buffer */
unsigned int bits; /* 08 - Number of bits remaining in 'byte' */
};
/*
* Huffmann tree item.
*/
struct huffman_tree_item {
struct huffman_tree_item *next; /* 00 - Pointer to next huffman_tree_item */
struct huffman_tree_item *prev; /* 04 - Pointer to prev huffman_tree_item (< 0 if none) */
unsigned long dcmp_byte; /* 08 - Index of this item in item pointer array, decompressed byte value */
unsigned long byte_value; /* 0C - Some byte value */
struct huffman_tree_item *parent; /* 10 - Pointer to parent huffman_tree_item (NULL if none) */
struct huffman_tree_item *child; /* 14 - Pointer to child huffman_tree_item */
};
/*
* Structure used for quick decompress. The 'bits' contains
* number of bits and dcmp_byte contains result decompressed byte
* value. After each walk through Huffman tree are filled all entries
* which are multiplies of number of bits loaded from input stream.
* These entries contain number of bits and result value. At the next
* 7 bits is tested this structure first. If corresponding entry found,
* decompression routine will not walk through Huffman tree and
* directly stores output byte to output stream.
*/
struct huffman_decompress {
unsigned long offs00; /* 00 - 1 if resolved */
unsigned long bits; /* 04 - Bit count */
union {
unsigned long dcmp_byte; /* 08 - Byte value for decompress (if bitCount <= 7) */
struct huffman_tree_item *p_item; /* 08 - THTreeItem (if number of bits is greater than 7 */
};
};
/*
* Structure for Huffman tree.
*/
struct huffman_tree {
unsigned long cmp0; /* 0000 - 1 if compression type 0 */
unsigned long offs0004; /* 0004 - Some flag */
struct huffman_tree_item items0008[0x203]; /* 0008 - huffman tree items */
/* Sometimes used as huffman tree item */
struct huffman_tree_item *item3050; /* 3050 - Always NULL (?) */
struct huffman_tree_item *item3054; /* 3054 - Pointer to huffman_tree_item */
struct huffman_tree_item *item3058; /* 3058 - Pointer to huffman_tree_item (< 0 if invalid) */
/* Sometimes used as huffman tree item */
struct huffman_tree_item *item305C; /* 305C - Usually NULL */
struct huffman_tree_item *first; /* 3060 - Pointer to top (first) Huffman tree item */
struct huffman_tree_item *last; /* 3064 - Pointer to bottom (last) Huffman tree item (< 0 if invalid) */
unsigned long items; /* 3068 - Number of used huffman tree items */
struct huffman_tree_item *items306C[0x102]; /* 306C - huffman_tree_item pointer array */
struct huffman_decompress qd3474[0x80]; /* 3474 - Array for quick decompression */
//unsigned char table1502A630[]; /* Some table to make struct size flexible */
};
int libmpq_huff_init_tree(struct huffman_tree *ht, struct huffman_tree_item *hi, unsigned int cmp);
int libmpq_huff_do_decompress(struct huffman_tree *ht, struct huffman_input_stream *is, unsigned char *out_buf, unsigned int out_length);
#endif /* _HUFFMAN_H */

View file

@ -0,0 +1,626 @@
/*
* mpq.c -- functions for developers using libmpq.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: mpq.c,v 1.6 2004/02/12 00:49:00 mbroemme Exp $
*/
#define _CRT_SECURE_NO_DEPRECATE
#include <stdlib.h>
#include <sys/stat.h>
//#include <unistd.h>
//#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include "mpq.h"
#include "common.h"
/*
* This function returns version information.
* format: MAJOR.MINOR.PATCH
*/
char *libmpq_version() {
static char version[10];
sprintf(version, "%i.%i.%i", LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
return version;
}
/*
* This function reads a file and verify if it is a legit MPQ archive
* or not. Then it fills the mpq_header structure and reads the hash
* table.
*/
int libmpq_archive_open(mpq_archive *mpq_a, unsigned char *mpq_filename) {
int fd = 0;
int rb = 0;
int ncnt = FALSE;
struct stat fileinfo;
/* allocate memory */
mpq_a->mpq_l = (mpq_list *)malloc(sizeof(mpq_list));
memset(mpq_a->mpq_l, 0, sizeof(mpq_list));
mpq_a->header = (mpq_header *)malloc(sizeof(mpq_header));
memset(mpq_a->header, 0, sizeof(mpq_header));
/* Check if file exists and is readable */
fd = _open((char *)mpq_filename, O_RDONLY | O_BINARY);
if (fd == LIBMPQ_EFILE) {
return LIBMPQ_EFILE;
}
/* fill the structures with informations */
strcpy((char *)mpq_a->filename, (char *)mpq_filename);
libmpq_init_buffer(mpq_a);
mpq_a->fd = fd;
mpq_a->header->id = 0;
mpq_a->maxblockindex = 0;
mpq_a->mpq_l->mpq_files = NULL;
mpq_a->mpqpos = 0; //k
while (!ncnt) {
mpq_a->header->id = 0;
#ifdef WIN32
_lseeki64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
#else
lseek64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
#endif
rb = _read(mpq_a->fd, mpq_a->header, sizeof(mpq_header));
/* if different number of bytes read, break the loop */
if (rb != sizeof(mpq_header)) {
return LIBMPQ_EFILE_FORMAT;
}
/* special offset for protected MPQs */
if (mpq_a->header->offset == LIBMPQ_HEADER_W3M) {
mpq_a->flags |= LIBMPQ_FLAG_PROTECTED;
mpq_a->header->offset = sizeof(mpq_header);
}
/* if valid signature has been found, break the loop */
if (mpq_a->header->id == LIBMPQ_ID_MPQ) {
ncnt = true;
}
/*if (mpq_a->header->id == LIBMPQ_ID_MPQ &&
mpq_a->header->offset == sizeof(mpq_header) &&
mpq_a->header->hashtablepos < mpq_a->header->archivesize &&
mpq_a->header->blocktablepos < mpq_a->header->archivesize) {
ncnt = TRUE;
}*/
/* move to the next possible offset */
if (!ncnt) {
mpq_a->mpqpos += 0x200;
}
}
/* get the right positions of the hash table and the block table. */
mpq_a->blocksize = (0x200 << mpq_a->header->blocksize);
fstat(mpq_a->fd, &fileinfo);
/* Normal MPQs must have position of */
/*if (mpq_a->header->hashtablepos + mpq_a->mpqpos < fileinfo.st_size &&
mpq_a->header->blocktablepos + mpq_a->mpqpos < fileinfo.st_size) {
mpq_a->header->hashtablepos += mpq_a->mpqpos;
mpq_a->header->blocktablepos += mpq_a->mpqpos;
} else {
return LIBMPQ_EFILE_FORMAT;
}*/
/* Try to read and decrypt the hashtable */
if (libmpq_read_hashtable(mpq_a) != 0) {
return LIBMPQ_EHASHTABLE;
}
/* Try to read and decrypt the blocktable */
if (libmpq_read_blocktable(mpq_a) != 0) {
return LIBMPQ_EBLOCKTABLE;
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function closes the file descriptor opened by
* mpq_open_archive(); and frees the decryption buffer.
*/
int libmpq_archive_close(mpq_archive *mpq_a) {
memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
/* free the allocated memory. */
free(mpq_a->header);
free(mpq_a->mpq_l);
/* Check if file descriptor is valid. */
if ((_close(mpq_a->fd)) == LIBMPQ_EFILE) {
return LIBMPQ_EFILE;
}
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function returns the value for the given infotype.
* If an error occurs something < 0 is returned.
*/
int libmpq_archive_info(mpq_archive *mpq_a, unsigned int infotype) {
unsigned int filecount = 0;
unsigned int fsize = 0;
unsigned int csize = 0;
mpq_block *mpq_b_end = mpq_a->blocktable + mpq_a->header->blocktablesize;
mpq_block *mpq_b = NULL;
switch (infotype) {
case LIBMPQ_MPQ_ARCHIVE_SIZE:
return mpq_a->header->archivesize;
case LIBMPQ_MPQ_HASHTABLE_SIZE:
return mpq_a->header->hashtablesize;
case LIBMPQ_MPQ_BLOCKTABLE_SIZE:
return mpq_a->header->blocktablesize;
case LIBMPQ_MPQ_BLOCKSIZE:
return mpq_a->blocksize;
case LIBMPQ_MPQ_NUMFILES:
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
filecount++;
}
return filecount;
case LIBMPQ_MPQ_COMPRESSED_SIZE:
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
csize += mpq_b->csize;
}
return csize;
case LIBMPQ_MPQ_UNCOMPRESSED_SIZE:
for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
fsize += mpq_b->fsize;
}
return fsize;
default:
return LIBMPQ_TOOLS_SUCCESS;
}
}
/*
* This function returns some useful file information.
*/
int libmpq_file_info(mpq_archive *mpq_a, unsigned int infotype, const int number) {
int blockindex = number; //-1;
int i = 0;
mpq_block *mpq_b = NULL;
mpq_hash *mpq_h = NULL;
/* check if given number is not out of range */
if (number < 1 || number > mpq_a->header->blocktablesize) {
return LIBMPQ_EINV_RANGE;
}
/* search for correct hashtable */
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
blockindex = (mpq_a->hashtable[i]).blockindex;
mpq_h = &(mpq_a->hashtable[i]);
break;
}
}*/
/* check if file was found */
/*if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
return LIBMPQ_EFILE_NOT_FOUND;
}*/
/* check if sizes are correct */
mpq_b = mpq_a->blocktable + blockindex;
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
return LIBMPQ_EFILE_CORRUPT;
}
/* check if file exists */
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
return LIBMPQ_EFILE_NOT_FOUND;
}
switch (infotype) {
case LIBMPQ_FILE_COMPRESSED_SIZE:
return mpq_b->csize;
case LIBMPQ_FILE_UNCOMPRESSED_SIZE:
return mpq_b->fsize;
case LIBMPQ_FILE_COMPRESSION_TYPE:
if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
return LIBMPQ_FILE_COMPRESS_PKWARE;
}
if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
return LIBMPQ_FILE_COMPRESS_MULTI;
}
default:
return LIBMPQ_TOOLS_SUCCESS;
}
}
/*
* This function searches the listfile for the filename.
* On success it returns the filename, otherwiese a name
* like file000001.xxx and if number is out of range it
* returns NULL.
*/
char *libmpq_file_name(mpq_archive *mpq_a, const int number) {
static char tempfile[PATH_MAX];
/* check if we are in the range of available files. */
if (number > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || number < 1) {
return NULL;
}
/* this is safe because we built a fallback filelist, if something was wrong. */
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[number - 1], number);
return tempfile;
}
/*
* This function returns the number to the given
* filename.
*/
int libmpq_file_number(mpq_archive *mpq_a, const char *name) {
int i;
char tempfile[PATH_MAX];
for (i = 0; mpq_a->mpq_l->mpq_files[i]; i++) {
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[i], i + 1);
if (strncmp(tempfile, name, strlen(name)) == 0) {
/* if file found return the number */
return i + 1;
}
}
/* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
return LIBMPQ_EFILE_NOT_FOUND;
}
/*
* This function verifies if a given file (by number
* or name) is in the opened mpq archive. On success
* it returns 0, otherwise LIBMPQ_EFILE_NOT_FOUND.
*/
int libmpq_file_check(mpq_archive *mpq_a, void *file, int type) {
int found = 0;
int i;
char tempfile[PATH_MAX];
switch (type) {
case LIBMPQ_FILE_TYPE_INT:
/* check if we are in the range of available files. */
if (*(int *)file > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || *(int *)file < 1) {
return LIBMPQ_EFILE_NOT_FOUND;
} else {
return LIBMPQ_TOOLS_SUCCESS;
}
case LIBMPQ_FILE_TYPE_CHAR:
for (i = 0; mpq_a->mpq_l->mpq_files[i]; i++) {
sprintf(tempfile, (char *)mpq_a->mpq_l->mpq_files[i], i);
if (strncmp(tempfile, (char *)file, strlen((char *)file)) == 0) {
/* if file found break */
found = 1;
break;
}
}
/* if a file was found return 0 */
if (found == 1) {
return LIBMPQ_TOOLS_SUCCESS;
} else {
return LIBMPQ_EFILE_NOT_FOUND;
}
default:
return LIBMPQ_TOOLS_SUCCESS;
}
}
/*
* This function extracts a file from a MPQ archive
* by the given number.
*/
int libmpq_file_extract(mpq_archive *mpq_a, const int number, const char *filename) {
int blockindex = number; //-1;
int fd = 0;
int i = 0;
char buffer[0x1000];
//char tempfile[PATH_MAX];
unsigned int transferred = 1;
mpq_file *mpq_f = NULL;
mpq_block *mpq_b = NULL;
mpq_hash *mpq_h = NULL;
/* if (number < 1 || number > mpq_a->header->blocktablesize) {
return LIBMPQ_EINV_RANGE;
}*/
/*
sprintf(tempfile, libmpq_file_name(mpq_a, number));
*/
/* check if mpq_f->filename could be written here. */
fd = _open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
if (fd == LIBMPQ_EFILE) {
return LIBMPQ_EFILE;
}
/* search for correct hashtable */
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
blockindex = (mpq_a->hashtable[i]).blockindex;
mpq_h = &(mpq_a->hashtable[i]);
break;
}
}*/
/* check if file was found */
if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
return LIBMPQ_EFILE_NOT_FOUND;
}
/* check if sizes are correct */
mpq_b = mpq_a->blocktable + blockindex;
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
return LIBMPQ_EFILE_CORRUPT;
}
/* check if file exists */
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
return LIBMPQ_EFILE_NOT_FOUND;
}
/* allocate memory for file structure */
mpq_f = (mpq_file *)malloc(sizeof(mpq_file));
if (!mpq_f) {
return LIBMPQ_EALLOCMEM;
}
/* initialize file structure */
memset(mpq_f, 0, sizeof(mpq_file));
mpq_f->fd = fd;
mpq_f->mpq_b = mpq_b;
mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
mpq_f->mpq_h = mpq_h;
mpq_f->accessed = FALSE;
mpq_f->blockposloaded = FALSE;
sprintf((char *)mpq_f->filename, filename);
/* allocate buffers for decompression. */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
/*
* Allocate buffer for block positions. At the begin of file are stored
* unsigned ints holding positions of each block relative from begin of
* file in the archive.
*/
if ((mpq_f->blockpos = (unsigned int *)malloc(sizeof(int) * mpq_f->nblocks + 1)) == NULL) {
return LIBMPQ_EALLOCMEM;
}
}
while (transferred > 0) {
transferred = libmpq_file_read_file(mpq_a, mpq_f, mpq_f->filepos, buffer, sizeof(buffer));
if (transferred == 0) {
break;
} else {
mpq_f->accessed = TRUE;
mpq_f->filepos += transferred;
}
transferred = _write(mpq_f->fd, buffer, transferred);
if (transferred == 0) {
break;
}
}
_close(fd);
/* freeing the file structure */
free(mpq_f);
return LIBMPQ_TOOLS_SUCCESS;
}
/*
* This function tries to get the filenames for the hashes. It uses
* an internal listfile database and gets the correct listfile from
* some specific archive informations.
*/
int libmpq_listfile_open(mpq_archive *mpq_a, char file[PATH_MAX]) {
FILE *fp;
//char **filelist;
int i = 0;
//int fl_count;
//int fl_size;
int fl_count_fb;
int fl_size_fb;
int result = LIBMPQ_TOOLS_SUCCESS;
struct stat statbuf;
/* get file status */
if (stat(file, &statbuf) < 0) {
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
}
/* check if file is a filename or directory */
/*if (S_ISDIR(statbuf.st_mode)) {
// allocate memory for the file list
filelist = (char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
fl_count = 0;
fl_size = LIBMPQ_CONF_FL_INCREMENT;
// check if it is a valid listfile
if (libmpq_detect_listfile_rec(file, &filelist, &fl_count, &fl_size)) {
filelist == NULL;
}
filelist[fl_count] = NULL;
// return if no listfile was found
if (filelist == NULL) {
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
}
for (i = 0; filelist[i]; i++) {
if ((fp = fopen(filelist[i], "r")) != NULL ) {
result = libmpq_read_listfile(mpq_a, fp);
fclose(fp);
}
}
// freeing the listfile struct
libmpq_free_listfile(filelist);
}*/
/* if file is a regular file use it */
//if (S_ISREG(statbuf.st_mode)) {
/* if specific listfile was forced. */
if ((fp = fopen(file, "r")) != NULL ) {
result = libmpq_read_listfile(mpq_a, fp);
fclose(fp);
} else {
result = LIBMPQ_CONF_EFILE_OPEN;
}
//}
/* if error occured we need to create a fallback filelist. */
if (mpq_a->mpq_l->mpq_files == NULL) {
/* allocate memory for the file list */
mpq_a->mpq_l->mpq_files = (unsigned char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
fl_count_fb = 0;
fl_size_fb = LIBMPQ_CONF_FL_INCREMENT;
for (i = 0; i < libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES); i++) {
/* set the next filelist entry to a copy of the file */
mpq_a->mpq_l->mpq_files[fl_count_fb++] = (unsigned char *)_strdup("file%06lu.xxx");
/* increase the array size */
if (fl_count_fb == fl_size_fb) {
mpq_a->mpq_l->mpq_files = (unsigned char **)realloc(mpq_a->mpq_l->mpq_files, (fl_size_fb + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
fl_size_fb += LIBMPQ_CONF_FL_INCREMENT;
}
}
mpq_a->mpq_l->mpq_files[fl_count_fb] = NULL;
/* if no error occurs and no listfile was assigned, we think there was no matching listfile. */
if (result == 0) {
result = LIBMPQ_CONF_EFILE_NOT_FOUND;
}
}
return result;
}
/*
* This function frees the allocated memory for the listfile.
*/
int libmpq_listfile_close(mpq_archive *mpq_a) {
int i = 0;
/* safety check if we really have a filelist. */
if (mpq_a->mpq_l->mpq_files != NULL) {
/* freeing the filelist */
while (mpq_a->mpq_l->mpq_files[i]) {
free(mpq_a->mpq_l->mpq_files[i++]);
}
free(mpq_a->mpq_l->mpq_files);
}
return 0;
}
int libmpq_file_getdata(mpq_archive *mpq_a, mpq_hash mpq_h, const int number, unsigned char *dest) {
int blockindex = number; //-1;
int i = 0;
mpq_file *mpq_f = NULL;
mpq_block *mpq_b = NULL;
int success = 0;
/*if (number < 1 || number > mpq_a->header->blocktablesize) {
return LIBMPQ_EINV_RANGE;
}*/
/* search for correct hashtable */
/*for (i = 0; i < mpq_a->header->hashtablesize; i++) {
if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
blockindex = (mpq_a->hashtable[i]).blockindex;
mpq_h = &(mpq_a->hashtable[i]);
break;
}
}*/
/* check if file was found */
if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
return LIBMPQ_EFILE_NOT_FOUND;
}
/* check if sizes are correct */
mpq_b = mpq_a->blocktable + blockindex;
if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
return LIBMPQ_EFILE_CORRUPT;
}
/* check if file exists */
if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
return LIBMPQ_EFILE_NOT_FOUND;
}
/* allocate memory for file structure */
mpq_f = (mpq_file*)malloc(sizeof(mpq_file));
if (!mpq_f) {
return LIBMPQ_EALLOCMEM;
}
/* initialize file structure */
memset(mpq_f, 0, sizeof(mpq_file));
mpq_f->mpq_b = mpq_b;
mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
mpq_f->mpq_h = &mpq_h;
mpq_f->accessed = FALSE;
mpq_f->blockposloaded = FALSE;
/* allocate buffers for decompression. */
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
/*
* Allocate buffer for block positions. At the begin of file are stored
* unsigned ints holding positions of each block relative from begin of
* file in the archive.
*/
if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * (mpq_f->nblocks + 1))) == NULL) {
return LIBMPQ_EALLOCMEM;
}
}
if(libmpq_file_read_file(mpq_a, mpq_f, 0, (char*)dest, mpq_b->fsize) == mpq_b->fsize)
success = 1;
if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
// Free buffer for block positions
free(mpq_f->blockpos);
}
/* freeing the file structure */
free(mpq_f);
return success?LIBMPQ_TOOLS_SUCCESS:LIBMPQ_EFILE_CORRUPT;
}

View file

@ -0,0 +1,225 @@
/*
* mpq.h -- some default types and defines.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of StormLib.h and
* StormPort.h included in stormlib. The C++ version belongs to
* the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
* Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: mpq.h,v 1.8 2004/02/12 00:45:50 mbroemme Exp $
*/
#ifndef _MPQ_H
#define _MPQ_H
#include <limits.h>
#ifndef PATH_MAX
#define PATH_MAX 260
#endif
#define LIBMPQ_MAJOR_VERSION 0 /* Major version number... maybe sometimes we reach version 1 :) */
#define LIBMPQ_MINOR_VERSION 3 /* Minor version number - increased only for small changes */
#define LIBMPQ_PATCH_VERSION 0 /* Patchlevel - changed on bugfixes etc... */
#define LIBMPQ_TOOLS_SUCCESS 0 /* return value for all functions which success */
#define LIBMPQ_TOOLS_BUFSIZE 0x500 /* buffer size for the decryption engine */
#define LIBMPQ_EFILE -1 /* error on file operation */
#define LIBMPQ_EFILE_FORMAT -2 /* bad file format */
#define LIBMPQ_EFILE_CORRUPT -3 /* file corrupt */
#define LIBMPQ_EFILE_NOT_FOUND -4 /* file in archive not found */
#define LIBMPQ_EFILE_READ -5 /* Read error in archive */
#define LIBMPQ_EALLOCMEM -6 /* maybe not enough memory? :) */
#define LIBMPQ_EFREEMEM -7 /* can not free memory */
#define LIBMPQ_EINV_RANGE -8 /* Given filenumber is out of range */
#define LIBMPQ_EHASHTABLE -9 /* error in reading hashtable */
#define LIBMPQ_EBLOCKTABLE -10 /* error in reading blocktable */
#define LIBMPQ_ID_MPQ 0x1A51504D /* MPQ archive header ID ('MPQ\x1A') */
#define LIBMPQ_HEADER_W3M 0x6D9E4B86 /* special value used by W3M Map Protector */
#define LIBMPQ_FLAG_PROTECTED 0x00000002 /* Set on protected MPQs (like W3M maps) */
#define LIBMPQ_HASH_ENTRY_DELETED 0xFFFFFFFE /* Block index for deleted hash entry */
#define LIBMPQ_FILE_COMPRESS_PKWARE 0x00000100 /* Compression made by PKWARE Data Compression Library */
#define LIBMPQ_FILE_COMPRESS_MULTI 0x00000200 /* Multiple compressions */
#define LIBMPQ_FILE_COMPRESSED 0x0000FF00 /* File is compressed */
#define LIBMPQ_FILE_EXISTS 0x80000000 /* Set if file exists, reset when the file was deleted */
#define LIBMPQ_FILE_ENCRYPTED 0x00010000 /* Indicates whether file is encrypted */
#define LIBMPQ_FILE_HAS_METADATA 0x04000000
#define LIBMPQ_FILE_COMPRESSED_SIZE 1 /* MPQ compressed filesize of given file */
#define LIBMPQ_FILE_UNCOMPRESSED_SIZE 2 /* MPQ uncompressed filesize of given file */
#define LIBMPQ_FILE_COMPRESSION_TYPE 3 /* MPQ compression type of given file */
#define LIBMPQ_FILE_TYPE_INT 4 /* file is given by number */
#define LIBMPQ_FILE_TYPE_CHAR 5 /* file is given by name */
#define LIBMPQ_MPQ_ARCHIVE_SIZE 1 /* MPQ archive size */
#define LIBMPQ_MPQ_HASHTABLE_SIZE 2 /* MPQ archive hashtable size */
#define LIBMPQ_MPQ_BLOCKTABLE_SIZE 3 /* MPQ archive blocktable size */
#define LIBMPQ_MPQ_BLOCKSIZE 4 /* MPQ archive blocksize */
#define LIBMPQ_MPQ_NUMFILES 5 /* Number of files in the MPQ archive */
#define LIBMPQ_MPQ_COMPRESSED_SIZE 6 /* Compressed archive size */
#define LIBMPQ_MPQ_UNCOMPRESSED_SIZE 7 /* Uncompressed archive size */
#define LIBMPQ_HUFF_DECOMPRESS 0 /* Defines that we want to decompress using huffman trees. */
#define LIBMPQ_CONF_EFILE_OPEN -1 /* error if a specific listfile was forced and could not be opened. */
#define LIBMPQ_CONF_EFILE_CORRUPT -2 /* listfile seems to be corrupt */
#define LIBMPQ_CONF_EFILE_LIST_CORRUPT -3 /* listfile seems correct, but filelist is broken */
#define LIBMPQ_CONF_EFILE_NOT_FOUND -4 /* error if no matching listfile found */
#define LIBMPQ_CONF_EFILE_VERSION -5 /* libmpq version does not match required listfile version */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/*
#ifndef min
#define min(a, b) ((a < b) ? a : b)
#endif
*/
typedef unsigned int mpq_buffer[LIBMPQ_TOOLS_BUFSIZE];
typedef int (*DECOMPRESS)(char *, int *, char *, int);
typedef struct {
unsigned long mask; /* Decompression bit */
DECOMPRESS decompress; /* Decompression function */
} decompress_table;
/* MPQ file header */
typedef struct {
unsigned int id; /* The 0x1A51504D ('MPQ\x1A') signature */
unsigned int offset; /* Offset of the first file (Relative to MPQ start) */
unsigned int archivesize; /* Size of MPQ archive */
unsigned short offsetsc; /* 0000 for SC and BW */
unsigned short blocksize; /* Size of file block is (0x200 << blockSize) */
unsigned int hashtablepos; /* File position of hashTable */
unsigned int blocktablepos; /* File position of blockTable. Each entry has 16 bytes */
unsigned int hashtablesize; /* Number of entries in hash table */
unsigned int blocktablesize; /* Number of entries in the block table */
} mpq_header;
//} __attribute__ ((packed)) mpq_header;
/* Hash entry. All files in the archive are searched by their hashes. */
typedef struct {
unsigned int name1; /* The first two unsigned ints */
unsigned int name2; /* are the encrypted file name */
unsigned int locale; /* Locale information. */
unsigned int blockindex; /* Index to file description block */
} mpq_hash;
/* File description block contains informations about the file */
typedef struct {
unsigned int filepos; /* Block file starting position in the archive */
unsigned int csize; /* Compressed file size */
unsigned int fsize; /* Uncompressed file size */
unsigned int flags; /* Flags */
} mpq_block;
/* File handle structure used since Diablo 1.00 (0x38 bytes) */
typedef struct {
unsigned char filename[PATH_MAX]; /* filename of the actual file in the archive */
int fd; /* File handle */
unsigned int seed; /* Seed used for file decrypt */
unsigned int filepos; /* Current file position */
unsigned int offset;
unsigned int nblocks; /* Number of blocks in the file (incl. the last noncomplete one) */
unsigned int *blockpos; /* Position of each file block (only for compressed files) */
int blockposloaded; /* TRUE if block positions loaded */
unsigned int offset2; /* (Number of bytes somewhere ?) */
mpq_hash *mpq_h; /* Hash table entry */
mpq_block *mpq_b; /* File block pointer */
/* Non-Storm.dll members */
unsigned int accessed; /* Was something from the file already read? */
} mpq_file;
/* List handle structure */
typedef struct {
unsigned char mpq_version[10]; /* libmpq version required by the listfile */
unsigned char mpq_name[PATH_MAX]; /* mpq archive name without full path */
unsigned char mpq_type[20]; /* mpq archive type */
unsigned char mpq_game[40]; /* blizzard title the file matches */
unsigned char mpq_game_version[10]; /* game version */
unsigned char **mpq_files; /* filelist */
} mpq_list;
/* Archive handle structure used since Diablo 1.00 */
typedef struct {
unsigned char filename[PATH_MAX]; /* Opened archive file name */
int fd; /* File handle */
unsigned int blockpos; /* Position of loaded block in the file */
unsigned int blocksize; /* Size of file block */
unsigned char *blockbuf; /* Buffer (cache) for file block */
unsigned int bufpos; /* Position in block buffer */
unsigned int mpqpos; /* MPQ archive position in the file */
unsigned int filepos; /* Current file pointer */
unsigned int openfiles; /* Number of open files + 1 */
mpq_buffer buf; /* MPQ buffer */
mpq_header *header; /* MPQ file header */
mpq_hash *hashtable; /* Hash table */
mpq_block *blocktable; /* Block table */
/* Non-Storm.dll members */
mpq_list *mpq_l; /* Handle to file list from database */
unsigned int flags; /* See LIBMPQ_TOOLS_FLAG_XXXXX */
unsigned int maxblockindex; /* The highest block table entry */
} mpq_archive;
extern char *libmpq_version();
extern int libmpq_archive_open(mpq_archive *mpq_a, unsigned char *mpq_filename);
extern int libmpq_archive_close(mpq_archive *mpq_a);
extern int libmpq_archive_info(mpq_archive *mpq_a, unsigned int infotype);
//extern int libmpq_file_extract(mpq_archive *mpq_a, const int number);
extern int libmpq_file_info(mpq_archive *mpq_a, unsigned int infotype, const int number);
extern char *libmpq_file_name(mpq_archive *mpq_a, const int number);
extern int libmpq_file_number(mpq_archive *mpq_a, const char *name);
extern int libmpq_file_check(mpq_archive *mpq_a, void *file, int type);
extern int libmpq_listfile_open(mpq_archive *mpq_a, char file[PATH_MAX]);
extern int libmpq_listfile_close(mpq_archive *mpq_a);
extern int libmpq_pkzip_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
extern int libmpq_zlib_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
extern int libmpq_huff_decompress(char *out_buf, int *out_length, char *in_buf, int in_length);
extern int libmpq_wave_decompress_stereo(char *out_buf, int *out_length, char *in_buf, int in_length);
extern int libmpq_wave_decompress_mono(char *out_buf, int *out_length, char *in_buf, int in_length);
extern int libmpq_multi_decompress(char *out_buf, int *pout_length, char *in_buf, int in_length);
static decompress_table dcmp_table[] = {
{0x08, libmpq_pkzip_decompress}, /* Decompression with Pkware Data Compression Library */
{0x02, libmpq_zlib_decompress}, /* Decompression with the "zlib" library */
{0x01, libmpq_huff_decompress}, /* Huffmann decompression */
{0x80, libmpq_wave_decompress_stereo}, /* WAVE decompression for stereo waves */
{0x40, libmpq_wave_decompress_mono} /* WAVE decompression for mono waves */
};
int libmpq_file_extract(mpq_archive *mpq_a, const int number, const char *filename);
int libmpq_file_getdata(mpq_archive *mpq_a, mpq_hash mpq_h, const int number, unsigned char *dest);
#endif /* _MPQ_H */

View file

@ -0,0 +1,294 @@
/*
* parser.c -- functions used to parse list or config file.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: parser.c,v 1.5 2004/02/12 00:47:53 mbroemme Exp $
*/
#define _CRT_SECURE_NO_DEPRECATE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mpq.h"
#include "common.h"
#include <ctype.h>
/*
* This function deletes the specified characters, but leaves
* escape sequences unaffected. This means that " would be
* deleted but \" would not.
*/
char *libmpq_conf_delete_char(char *buf, char *chars) {
static char *temp;
char ch;
temp = buf;
/* strip out special chars like " */
while (temp = strpbrk(temp, chars)) {
ch = temp[0];
memmove(&temp[0], &temp[1], strlen(temp));
if (ch == '\\') {
temp++;
}
}
return buf;
}
/*
* This function parses a line for the value to the given option. It
* return 1 on success and the byte array or 0 and null.
*/
int libmpq_conf_parse_line(char *line, char *search_value, char *return_value, int size) {
int level = 0;
int found = 0;
int i = 0;
int pos = 0;
/* search value */
while (*(++line)) {
/* check for spaces */
if (!isspace(*line) && level == 1) {
/* we found our value so break */
found = 1;
break;
}
/* check for '=' so the value follows as next parameter */
if (*line == '=' && level == 0) {
level = 1;
}
}
/* now search for comment in this line */
for (i = 0; i < strlen(line); i++) {
if (line[i] == '#') {
pos = i - 1;
break;
}
}
/* now set end of byte array behind value, but only if comment was found */
if (pos != 0) {
for (i = pos; i >= 0; i--) {
if (line[i] != ' ' && line[i] != '\t') {
line[i + 1] = '\0';
break;
}
}
}
/* now check if line has trailing spaces */
for (i = strlen(line); i >= 0; i--) {
if (line[i] != ' ' && line[i] != '\t') {
line[i + 1] = '\0';
break;
}
}
/* now check if value is quoted with "" and if there is a char behind. */
for (i = strlen(line); i >= 0; i--) {
if (line[i] == '"') {
line[i + 1] = '\0';
break;
}
}
/* return the values */
strncpy(return_value, line, size);
return found;
}
/*
* This function returns the value for a given option in the
* listdb or config file. On success it returns 1, otherwise 0.
*/
int libmpq_conf_get_value(FILE *fp, char *search_value, void *return_value, int type, int size) {
char buf[LIBMPQ_CONF_BUFSIZE];
int found = 0;
int result = LIBMPQ_TOOLS_SUCCESS;
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
char *line;
buf[strlen(buf) - 1] = '\0';
/* skip whitespace */
for (line = buf; isspace(*line); line++) {
continue;
}
/* skip empty line */
if (line[0] == '\0') {
continue;
}
/* skip comments */
if (line[0] == '#') {
continue;
}
/* process the line */
//if (!strncasecmp(line, search_value, strlen(search_value))) {
if (!strcmp(line, search_value)) {
found = libmpq_conf_parse_line(line, search_value, line, LIBMPQ_CONF_BUFSIZE);
if (found == 1) {
libmpq_conf_delete_char(line, "\"\\");
switch (type) {
case LIBMPQ_CONF_TYPE_INT:
/* if it is no valid number it is safe to return 0 */
*(int *)return_value = atoi(line);
break;
default:
strncpy((char *)return_value, line, size);
break;
}
/* value found, so rewind stream */
break;
}
}
}
/* if value was not found */
if (found == 0) {
switch (type) {
case LIBMPQ_CONF_TYPE_INT:
*(int *)return_value = 0;
result = LIBMPQ_CONF_EVALUE_NOT_FOUND;
break;
default:
strncpy((char *)return_value, "", size);
result = LIBMPQ_CONF_EVALUE_NOT_FOUND;
break;
}
}
fseek(fp, 0L, SEEK_SET);
return result;
}
/*
* This function returns a pointer to a byte array, with all values
* found in the config file. As second value it returns th number of
* entries in the byte array. On success it returns 1, otherwise 0.
*/
int libmpq_conf_get_array(FILE *fp, char *search_value, char ***filelist, int *entries) {
char buf[LIBMPQ_CONF_BUFSIZE];
char temp[LIBMPQ_CONF_BUFSIZE];
int level = 0;
int array_start = 0;
int array_end = 0;
int fl_count;
int fl_size;
int found = 0;
int i = 0;
*entries = 0;
/* allocate memory for the file list */
(*filelist) = (char **)malloc(LIBMPQ_CONF_FL_INCREMENT * sizeof(char *));
fl_count = 0;
fl_size = LIBMPQ_CONF_FL_INCREMENT;
while (fgets(buf, LIBMPQ_CONF_BUFSIZE, fp) != NULL) {
char *line;
buf[strlen(buf) - 1] = '\0';
/* skip whitespace */
for (line = buf; isspace(*line); line++) {
continue;
}
/* skip empty line */
if (line[0] == '\0') {
continue;
}
/* skip comments */
if (line[0] == '#') {
continue;
}
/* check for array end ) */
if (*line == ')') {
array_end = 1;
break;
}
/* process entries between () */
if (array_start == 1 && array_end == 0) {
/* add dummy option to use with libmpq_conf_parse_line() */
strncpy(temp, "MPQ_BUFFER = ", LIBMPQ_CONF_BUFSIZE);
strncat(temp, line, LIBMPQ_CONF_BUFSIZE);
found = libmpq_conf_parse_line(temp, "MPQ_BUFFER", temp, LIBMPQ_CONF_BUFSIZE);
if (found == 1) {
libmpq_conf_delete_char(temp, "\"\\");
/* set the next filelist entry to a copy of the file */
(*filelist)[fl_count++] = _strdup(temp);
/* increase the array size */
if (fl_count == fl_size) {
(*filelist) = (char **)realloc((*filelist), (fl_size + LIBMPQ_CONF_FL_INCREMENT) * sizeof(char *));
fl_size += LIBMPQ_CONF_FL_INCREMENT;
}
/* increase number of entries */
(*entries)++;
}
}
/* process the line and search array start */
//if (!strncasecmp(line, search_value, strlen(search_value))) {
if (!strcmp(line, search_value)) {
/* search value */
while (*(++line)) {
/* check for array start ( */
if (*line == '(' && level == 1) {
/* we found our value so break */
array_start = 1;
break;
}
/* check for '=' so the value follows as next parameter */
if (*line == '=' && level == 0) {
level = 1;
}
}
}
}
/* we got all files, so rewind stream */
fseek(fp, 0L, SEEK_SET);
(*filelist)[fl_count] = NULL;
return found;
}

View file

@ -0,0 +1,185 @@
/*
* wave.c -- this file contains decompression methods used by Storm.dll
* to decompress wave files.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of wave.cpp included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
* Tom Amigo <tomamigo@apexmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "wave.h"
/* Tables necessary dor decompression */
static unsigned long wave_table_1503f120[] = {
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006,
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007,
0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008
};
static unsigned long wave_table_1503f1a0[] = {
0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E,
0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F,
0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042,
0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F,
0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133,
0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292,
0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583,
0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0,
0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954,
0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B,
0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462,
0x00007FFF
};
/*
* Decompress a wave file, mono or stereo
*
* Offset: 1500F230
*/
int libmpq_wave_decompress(unsigned char *out_buf, int out_length, unsigned char *in_buf, int in_length, int channels) {
byte_and_short out;
byte_and_short in;
unsigned char *in_end = in_buf + in_length; /* End on input buffer */
unsigned long index;
long nr_array1[2];
long nr_array2[2];
int count = 0;
out.pb = out_buf;
in.pb = in_buf;
nr_array1[0] = 0x2C;
nr_array1[1] = 0x2C;
in.pw++;
/* 15007AD7 */
for (count = 0; count < channels; count++) {
long temp;
temp = *(short *)in.pw++;
nr_array2[count] = temp;
if (out_length < 2) {
return out.pb - out_buf;
}
*out.pw++ = (unsigned short)temp;
out_length -= 2;
}
index = channels - 1;
while (in.pb < in_end) {
unsigned char one_byte = *in.pb++;
if (channels == 2) {
index = (index == 0) ? 1 : 0;
}
/*
* Get one byte from input buffer
* 15007B25
*/
if (one_byte & 0x80) {
/* 15007B32 */
switch(one_byte & 0x7F) {
case 0: /* 15007B8E */
if (nr_array1[index] != 0) {
nr_array1[index]--;
}
if (out_length < 2) {
break;
}
*out.pw++ = (unsigned short)nr_array2[index];
out_length -= 2;
continue;
case 1: /* 15007B72 */
nr_array1[index] += 8; /* EBX also */
if (nr_array1[index] > 0x58) {
nr_array1[index] = 0x58;
}
if (channels == 2) {
index = (index == 0) ? 1 : 0;
}
continue;
case 2:
continue;
default:
nr_array1[index] -= 8;
if (nr_array1[index] < 0) {
nr_array1[index] = 0;
}
if (channels != 2) {
continue;
}
index = (index == 0) ? 1 : 0;
continue;
}
} else {
unsigned long temp1 = wave_table_1503f1a0[nr_array1[index]]; /* EDI */
unsigned long temp2 = temp1 >> in_buf[1]; /* ESI */
long temp3 = nr_array2[index]; /* ECX */
if (one_byte & 0x01) { /* EBX = one_byte */
temp2 += (temp1 >> 0);
}
if (one_byte & 0x02) {
temp2 += (temp1 >> 1);
}
if (one_byte & 0x04) {
temp2 += (temp1 >> 2);
}
if (one_byte & 0x08) {
temp2 += (temp1 >> 3);
}
if (one_byte & 0x10) {
temp2 += (temp1 >> 4);
}
if (one_byte & 0x20) {
temp2 += (temp1 >> 5);
}
if(one_byte & 0x40) {
temp3 -= temp2;
if (temp3 <= (long)0xFFFF8000) {
temp3 = (long)0xFFFF8000;
}
} else {
temp3 += temp2;
if (temp3 >= 0x7FFF) {
temp3 = 0x7FFF;
}
}
nr_array2[index] = temp3;
if (out_length < 2) {
break;
}
temp2 = nr_array1[index];
one_byte &= 0x1F;
*out.pw++ = (unsigned short)temp3;
out_length -= 2;
temp2 += wave_table_1503f120[one_byte];
nr_array1[index] = temp2;
if (nr_array1[index] < 0) {
nr_array1[index] = 0;
} else {
if (nr_array1[index] > 0x58) {
nr_array1[index] = 0x58;
}
}
}
}
return (out.pb - out_buf);
}

View file

@ -0,0 +1,37 @@
/*
* wave.h -- header file for WAVe unplode functions used by mpq-tools.
*
* Copyright (C) 2003 Maik Broemme <mbroemme@plusserver.de>
*
* This source was adepted from the C++ version of wave.h included
* in stormlib. The C++ version belongs to the following authors,
*
* Ladislav Zezula <ladik.zezula.net>
* Tom Amigo <tomamigo@apexmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _WAVE_H
#define _WAVE_H
typedef union {
unsigned short *pw;
unsigned char *pb;
} byte_and_short;
int libmpq_wave_decompress(unsigned char *out_buf, int out_length, unsigned char *in_buf, int in_length, int channels);
#endif /* _WAVE_H */

View file

@ -0,0 +1,323 @@
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2003 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#ifndef ZCONF_H
#define ZCONF_H
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
*/
#ifdef Z_PREFIX
# define deflateInit_ z_deflateInit_
# define deflate z_deflate
# define deflateEnd z_deflateEnd
# define inflateInit_ z_inflateInit_
# define inflate z_inflate
# define inflateEnd z_inflateEnd
# define deflateInit2_ z_deflateInit2_
# define deflateSetDictionary z_deflateSetDictionary
# define deflateCopy z_deflateCopy
# define deflateReset z_deflateReset
# define deflatePrime z_deflatePrime
# define deflateParams z_deflateParams
# define deflateBound z_deflateBound
# define inflateInit2_ z_inflateInit2_
# define inflateSetDictionary z_inflateSetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateCopy z_inflateCopy
# define inflateReset z_inflateReset
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# define uncompress z_uncompress
# define adler32 z_adler32
# define crc32 z_crc32
# define get_crc_table z_get_crc_table
# define Byte z_Byte
# define uInt z_uInt
# define uLong z_uLong
# define Bytef z_Bytef
# define charf z_charf
# define intf z_intf
# define uIntf z_uIntf
# define uLongf z_uLongf
# define voidpf z_voidpf
# define voidp z_voidp
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
# define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
# define WINDOWS
#endif
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
# ifndef SYS16BIT
# define SYS16BIT
# endif
# endif
#endif
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
*/
#ifdef SYS16BIT
# define MAXSEG_64K
#endif
#ifdef MSDOS
# define UNALIGNED_OK
#endif
#ifdef __STDC_VERSION__
# ifndef STDC
# define STDC
# endif
# if __STDC_VERSION__ >= 199901L
# ifndef STDC99
# define STDC99
# endif
# endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
# define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
# define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
# define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
# define STDC
#endif
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
# define STDC
#endif
#ifndef STDC
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
# define const /* note: need a more gentle solution here */
# endif
#endif
/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
# define NO_DUMMY_DECL
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
* created by gzip. (Files created by minigzip can still be extracted by
* gzip.)
*/
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
(1 << (windowBits+2)) + (1 << (memLevel+9))
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
* just define FAR to be empty.
*/
#ifdef SYS16BIT
# if defined(M_I86SM) || defined(M_I86MM)
/* MSC small or medium model */
# define SMALL_MEDIUM
# ifdef _MSC_VER
# define FAR _far
# else
# define FAR far
# endif
# endif
# if (defined(__SMALL__) || defined(__MEDIUM__))
/* Turbo C small or medium model */
# define SMALL_MEDIUM
# ifdef __BORLANDC__
# define FAR _far
# else
# define FAR far
# endif
# endif
#endif
#if defined(WINDOWS) || defined(WIN32)
/* If building or using zlib as a DLL, define ZLIB_DLL.
* This is not mandatory, but it offers a little performance increase.
*/
# ifdef ZLIB_DLL
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
# ifdef ZLIB_INTERNAL
# define ZEXTERN extern __declspec(dllexport)
# else
# define ZEXTERN extern __declspec(dllimport)
# endif
# endif
# endif /* ZLIB_DLL */
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif
#endif
#if defined (__BEOS__)
# ifdef ZLIB_DLL
# ifdef ZLIB_INTERNAL
# define ZEXPORT __declspec(dllexport)
# define ZEXPORTVA __declspec(dllexport)
# else
# define ZEXPORT __declspec(dllimport)
# define ZEXPORTVA __declspec(dllimport)
# endif
# endif
#endif
#ifndef ZEXTERN
# define ZEXTERN extern
#endif
#ifndef ZEXPORT
# define ZEXPORT
#endif
#ifndef ZEXPORTVA
# define ZEXPORTVA
#endif
#ifndef FAR
# define FAR
#endif
#if !defined(__MACTYPES__)
typedef unsigned char Byte; /* 8 bits */
#endif
typedef unsigned int uInt; /* 16 bits or more */
typedef unsigned long uLong; /* 32 bits or more */
#ifdef SMALL_MEDIUM
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
# define Bytef Byte FAR
#else
typedef Byte FAR Bytef;
#endif
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void const *voidpc;
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte const *voidpc;
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
# include <sys/types.h> /* for off_t */
# include <unistd.h> /* for SEEK_* and off_t */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# define z_off_t off_t
#endif
#ifndef SEEK_SET
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
# define z_off_t long
#endif
#if defined(__OS400__)
#define NO_vsnprintf
#endif
#if defined(__MVS__)
# define NO_vsnprintf
# ifdef FAR
# undef FAR
# endif
#endif
/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
# pragma map(deflateInit_,"DEIN")
# pragma map(deflateInit2_,"DEIN2")
# pragma map(deflateEnd,"DEEND")
# pragma map(deflateBound,"DEBND")
# pragma map(inflateInit_,"ININ")
# pragma map(inflateInit2_,"ININ2")
# pragma map(inflateEnd,"INEND")
# pragma map(inflateSync,"INSY")
# pragma map(inflateSetDictionary,"INSEDI")
# pragma map(compressBound,"CMBND")
# pragma map(inflate_table,"INTABL")
# pragma map(inflate_fast,"INFA")
# pragma map(inflate_copyright,"INCOPY")
#endif
#endif /* ZCONF_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,133 @@
#include "mpq_libmpq.h"
#include <deque>
ArchiveSet gOpenArchives;
MPQArchive::MPQArchive(const char* filename)
{
int result = libmpq_archive_open(&mpq_a, (unsigned char*)filename);
printf("Opening %s\n", filename);
if(result) {
switch(result) {
case LIBMPQ_EFILE : /* error on file operation */
printf("Error opening archive '%s': File operation Error\n", filename);
break;
case LIBMPQ_EFILE_FORMAT : /* bad file format */
printf("Error opening archive '%s': Bad file format\n", filename);
break;
case LIBMPQ_EFILE_CORRUPT : /* file corrupt */
printf("Error opening archive '%s': File corrupt\n", filename);
break;
case LIBMPQ_EFILE_NOT_FOUND : /* file in archive not found */
printf("Error opening archive '%s': File in archive not found\n", filename);
break;
case LIBMPQ_EFILE_READ : /* Read error in archive */
printf("Error opening archive '%s': Read error in archive\n", filename);
break;
case LIBMPQ_EALLOCMEM : /* maybe not enough memory? :) */
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
break;
case LIBMPQ_EFREEMEM : /* can not free memory */
printf("Error opening archive '%s': Cannot free memory\n", filename);
break;
case LIBMPQ_EINV_RANGE : /* Given filenumber is out of range */
printf("Error opening archive '%s': Given filenumber is out of range\n", filename);
break;
case LIBMPQ_EHASHTABLE : /* error in reading hashtable */
printf("Error opening archive '%s': Error in reading hashtable\n", filename);
break;
case LIBMPQ_EBLOCKTABLE : /* error in reading blocktable */
printf("Error opening archive '%s': Error in reading blocktable\n", filename);
break;
default:
printf("Error opening archive '%s': Unknown error\n", filename);
break;
}
return;
}
gOpenArchives.push_front(this);
}
void MPQArchive::close()
{
//gOpenArchives.erase(erase(&mpq_a);
libmpq_archive_close(&mpq_a);
}
MPQFile::MPQFile(const char* filename):
eof(false),
buffer(0),
pointer(0),
size(0)
{
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
{
mpq_archive &mpq_a = (*i)->mpq_a;
mpq_hash hash = (*i)->GetHashEntry(filename);
uint32 blockindex = hash.blockindex;
if ((blockindex == 0xFFFFFFFF) || (blockindex == 0)) {
continue; //file not found
}
int fileno = blockindex;
//int fileno = libmpq_file_number(&mpq_a, filename);
//if(fileno == LIBMPQ_EFILE_NOT_FOUND)
// continue;
// Found!
size = libmpq_file_info(&mpq_a, LIBMPQ_FILE_UNCOMPRESSED_SIZE, fileno);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
eof = true;
buffer = 0;
return;
}
buffer = new char[size];
//libmpq_file_getdata
libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);
return;
}
eof = true;
buffer = 0;
}
size_t MPQFile::read(void* dest, size_t bytes)
{
if (eof) return 0;
size_t rpos = pointer + bytes;
if (rpos > size) {
bytes = size - pointer;
eof = true;
}
memcpy(dest, &(buffer[pointer]), bytes);
pointer = rpos;
return bytes;
}
void MPQFile::seek(int offset)
{
pointer = offset;
eof = (pointer >= size);
}
void MPQFile::seekRelative(int offset)
{
pointer += offset;
eof = (pointer >= size);
}
void MPQFile::close()
{
if (buffer) delete[] buffer;
buffer = 0;
eof = true;
}

View file

@ -0,0 +1,124 @@
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#ifndef MPQ_H
#define MPQ_H
#include "libmpq/mpq.h"
#include <string.h>
#include <ctype.h>
#include <vector>
#include <iostream>
#include <deque>
using namespace std;
typedef unsigned int uint32;
class MPQArchive
{
public:
mpq_archive mpq_a;
MPQArchive(const char* filename);
void close();
uint32 HashString(const char* Input, uint32 Offset) {
uint32 seed1 = 0x7fed7fed;
uint32 seed2 = 0xeeeeeeee;
for (uint32 i = 0; i < strlen(Input); i++) {
uint32 val = toupper(Input[i]);
seed1 = mpq_a.buf[Offset + val] ^ (seed1 + seed2);
seed2 = val + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
mpq_hash GetHashEntry(const char* Filename) {
uint32 index = HashString(Filename, 0);
index &= mpq_a.header->hashtablesize - 1;
uint32 name1 = HashString(Filename, 0x100);
uint32 name2 = HashString(Filename, 0x200);
for(uint32 i = index; i < mpq_a.header->hashtablesize; ++i) {
mpq_hash hash = mpq_a.hashtable[i];
if (hash.name1 == name1 && hash.name2 == name2) return hash;
}
mpq_hash nullhash;
nullhash.blockindex = 0xFFFFFFFF;
return nullhash;
}
vector<string> GetFileList() {
vector<string> filelist;
mpq_hash hash = GetHashEntry("(listfile)");
uint32 blockindex = hash.blockindex;
if ((blockindex == 0xFFFFFFFF) || (blockindex == 0))
return filelist;
uint32 size = libmpq_file_info(&mpq_a, LIBMPQ_FILE_UNCOMPRESSED_SIZE, blockindex);
char *buffer = new char[size];
libmpq_file_getdata(&mpq_a, hash, blockindex, (unsigned char*)buffer);
char seps[] = "\n";
char *token;
token = strtok( buffer, seps );
uint32 counter = 0;
while ((token != NULL) && (counter < size)) {
//cout << token << endl;
token[strlen(token) - 1] = 0;
string s = token;
filelist.push_back(s);
counter += strlen(token) + 2;
token = strtok(NULL, seps);
}
delete buffer;
return filelist;
}
};
typedef std::deque<MPQArchive*> ArchiveSet;
class MPQFile
{
//MPQHANDLE handle;
bool eof;
char *buffer;
size_t pointer,size;
// disable copying
MPQFile(const MPQFile &f) {}
void operator=(const MPQFile &f) {}
public:
MPQFile(const char* filename); // filenames are not case sensitive
~MPQFile() { close(); }
size_t read(void* dest, size_t bytes);
size_t getSize() { return size; }
size_t getPos() { return pointer; }
char* getBuffer() { return buffer; }
char* getPointer() { return buffer + pointer; }
bool isEof() { return eof; }
void seek(int offset);
void seekRelative(int offset);
void close();
};
inline void flipcc(char *fcc)
{
char t;
t=fcc[0];
fcc[0]=fcc[3];
fcc[3]=t;
t=fcc[1];
fcc[1]=fcc[2];
fcc[2]=t;
}
#endif

Binary file not shown.

View file

@ -0,0 +1,322 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="vmap_assembler"
ProjectGUID="{572FFF74-480C-4472-8ABF-81733BB4049D}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="..\Debug"
IntermediateDirectory="..\Debug\obj"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite; ..\..\..\src\shared\vmap"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmap_assembler.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/vmap_assembler.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="..\Release"
IntermediateDirectory="..\Release\obj"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite; ..\..\..\src\shared\vmap"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmap_assembler.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\..\vmap_assembler.cpp">
</File>
</Filter>
<Filter
Name="vmaplib">
<File
RelativePath="..\..\..\src\shared\vmap\AABSPTree.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\NodeValueAccess.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortBox.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortVector.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.cpp">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.h">
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapTools.h">
</File>
</Filter>
<Filter
Name="g3dlite">
<File
RelativePath="..\..\..\dep\src\g3dlite\AABox.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\AABox.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\AABSPTree.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Array.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Box.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Box.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\CollisionDetection.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\CoordinateFrame.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Crypto.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Crypto.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\debug.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\format.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\format.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\g3dmath.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\g3dmath.inl">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\GCamera.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Line.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Matrix3.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Matrix3.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Plane.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Plane.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\platform.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Quat.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Quat.inl">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Ray.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\RegistryUtil.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Sphere.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\stringutils.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\System.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\System.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Table.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Triangle.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Triangle.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2.inl">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2int16.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Vector3.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3.inl">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3int16.h">
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Vector4.cpp">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector4.h">
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector4.inl">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,456 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="vmap_assembler"
ProjectGUID="{572FFF74-480C-4472-8ABF-81733BB4049D}"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="..\Debug"
IntermediateDirectory="..\Debug\obj"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite;..\..\..\src\shared\vmap;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
EnableEnhancedInstructionSet="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmap_assembler.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/vmap_assembler.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="..\Release"
IntermediateDirectory="..\Release\obj"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\dep\include\g3dlite;..\..\..\src\shared\vmap;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
EnableEnhancedInstructionSet="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmap_assembler.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\..\vmap_assembler.cpp"
>
</File>
</Filter>
<Filter
Name="vmaplib"
>
<File
RelativePath="..\..\..\src\shared\vmap\AABSPTree.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\NodeValueAccess.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortBox.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortVector.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapTools.h"
>
</File>
</Filter>
<Filter
Name="g3dlite"
>
<File
RelativePath="..\..\..\dep\src\g3dlite\AABox.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\AABox.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\AABSPTree.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Array.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Box.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Box.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\CollisionDetection.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\CoordinateFrame.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Crypto.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Crypto.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\debug.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\format.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\format.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\g3dmath.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\g3dmath.inl"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\GCamera.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Line.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Matrix3.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Matrix3.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Plane.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Plane.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\platform.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Quat.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Quat.inl"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Ray.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\RegistryUtil.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Sphere.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\stringutils.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\System.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\System.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Table.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Triangle.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Triangle.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2.inl"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector2int16.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Vector3.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3.inl"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector3int16.h"
>
</File>
<File
RelativePath="..\..\..\dep\src\g3dlite\Vector4.cpp"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector4.h"
>
</File>
<File
RelativePath="..\..\..\dep\include\g3dlite\G3D\Vector4.inl"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,17 @@
# list of map names
509 #AhnQiraj
469 #BlackwingLair
189 #MonasteryInstances
030 #PVPZone01
037 #PVPZone02
033 #Shadowfang
533 #Stratholme Raid
209 #TanarisInstance
309 #Zul'gurub
560 #HillsbradPast
534 #HyjalPast
532 #Karazahn
543 #HellfireRampart
568 #ZulAman
564 #BlackTemple

View file

@ -0,0 +1,118 @@
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "TileAssembler.h"
//=======================================================
// remove last return or LF and tailing SPACE
// remove all char after a #
void chompAndTrim(std::string& str)
{
for(unsigned int i=0;i<str.length(); ++i) {
char lc = str[i];
if(lc == '#') {
str = str.substr(0,i);
break;
}
}
while(str.length() >0) {
char lc = str[str.length()-1];
if(lc == '\r' || lc == '\n' || lc == ' ') {
str = str.substr(0,str.length()-1);
} else {
break;
}
}
}
//=======================================================
/**
This callback method is called for each model found in the dir file.
return true if it should be included in the vmap
*/
bool modelNameFilter(char *pName)
{
#if 0
bool result;
result = !Wildcard::wildcardfit("*bush[0-9]*", pName);
if(result) result = !Wildcard::wildcardfit("*shrub[0-9]*", pName);
if(result) result = !Wildcard::wildcardfit("*_Bushes_*", pName);
if(result) result = !Wildcard::wildcardfit("*_Bush_*", pName);
if(!result) {
printf("%s",pName);
}
#endif
return true;
}
//=======================================================
/**
File contains map names that should be split into tiles
A '#' at the beginning of a line defines a comment
*/
bool readConfigFile(char *pConffile, VMAP::TileAssembler* pTa)
{
bool result = false;
char buffer[501];
FILE *cf = fopen(pConffile, "rb");
if(cf) {
while(fgets(buffer, 500, cf)) {
std::string name = std::string(buffer);
size_t pos = name.find_first_not_of(' ');
name = name.substr(pos);
chompAndTrim(name); // just to be sure
if(name[0] != '#' && name.size() >0) { // comment?
unsigned int mapId = atoi(name.c_str());
pTa->addWorldAreaMapId(mapId);
}
}
fclose(cf);
result = true;
}
return(result);
}
//=======================================================
int main(int argc, char* argv[])
{
if(argc == 3 || argc == 4)
{
bool ok = true;
char *src = argv[1];
char *dest = argv[2];
char *conffile = NULL;
if(argc >= 4) {
conffile = argv[3];
}
VMAP::TileAssembler* ta = new VMAP::TileAssembler(std::string(src), std::string(dest));
ta->setModelNameFilterMethod(modelNameFilter);
/*
All the names in the list are considered to be world maps or huge instances.
These maps will be spilt into tiles in the vmap assemble process
*/
if(conffile != NULL) {
ok = readConfigFile(conffile, ta);
if(!ok) {
printf("Can not open file config file: %s\n", conffile);
}
}
if(ok) { ok = ta->convertWorld(); }
if(ok) {
printf("Ok, all done\n");
} else {
printf("exit with errors\n");
return 1;
}
delete ta;
}
else
{
printf("\nusage: %s <raw data dir> <vmap dest dir> [config file name]\n", argv[0]);
return 1;
}
return 0;
}

View file

@ -0,0 +1,23 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmap_assembler", "VC71\vmap_assembler.vcproj", "{572FFF74-480C-4472-8ABF-81733BB4049D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug.ActiveCfg = Debug|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug.Build.0 = Debug|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release.ActiveCfg = Release|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmap_assembler", "VC80\vmap_assembler.vcproj", "{572FFF74-480C-4472-8ABF-81733BB4049D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug|Win32.ActiveCfg = Debug|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Debug|Win32.Build.0 = Debug|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release|Win32.ActiveCfg = Release|Win32
{572FFF74-480C-4472-8ABF-81733BB4049D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,570 @@
#include "ModelContainerView.h"
namespace VMAP
{
char* gDataDir = NULL;
char* gLogFile = NULL;
//==========================================
ModelContainerView::ModelContainerView(const G3D::GApp::Settings& settings) : GApp(settings) {
i_App = this;
iCommandFileRW.setFileName(gLogFile);
iCurrCmdIndex = 0;
iVMapManager = new VMapManager();
iDrawLine = false;
iVARAreaRef = VARArea::create(1024*1024*60);
iVARAreaRef2 = VARArea::create(1024*1024*2);
iInstanceId = -1;
iPosSent = false;
}
//===================================================
ModelContainerView::~ModelContainerView(void)
{
Array<std::string > keys = iTriVarTable.getKeys();
Array<std::string>::ConstIterator i = keys.begin();
while(i != keys.end()) {
VAR* var = iTriVarTable.get(*i);
delete var;
++i;
}
}
//===================================================
void ModelContainerView::cleanup() {
}
//===================================================
Vector3 getViewPos(const ModelContainer* mc, unsigned int pModelNr = 0) {
if(mc->getNSubModel() < pModelNr) {
pModelNr = mc->getNSubModel();
}
const SubModel sm = mc->getSubModel(pModelNr);
return (sm.getAABoxBounds().low());
}
void ModelContainerView::init() {
}
//==========================================
void fillSubModelArary(const ModelContainer* pModelContainer, const TreeNode *root, Array<SubModel>& array, Vector3& pLo, Vector3& pHi) {
Vector3 lo = Vector3(inf(), inf(), inf());
Vector3 hi = Vector3(-inf(), -inf(), -inf());
for(int i=0; i< root->getNValues(); i++) {
SubModel sm = pModelContainer->getSubModel(root->getStartPosition() + i);
lo = lo.min(sm.getAABoxBounds().low());
hi = hi.max(sm.getAABoxBounds().high());
array.append(sm);
}
if(root->getChild((TreeNode *) &pModelContainer->getTreeNode(0), 0)) {
fillSubModelArary(pModelContainer, root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 0), array, lo, hi);
}
if(root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 1)) {
fillSubModelArary(pModelContainer, root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 1), array, lo, hi);
}
float dist1 = (hi -lo).magnitude();
AABox b;
root->getBounds(b);
float dist2 = (b.high() -b.low()).magnitude();
if(dist1 > dist2) {
// error
int xxx = 0;
}
}
//==========================================
void ModelContainerView::addModelContainer(const std::string& pName,const ModelContainer* pModelContainer) {
// VARArea::UsageHint::WRITE_EVERY_FEW_FRAMES
int offset=0;
Array<int> iIndexArray;
Array<Vector3> iGlobArray;
Array<SubModel> SMArray;
Vector3 lo, hi;
fillSubModelArary(pModelContainer, &pModelContainer->getTreeNode(0), SMArray,lo,hi);
for(int i=0; i<SMArray.size(); ++i) {
SubModel sm = SMArray[i];
Array<Vector3> vArray;
Array<int> iArray;
fillVertexAndIndexArrays(sm, vArray, iArray);
for(int j=0;j<iArray.size(); ++j) {
iIndexArray.append(offset+iArray[j]);
}
for(int j=0;j<vArray.size(); ++j) {
iGlobArray.append(vArray[j]);
}
offset += vArray.size();
//break;
}
iTriVarTable.set(pName, new VAR(iGlobArray ,iVARAreaRef));
iTriIndexTable.set(pName, iIndexArray);
}
//===================================================
void ModelContainerView::removeModelContainer(const std::string& pName, const ModelContainer* pModelContainer) {
VAR* var = iTriVarTable.get(pName);
iTriVarTable.remove(pName);
delete var;
}
Vector3 p1,p2,p3,p4,p5,p6,p7;
Array<AABox>gBoxArray;
Array<G3D::Triangle>gTriArray;
int gCount1 = 0, gCount2 = 0 , gCount3 = 0, gCount4 = 0;
bool myfound=false;
//===================================================
void ModelContainerView::onInit() {
// Called before the application loop beings. Load data here and
// not in the constructor so that common exceptions will be
// automatically caught.
iSky = Sky::fromFile("../../data/sky/");
iSkyParameters = SkyParameters(G3D::toSeconds(11, 00, 00, AM));
iLighting = Lighting::fromSky(iSky, iSkyParameters, Color3::white());
// This simple demo has no shadowing, so make all lights unshadowed
iLighting->lightArray.append(iLighting->shadowedLightArray);
iLighting->shadowedLightArray.clear();
// Example debug GUI:
//debugPane->addCheckBox("Use explicit checking", &explicitCheck);
debugWindow->setVisible(true);
toneMap->setEnabled(false);
}
void ModelContainerView::onGraphics(RenderDevice* rd, Array<PosedModelRef> &posed3D, Array<PosedModel2DRef> &posed2D) {
Array<PosedModel::Ref> opaque, transparent;
LightingRef localLighting = toneMap->prepareLighting(iLighting);
SkyParameters localSky = toneMap->prepareSkyParameters(iSkyParameters);
toneMap->beginFrame(rd);
rd->setProjectionAndCameraMatrix(defaultCamera);
rd->setColorClearValue(Color3::black());
rd->clear();
//iSky->render(rd, localSky);
// Setup lighting
rd->enableLighting();
//rd->setLight(0, localLighting->lightArray[0]);
//rd->setAmbientLightColor(localLighting->ambientAverage());
GLight light =GLight::directional(defaultController.pointer()->position() + defaultController.pointer()->lookVector()*2,Color3::white());
rd->setLight(0,light);
rd->setColor(Color3::blue());
Array<std::string > keys = iTriVarTable.getKeys();
Array<std::string>::ConstIterator i = keys.begin();
while(i != keys.end()) {
VAR* var = iTriVarTable.get(*i);
Array<int> indexArray = iTriIndexTable.get(*i);
rd->beginIndexedPrimitives();
rd->setVertexArray(*var);
rd->sendIndices(RenderDevice::LINES, indexArray);
rd->endIndexedPrimitives();
++i;
}
for(int i=0; i<gBoxArray.size(); ++i) {
AABox b = gBoxArray[i];
Draw::box(b,rd,Color4(Color3::red(),0.9f));
}
//-------
//triangles
{
if(iTriDebugArray.size() > 0)
{
rd->setColor(Color3::red());
rd->beginIndexedPrimitives();
rd->setVertexArray(iTriDebugVar);
rd->sendIndices(RenderDevice::LINES, iTriDebugArray);
rd->endIndexedPrimitives();
}
}
//--------
if(iDrawLine) {
Draw::lineSegment(LineSegment::fromTwoPoints(iPos1, iPos2), rd, iColor, 3);
if(myfound) {
//Draw::lineSegment(LineSegment::fromTwoPoints(p1, p2), rd, iColor, 3);
//Draw::lineSegment(LineSegment::fromTwoPoints(p2, p3), rd, iColor, 3);
//Draw::lineSegment(LineSegment::fromTwoPoints(p3, p1), rd, iColor, 3);
Draw::sphere(Sphere(p4,0.5),rd, iColor);
//Draw::sphere(Sphere(p5,0.5),rd, Color3::green());
}
}
// Always render the posed models passed in or the Developer Window and
// other Widget features will not appear.
if (posed3D.size() > 0) {
Vector3 lookVector = renderDevice->getCameraToWorldMatrix().lookVector();
PosedModel::sort(posed3D, lookVector, opaque, transparent);
for (int i = 0; i < opaque.size(); ++i) {
opaque[i]->render(renderDevice);
}
for (int i = 0; i < transparent.size(); ++i) {
transparent[i]->render(renderDevice);
}
}
rd->disableLighting();
toneMap->endFrame(rd);
PosedModel2D::sortAndRender(rd, posed2D);
}
//===================================================
void ModelContainerView::fillRenderArray(const SubModel& pSm, Array<TriangleBox> &pArray, const TreeNode* pTreeNode) {
for(int i=0;i<pTreeNode->getNValues(); i++) {
pArray.append(pSm.getTriangles()[i+pTreeNode->getStartPosition()]);
}
if(pTreeNode->getChild(pSm.getTreeNodes(), 0) != 0) {
fillRenderArray(pSm, pArray, pTreeNode->getChild(pSm.getTreeNodes(), 0));
}
if(pTreeNode->getChild(pSm.getTreeNodes(), 1) != 0) {
fillRenderArray(pSm, pArray, pTreeNode->getChild(pSm.getTreeNodes(), 1));
}
}
//===================================================
void ModelContainerView::fillVertexAndIndexArrays(const SubModel& pSm, Array<Vector3>& vArray, Array<int>& iArray) {
Array<TriangleBox> tbarray;
fillRenderArray(pSm, tbarray, &pSm.getTreeNode(0));
MeshBuilder builder;
int len = tbarray.size();
int count = 0;
for(int i=0;i<len;++i) {
Triangle t = Triangle(tbarray[i].vertex(0).getVector3() + pSm.getBasePosition(),
tbarray[i].vertex(1).getVector3() + pSm.getBasePosition(),
tbarray[i].vertex(2).getVector3() + pSm.getBasePosition());
vArray.append(t.vertex(0));
vArray.append(t.vertex(1));
vArray.append(t.vertex(2));
iArray.append(count+0);
iArray.append(count+1);
iArray.append(count+1);
iArray.append(count+2);
iArray.append(count+2);
iArray.append(count+0);
count+=3;
}
}
//====================================================================
void ModelContainerView::showMap(int pMapId, int x, int y) {
MapTree* mt = iVMapManager->getInstanceMapTree(pMapId);
std::string dirFileName = iVMapManager->getDirFileName(pMapId);
if(!mt->hasDirFile(dirFileName)) {
dirFileName = iVMapManager->getDirFileName(pMapId, x, y);
}
showMap(mt,dirFileName);
iInstanceId = pMapId;
}
//====================================================================
bool ModelContainerView::loadAndShowTile(int pMapId, int x, int y) {
char buffer[500];
sprintf(buffer, "%s/vmaps",gDataDir);
bool result = false;
//if(pMapId == 1) return true; //+++
int val = iVMapManager->loadMap(buffer,(unsigned int) pMapId, x,y);
if(val == VMAP_LOAD_RESULT_OK) {
result = true;
showMap(pMapId,x,y);
} else {
printf("Unable to load %s\n", buffer);
}
return(result);
}
//=======================================================================
void ModelContainerView::showMap(MapTree* mt, std::string dirFileName) {
if(mt->hasDirFile(dirFileName)) {
FilesInDir filesInDir = mt->getDirFiles(dirFileName);
if(filesInDir.getRefCount() == 1) {
Array<std::string> fileNames = filesInDir.getFiles();
for(int i=0; i<fileNames.size(); ++i) {
std::string name = fileNames[i];
ManagedModelContainer* mc = mt->getModelContainer(name);
//if(mc->getNSubModel() == 791) {
addModelContainer(name, mc);
//}
}
}
}
}
//=======================================================================
bool ModelContainerView::loadAndShowTile(int pMapId) {
char buffer[500];
sprintf(buffer, "%s/vmaps",gDataDir);
bool result = false;
int val = iVMapManager->loadMap(buffer, (unsigned int) pMapId,-1,-1);
if(val == VMAP_LOAD_RESULT_OK) {
result = true;
MapTree* mt = iVMapManager->getInstanceMapTree(pMapId);
std::string dirFileName = iVMapManager->getDirFileName(pMapId);
iTriVarTable = Table<std::string , VAR*>();
iTriIndexTable = Table<std::string , Array<int> >(); // reset table
iInstanceId = pMapId;
showMap(mt,dirFileName);
}
return(result);
}
//====================================================================
void ModelContainerView::processCommand() {
iDrawLine = false;
if(iCurrCmdIndex < iCmdArray.size()) {
bool cmdfound = false;
while(!cmdfound && (iCurrCmdIndex < iCmdArray.size())) {
Command c = iCmdArray[iCurrCmdIndex];
if(c.getType() == LOAD_TILE) {
iPrevLoadCommands.push_back(c);
if(iPosSent) {
if(loadAndShowTile(c.getInt(2), c.getInt(0), c.getInt(1))) {
printf("load tile mapId=%d, %d, %d\n", c.getInt(2), c.getInt(0), c.getInt(1));
} else {
printf("ERROR: unable to load tile mapId= %d, %d, %d\n", c.getInt(2), c.getInt(0), c.getInt(1));
}
cmdfound = true;
} else {
printf("ignore load tile mapId=%d, %d, %d\n", c.getInt(2), c.getInt(0), c.getInt(1));
}
} else if(c.getType() == LOAD_INSTANCE) {
if(loadAndShowTile(c.getInt(0))) {
printf("load instance %d\n", c.getInt(0));
}
cmdfound = true;
} else if(c.getType() == UNLOAD_TILE) {
/*
iVMapManager->unloadMap(c.getInt(2), c.getInt(0), c.getInt(1));
printf("unload tile %d, %d\n", c.getInt(0), c.getInt(1));
std::string dirFileName = iVMapManager->getDirFileName(iVMapManager->getMapIdNames(c.getInt(2)).iMapGroupName.c_str(), c.getInt(0), c.getInt(1));
MapTree* mt = iVMapManager->getInstanceMapTree(c.getInt(2));
if(mt->hasDirFile(dirFileName)) {
Array<std::string> fileNames = mt->getDirFiles(dirFileName).getFiles();
for(int i=0; i<fileNames.size(); ++i) {
std::string name = fileNames[i];
ManagedModelContainer* mc = mt->getModelContainer(name);
removeModelContainer(name, mc);
}
}
*/
} else if(c.getType() == SET_POS) {
if(!iPosSent) {
int count = 3;
while(iPrevLoadCommands.size() > 0 && count>0) {
Command lc = iPrevLoadCommands.last();
iPrevLoadCommands.pop_back();
// first time, load the last map needed
if(loadAndShowTile(lc.getInt(2), lc.getInt(0), lc.getInt(1))) {
printf("load tile mapid=%d, %d, %d\n", lc.getInt(2), lc.getInt(0), lc.getInt(1));
} else {
printf("ERROR: unable to load tile mapid=%d, %d, %d\n", lc.getInt(2), lc.getInt(0), lc.getInt(1));
}
--count;
}
}
iPosSent = true;
defaultCamera.setPosition(Vector3(c.getVector(0).x,c.getVector(0).y+3, c.getVector(0).z));
defaultController.pointer()->setPosition(Vector3(c.getVector(0).x,c.getVector(0).y+3, c.getVector(0).z));
printf("set pos to %f, %f, %f\n",c.getVector(0).x, c.getVector(0).y, c.getVector(0).z );
cmdfound = true;
} else if(c.getType() == TEST_VIS) {
printf("TEST line of sight\n");
iDrawLine = true;
iPos1 = iVMapManager->convertPositionToInternalRep(c.getVector(0).x, c.getVector(0).y, c.getVector(0).z);
iPos2 = iVMapManager->convertPositionToInternalRep(c.getVector(1).x, c.getVector(1).y, c.getVector(1).z);
if(c.getInt(0) != 0) {
iColor = Color3::green();
} else {
iColor = Color3::red();
}
cmdfound = true;
/*
{
// draw debug-lines
int count = 0;
for(int i=0; i<gTriArray.size(); ++i) {
Triangle &t = gTriArray[i];
iVTriDebugArray.append(t.vertex(0));
iVTriDebugArray.append(t.vertex(1));
iVTriDebugArray.append(t.vertex(2));
iTriDebugArray.append(count+0);
iTriDebugArray.append(count+1);
iTriDebugArray.append(count+1);
iTriDebugArray.append(count+2);
iTriDebugArray.append(count+2);
iTriDebugArray.append(count+0);
count+=3;
}
iTriDebugVar = VAR(iVTriDebugArray ,iVARAreaRef2);
}
*/
}
++iCurrCmdIndex;
}
} else {
printf("end reached\n");
}
}
//====================================================================
Vector3 ModelContainerView::convertPositionToMangosRep(float x, float y, float z) const {
float pos[3];
pos[0] = z;
pos[1] = x;
pos[2] = y;
double full = 64.0*533.33333333;
double mid = full/2.0;
pos[0] = -((mid+pos[0])-full);
pos[1] = -((mid+pos[1])-full);
return(Vector3(pos));
}
//====================================================================
void ModelContainerView::onUserInput(UserInput* ui) {
GApp::onUserInput(ui);
if(ui->keyPressed(GKey::fromString("l"))) { //load
iCmdArray = Array<Command>();
iCommandFileRW.getNewCommands(iCmdArray);
iCurrCmdIndex = 0;
processCommand();
}
if(ui->keyPressed(GKey::fromString("r"))) { //restart
iCurrCmdIndex = 0;
}
if(ui->keyPressed(GKey::fromString("1"))) { //inc count1
gCount1++;
}
if(ui->keyPressed(GKey::fromString("h"))) { //inc count1
#if 0
i_App->defaultController.getPosition();
Vector3 pos = i_App->defaultController.getPosition();
Vector3 pos2 = convertPositionToMangosRep(pos.x, pos.y, pos.z);
//Vector3 pos3 = iVMapManager->convertPositionToInternalRep(pos2.x, pos2.y, pos2.z);
//pos3 = iVMapManager->convertPositionToInternalRep(pos2.x, pos2.y, pos2.z);
float hight = iVMapManager->getHeight(iInstanceId, pos2.x, pos2.y, pos2.z);
printf("Hight = %f\n",hight);
#endif
}
if(ui->keyPressed(GKey::fromString("2"))) { //dec count1
gCount1--;
if(gCount1 < 0)
gCount1 = 0;
}
if(ui->keyPressed(GKey::fromString("z"))) { //zero pos
i_App->defaultCamera.setPosition(Vector3(0,0,0));
printf("set pos to 0, 0, 0\n");
}
if(ui->keyPressed(GKey::fromString("c"))) { //restart
if(iCurrCmdIndex > 0) {
if(iCmdArray[iCurrCmdIndex-1].getType() == TEST_VIS) {
Vector3 p1 = iCmdArray[iCurrCmdIndex-1].getVector(0);
Vector3 p2 = iCmdArray[iCurrCmdIndex-1].getVector(1);
bool result;
int mapId = iCmdArray[iCurrCmdIndex-1].getInt(1);
gCount3 = gCount2 = 0;// debug counter
gBoxArray = Array<AABox>();
result = iVMapManager->isInLineOfSight(mapId, p1.x,p1.y,p1.z,p2.x,p2.y,p2.z);
printf("recalc last line of light: result = %d\n", result);
}
}
}
if(ui->keyPressed(GKey::LEFT_MOUSE)) {
if( iCurrCmdIndex>0) {
--iCurrCmdIndex;
printf("restart last command\n");
processCommand();
}
}
if(ui->keyPressed(GKey::MIDDLE_MOUSE)) {
processCommand();
}
}
//==========================================
void ModelContainerView::setViewPosition(const Vector3& pPosition) {
//i_App->defaultController.setPosition(pPosition);
i_App->defaultCamera.setPosition(pPosition);
}
//==========================================
//==========================================
}
G3D_START_AT_MAIN();
int main(int argc, char** argv) {
if(argc == 3) {
VMAP::gDataDir = argv[1];
VMAP::gLogFile = argv[2];
G3D::GApp::Settings settings;
settings.window.width = 1024;
settings.window.height = 768;
//settings.useDeveloperTools = true;
VMAP::ModelContainerView modelContainerView(settings);
modelContainerView.run();
} else {
printf("%s <data dir> <vmapcmd.log file>\n",argv[0]);
}
}

View file

@ -0,0 +1,89 @@
#ifndef _MODELCONTAINERVIEW_H
#define _MODELCONTAINERVIEW_H
#include <G3D/G3DAll.h>
#include <G3D/System.h>
#include "ModelContainer.h"
#include "DebugCmdLogger.h"
#include "vmapmanager.h"
namespace VMAP
{
//==========================================
//==========================================
class ModelContainerView :
public G3D::GApp
{
private:
SkyRef iSky;
LightingRef iLighting;
SkyParameters iSkyParameters;
VARAreaRef iVARAreaRef;
Table<std::string , VAR*> iTriVarTable;
Table<std::string , Array<int> > iTriIndexTable;
VARAreaRef iVARAreaRef2;
VAR iTriDebugVar;
Array<Vector3> iVTriDebugArray;
Array<int> iTriDebugArray;
//Array<int> iLineIndexArray;
GApp* i_App;
CommandFileRW iCommandFileRW;
Array<Command> iCmdArray;
int iCurrCmdIndex;
VMapManager* iVMapManager;
Vector3 iPos1;
Vector3 iPos2;
Color3 iColor;
bool iDrawLine;
int iInstanceId;
bool iPosSent;
Array<Command> iPrevLoadCommands;
private:
Vector3 convertPositionToMangosRep(float x, float y, float z) const;
public:
ModelContainerView(const G3D::GApp::Settings& settings);
~ModelContainerView(void);
void addModelContainer(const std::string& pName,const ModelContainer* pModelContainer);
void removeModelContainer(const std::string& pName, const ModelContainer* pModelContainer);
void setViewPosition(const Vector3& pPosition);
void onGraphics(RenderDevice* rd, Array<PosedModelRef> &posed3D, Array<PosedModel2DRef> &posed2D);
virtual void onInit();
void init();
void cleanup();
void onUserInput(UserInput* ui);
void fillRenderArray(const SubModel& pSm,Array<TriangleBox> &pArray, const TreeNode* pTreeNode);
void fillVertexAndIndexArrays(const SubModel& pSm, Array<Vector3>& vArray, Array<int>& iArray);
bool loadAndShowTile(int pMapId, int x, int y);
void showMap(int pMapId, int x, int y);
void showMap(MapTree* mt, std::string dirFileName);
bool loadAndShowTile(int pMapId);
void processCommand();
};
//==========================================
//==========================================
}
#endif

Binary file not shown.

View file

@ -0,0 +1,308 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="vmapdebugger"
ProjectGUID="{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}"
RootNamespace="vmapdebugger"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\src\shared\vmap;&quot;G:\Core My Work\G3D-7.00\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_DEBUG_VMAPS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmapdebugger.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;G:\Core My Work\G3D-7.00\lib&quot;"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/vmapdebugger.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\src\shared\vmap;&quot;G:\Core My Work\G3D-7.00\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_DEBUG;_DEBUG_VMAPS"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/vmapdebugger.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;G:\Core My Work\G3D-7.00\lib&quot;"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\ModelContainerView.cpp"
>
</File>
<File
RelativePath="..\ModelContainerView.h"
>
</File>
</Filter>
<Filter
Name="vmap"
>
<File
RelativePath="..\..\..\src\shared\vmap\AABSPTree.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\BaseModel.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\CoordModelMapping.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\DebugCmdLogger.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\IVMapManager.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ManagedModelContainer.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ModelContainer.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\NodeValueAccess.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortBox.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\ShortVector.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\SubModel.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TileAssembler.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\TreeNode.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapDefinitions.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapFactory.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapFactory.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapManager.cpp"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapManager.h"
>
</File>
<File
RelativePath="..\..\..\src\shared\vmap\VMapTools.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

Binary file not shown.

View file

@ -0,0 +1,121 @@
Here you find a visual debugging tool. With that you can check it yourself. You need to compile it
yourself or just use the precompiled version. The precompiled version should not need any
additional libraries. If you try to compile it yourself you need G3D library 7.00 and
SDL 1.2.8 or higher.
There is NO “how to compile support”.... You will manage it, if you need to...
What does it do?
The program analyses the content of the vmapcmd.log file created by [b] mangosd compiled
in debug mode [/b] with vmap support. The commands written to disk are read and the result
is displayed in a graphical view. This view shows a wire frame model of the loaded vmaps
and you can move in these maps. Furthermore you can see witch line of sight query where
performed and its result. You are able to perform the ling of sight query again and will see, if
the current version of the vmap source compiled against the debugger, produces the same
result. This last function is useful for debugging the line of sight code.
The little program is a real hack, but is fits is purpose.
How to use it:
[b]Logging[b]
You will need to set _VMAP_LOG_DEBUG when compiling core in debug mode to get this log.
If mangos is compiled in debug mode it will then write the vmapcmd.log file. The file does only
contain the information which vmaps are loaded. I addition to that the file need the
information where your character currently in standing in the maps. This position information
has to be inserted manually. To do that I modified the .announce command to send the
position of the current character to the log file (modification is in the attached patch).
The line of sight query is only stored in the log file if you enable this kind of logging. This is
done by performing the modified .gm off command. Enabling line of sight and moving your
character a bit will log the queries and there results. Dont do this for log, it will produce lots
of data, which is hard to analyze later.
The modified command .gm on will stop the logging of the line of sight calculation.
What do you have to do for logging?
1. Apply the patch to mangos to modify your .announce, .gmoff and .gmon commands
2. Compile mangos in debug mode
3. Go to the position where you suspect a problem
4. Use .gmon to be sure you will not be attacked when you login
5. Save, Logoff and stop mangosd
6. Delete the vmapcmd.log from the mangos dir. The logger will append to that file.
7. Start mangos
8. Login with your character
9. Send your position to the log file. Do this with the .announce command (.announce
foo)
10. Type .gmoff enabling the line of sight logging
11. Move a bit to get the attention of the mobs
12. Type .gmon to stop the logging
[b]Analysing the log file[/b]
1. Start the vmap debugger with the path to the mangos data dir and the full path (name) of
the log file
2. The debugger is controlled by single keys and the mouse. Here is a list of key commands.
The result is displayed at the console:
l (small L) Load the next block off logging data into the command queue and process the
first command from the queue. When the end is reached a message “end reached” is display at
the console. If you reached the you can press l again. Sending .gm on sets an end mark to the
file. You have to load the next logging block after each .gmon command.
r Reload the last command block
mouse middle click process the next command from the queue
mouse left click reprocess the last command from the queue
c recalculate the last line of sight command and send the result to the console
w,s,a,d move within the 3D view
ESC exit
TAB release/grep the mouse
[b]How to test the included example with the precompiled version with the included
vmapcmd.log file:[b]
open your console
move to the contrib\vmap_debugger\bin directory
run: vmapdebugger.exe <your mangos data dir> vmapcmd.log
Wait until the block screen is open and arrange the console and the screen, so you can see
both
Press: l (small L not one)
click middle
click middle
click middle
Now you should see the wire frame model of scholo and the green line of sight line in the
display. The green line means the test was performed and you are seen. A red line means you
are not seen. Move around a bit with the mouse and the w,s,a,d keys.
Press c
Press ESC
[b]Problems with your gfx.card[/b]
Maybe the program does not woth with your graphics card. In this case you have dad luck.
One think might help, if not .... I do not know...:
Here I take 60 MB Ram from Gfx-Card [b]VARArea::create(1024*1024*60)[/b]. That
might cause problems on your system.
[code]
ModelContainerView::ModelContainerView(GApp* pApp) : GApplet(pApp) {
i_App = pApp;
iCommandFileRW.setFileName(gLogFile);
iCurrCmdIndex = 0;
iVMapManager = new VMapManager();
iDrawLine = false;
iVARAreaRef = VARArea::create(1024*1024*60);
iInstanceId = -1;
}
[/code]
This should give all of you who, are interested the chance to check the content and behavior
of the vmaps.

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapdebugger", "VC8\vmapdebugger.vcproj", "{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}.Debug|Win32.ActiveCfg = Debug|Win32
{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}.Debug|Win32.Build.0 = Debug|Win32
{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}.Release|Win32.ActiveCfg = Release|Win32
{0F6BDF3C-9B6F-45A0-A443-E26E31C8A015}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,46 @@
@echo off
cls
echo.
echo Welcome to the vmaps extractor and assembler
echo.
echo You need 2GB of free space in disk, CTRL+C to stop process
echo Hit Enter to start . . .
pause>nul
cls
echo.
echo.
echo.
IF EXIST buildings\dir (ECHO The buildings folder already exist do you want to delete it?
echo If YES hit Enter to continue if no CLOSE the program now! . . .
pause>nul
DEL /S /Q buildings)
vmapextract_v2.exe
cls
echo.
echo.
echo.
IF NOT %ERRORLEVEL% LEQ 1 (echo The vmap extract tool finalized with errors.
echo Hit Enter to continue . . .
pause>nul)
cls
echo.
echo.
echo.
echo Vmaps extracted check log.txt for errors, now it's time to assemble the vmaps press any key to continue . . .
pause>nul
md vmaps
vmap_assembler.exe buildings vmaps splitConfig.txt
cls
echo.
echo.
echo.
IF NOT %ERRORLEVEL% LEQ 1 (echo The vmap assembler tool finalized with errors.
echo Hit Enter to continue . . .
pause>nul)
cls
echo.
echo.
echo.
echo Process done! copy vmaps folder to the MaNGOS main directory
echo Press any key to exit . . .
pause>nul

View file

@ -0,0 +1,5 @@
vmapextract_v2.exe
md vmaps
vmap_assembler.exe buildings vmaps splitConfig.txt
pause

View file

@ -0,0 +1,4 @@
execute make vmaps.bat to make vmaps step by sep
execute makevmaps_SIMPLE.bat to so it in one step no quesions final screen [recommended]
put vmaps folder in mangos main folder to enable LOS [Line Of Sight]

View file

@ -0,0 +1,17 @@
# list of map names
509 #AhnQiraj
469 #BlackwingLair
189 #MonasteryInstances
030 #PVPZone01
037 #PVPZone02
033 #Shadowfang
533 #Stratholme Raid
209 #TanarisInstance
309 #Zul'gurub
560 #HillsbradPast
534 #HyjalPast
532 #Karazahn
543 #HellfireRampart
568 #ZulAman
564 #BlackTemple

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,318 @@
THE MOPAQ ARCHIVE FORMAT
v0.9 (Thursday, June 30, 2005)
by Justin Olbrantz(Quantam)
Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quoting
in other works is freely allowed, as long as the source and author of the quote is stated.
TABLE OF CONTENTS
1. Introduction to the MoPaQ Format
2. The MoPaQ Format
2.1 General Archive Layout
2.2 Archive Header
2.3 Block Table
2.4 Hash Table
2.5 File Data
2.6 Listfile
2.7 Extended Attributes
2.8 Weak (Old) Digital Signature
2.9 Strong (New) Digital Signature
3. Algorithm Source Code
3.1 Encryption/Decryption
3.2 Hashing
3.3 Conversion of FILETIME and time_t
1. INTRODUCTION TO THE MOPAQ FORMAT
The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard
Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be
a read-only game archive format, and excels at this role.
The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked.
The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
2. THE MOPAQ FORMAT
All numbers in the MoPaQ format are in little endian. Data types are listed either as int (integer, the number of bits specified),
byte (8 bits), and char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise.
Structure members are listed in the following general form:
offset from the beginning of the structure: data type(array size) member name : member description
2.1 GENERAL ARCHIVE LAYOUT
- Archive Header
- File Data
- File Data - Special Files
- Hash Table
- Block Table
- Strong Digital signature
This is the usual archive format, and is not absolutely essential. Some archives have been observed placing the hash table
and file table after the archive header, and before the file data.
2.2 ARCHIVE HEADER
00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
04h: int32 HeaderSize : Size of the archive header. Should be 32.
08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present.
This size is used, among other things, for determining the region to hash in computing the digital signature.
0Ch: int16 Unknown : Unknown
0Eh: int8 SectorSizeShift : Power of two exponent specifying the number of 512-byte disk sectors in each logical sector
in the archive. The size of each logical sector the archive is 512 * 2^SectorSizeShift. Bugs in the Storm library dictate
that this should always be 3 (4096 byte sectors).
10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
18h: int32 HashTableEntries : Number of entries in the hash table. Must be a power of two, and must be less than 2^16.
1Ch: int32 BlockTableEntries : Number of entries in the block table.
The archive header is the first structure in the archive, at archive offset 0, but the archive does not need to be at offset
0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not
at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the
archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer
versions (due to the strong digital signature not being considered a part of the archive).
2.3 BLOCK TABLE
The block table contains entries for each region in the archive. Regions may be either files or empty space, which may be
overwritten by new files (typically this space is from deleted file data). The block table is encrypted, using the hash
of "(block table)" as the key. Each entry is structured as follows:
00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive. Meaningless if the block size is 0.
04h: int32 BlockSize : Size of the block in the archive.
08h: int32 FileSize : Size of the file data stored in the block. Only valid if the block is a file, otherwise meaningless, and should be 0. If the file is compressed, this is the size of the uncompressed file data.
0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
80000000h: Block is a file, and follows the file data format; otherwise, block is free space, and may be overwritten. If the block is not a file, all other flags should be cleared.
01000000h: File is stored as a single unit, rather than split into sectors.
00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
00010000h: File is encrypted.
00000200h: File is compressed. Mutually exclusive to file imploded.
00000100h: File is imploded. Mutually exclusive to file compressed.
2.4 HASH TABLE
Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
00h: int32 FilePathHashA : The hash of the file path, using method A.
04h: int32 FilePathHashB : The hash of the file path, using method B.
08h: int16 Language : The language of the file. This is a Windows LANGID data type, and uses the same values. 0 indicates the default language (American English), or that the file is language-neutral.
0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
0Ch: int32 FileBlockIndex : If the hash table entry is valid, this is the index into the block table of the file. Otherwise, one of the following two values:
FFFFFFFFh: Hash table entry is empty, and has always been empty. Terminates searches for a given file.
FFFFFFFEh: Hash table entry is empty, but was valid at some point (in other words, the file was deleted). Does not terminate searches for a given file.
2.5 FILE DATA
00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector's data, relative to the beginning of the file data. Not present if this information is calculatable (see details below).
immediately following SectorOffsetTable: SectorData : Data of each sector in the file, packed end to end (see details below).
Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may be smaller than this, depending on the size of the file data. This sector size is the size of the raw file data; if the file is compressed, the compressed sector will be smaller or the same size as the uncompressed sector size. Individual sectors in a compressed file may be stored uncompressed; this occurs if and only if the sector could not be compressed by the algorithm used (if the compressed sector size was greater than or equal to the size of the raw data), and is indicated by the sector's compressed size in SectorOffsetTable being equal to the uncompressed size of the sector (which may be calculated from the FileSize).
If the sector is compressed (but not imploded), a bit mask byte of the compression algorithm(s) used to compress the sector is appended to the beginning of the compressed sector data. This additional byte counts towards the total size of the sector; if the size of the sector (including this byte) exceeds or matches the uncompressed size of the sector data, the sector will be stored uncompressed, and this byte omitted. Multiple compression algorithms may be used on the same sector; in this case, successive compression occurs in the order the algorithms are listed below, and decompression occurs in the opposite order. For implimentations of all of these algorithms, see StormLib.
40h: IMA ADPCM mono
80h: IMA ADPCM stereo
01h: Huffman encoded
02h: Deflated (see ZLib)
08h: Imploded (see PKWare Data Compression Library)
10h: BZip2 compressed (see BZip2)
If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which
contains the entire file.
If the file is encrypted, each sector (after compression and appendage of the compression type byte, if applicable)
is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the
directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is
adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset)
XOR FileSize) (StormLib - an open-source implementation of the MoPaQ reading and writing functions,
by Ladislav Zezula - incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the
0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize.
This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors
is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the
SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously.
Note that the SectorOffsetTable will always be present if the file is compressed/imploded and the file is not stored as
a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the
archive's sector size).
2.6 LISTFILE
The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive.
The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)",
and is simply a non-Unix-style text file with one file path on each line, lines terminated with the bytes 0Dh 0Ah. The file
"(listfile)" may not be listed in the listfile.
2.7 EXTENDED ATTRIBUTES
The extended attributes are optional file attributes for files in the block table. These attributes were added at times after
the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes.
If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although
the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the
blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file,
in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other
structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some
archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This
file is structured as follows:
00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
00000001h: File CRC32s.
00000002h: File timestamps.
00000004h: File MD5s.
08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the
archive does not have CRC32s. immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block
in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive.
Omitted if the archive does not have MD5s.
2.8 WEAK DIGITAL SIGNATURE
The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation of the RSASSA-PKCS1-v1_5
digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak) RSA key (for more information about this
protocol, see the RSA Labs PKCS1 specification). The public key and exponent are stored in a resource in Storm. The signature
is stored uncompressed, unencrypted in the file "(signature)" in the archive. The archive is hashed from the beginning of the
archive (ArchiveOffset in the containing file) to the end of the archive (the length indicated by ArchiveSize); the signature
file is added to the archive before signing, and the space occupied by the file is considered to be all binary 0s during
signing/verification. This file is structured as follows:
00h: int32 Unknown : Must be 0.
04h: int32 Unknown : must be 0.
08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored in little-endian order.
2.9 STRONG DIGITAL SIGNATURE
The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and
a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well.
The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize
bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
04h: int2048 Signature : The digital signature, stored in little-endian format.
When the Signature field is decrypted with the public key and exponent, and the result stored in little-endian order, it is structured as follows:
00h: byte Padding : Must be 0Bh.
01h: byte(235) Padding : Must be BBh.
ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 format.
3. ALGORITHM SOURCE CODE
3.1 ENCRYPTION/DECRYPTION
I believe this was derived at some point from code in StormLib. Assumes the long type to be 32 bits, and the machine to be little endian order.
unsigned long dwCryptTable[0x500];
void InitializeCryptTable()
{
unsigned long seed = 0x00100001;
unsigned long index1 = 0;
unsigned long index2 = 0;
int i;
for (index1 = 0; index1 < 0x100; index1++)
{
for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
{
unsigned long temp1, temp2;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp1 = (seed & 0xFFFF) << 0x10;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp2 = (seed & 0xFFFF);
dwCryptTable[index2] = (temp1 | temp2);
}
}
}
void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
assert(lpbyBuffer);
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = *lpdwBuffer + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
assert(lpbyBuffer);
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = ch + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
3.2 HASHING
Based on code from StormLib.
// Different types of hashes to make with HashString
#define MPQ_HASH_TABLE_OFFSET 0
#define MPQ_HASH_NAME_A 1
#define MPQ_HASH_NAME_B 2
#define MPQ_HASH_FILE_KEY 3
unsigned long HashString(const char *lpszString, unsigned long dwHashType)
{
unsigned long seed1 = 0x7FED7FED;
unsigned long seed2 = 0xEEEEEEEE;
int ch;
while (*lpszString != 0)
{
ch = toupper(*lpszString++);
seed1 = dwCryptTable[(dwHashType * 0xFF) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
3.3 CONVERSION OF FILETIME AND time_t
#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
bool GetTimeFromFileTime(FILETIME &fileTime, time_t &time)
{
// The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
if (nTime < EPOCH_OFFSET)
return false;
nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
nTime /= 10000000ULL; // Convert 100 ns to sec
time = (time_t)nTime;
// Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
if ((nTime - (unsigned long long)time) > 0)
return false;
return true;
}
void GetFileTimeFromTime(time_t &time, FILETIME &fileTime)
{
unsigned long long nTime = (unsigned long long)time;
nTime *= 10000000ULL;
nTime += EPOCH_OFFSET;
fileTime.dwLowDateTime = (DWORD)nTime;
fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
}

View file

@ -0,0 +1,421 @@
THE MOPAQ ARCHIVE FORMAT
v1.0 (Friday, September 1, 2006)
by Justin Olbrantz(Quantam)
Distribution and reproduction of this specification are allowed without limitation, as long as it is not altered. Quotation in other works is freely allowed, as long as the source and author of the quote are stated.
TABLE OF CONTENTS
1. Introduction to the MoPaQ Format
2. The MoPaQ Format
2.1 General Archive Layout
2.2 Archive Header
2.3 Block Table
2.4 Extended Block Table
2.5 Hash Table
2.6 File Data
2.7 Listfile
2.8 Extended Attributes
2.9 Weak (Old) Digital Signature
2.10 Strong (New) Digital Signature
3. Algorithm Source Code
3.1 Encryption/Decryption
3.2 Hashing and File Key Computation
3.3 Finding Files
3.4 Deleting Files
3.5 Conversion of FILETIME and time_t
3.6 Forming a 64-bit Large Archive Offset from 32-bit and 16-bit Components
4. Revision History
1. INTRODUCTION TO THE MOPAQ FORMAT
The MoPaQ (or MPQ) format is an archive file format designed by Mike O'Brien (hence the name Mike O'brien PaCK) at Blizzard Entertainment. The format has been used in all Blizzard games since (and including) Diablo. It is heavily optimized to be a read-only game archive format, and excels at this role.
The Blizzard MoPaQ-reading functions are contained in the Storm module, which my be either statically or dynamically linked. The Blizzard MoPaQ-writing functions are contained in the MPQAPI module, which is always statically linked.
StormLib - mentioned several times in this specification - is an open-source MoPaQ reading and writing library written by Ladislav Zezula (no affiliation with Blizzard Entertainment). While it's a bit dated, and does not support all of the newer MoPaQ features, it contains source code to the more exotic compression methods used by MoPaQ, such as the PKWare implode algorithm, MoPaQ's huffman compression algorithm, and the IMA ADPCM compression used by MoPaQ.
2. THE MOPAQ FORMAT
All numbers in the MoPaQ format are in little endian byte order; signed numbers use the two's complement system. Data types are listed either as int (integer, the number of bits specified), byte (8 bits), or char (bytes which contain ASCII characters). All sizes and offsets are in bytes, unless specified otherwise. Structure members are listed in the following general form:
offset from the beginning of the structure: data type(array size) member name : member description
2.1 GENERAL ARCHIVE LAYOUT
- Archive Header
- File Data
- File Data - Special Files
- Hash Table
- Block Table
- Extended Block Table
- Strong Digital signature
This is the usual archive format, but it is not mandatory. Some archives have been observed placing the hash table and file table after the archive header, and before the file data.
2.2 ARCHIVE HEADER
00h: char(4) Magic : Indicates that the file is a MoPaQ archive. Must be ASCII "MPQ" 1Ah.
04h: int32 HeaderSize : Size of the archive header.
08h: int32 ArchiveSize : Size of the whole archive, including the header. Does not include the strong digital signature, if present. This size is used, among other things, for determining the region to hash in computing the digital signature. This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive is calculated as the size from the beginning of the archive to the end of the hash table, block table, or extended block table (whichever is largest).
0Ch: int16 FormatVersion : MoPaQ format version. MPQAPI will not open archives where this is negative. Known versions:
0000h: Original format. HeaderSize should be 20h, and large archives are not supported.
0001h: Burning Crusade format. Header size should be 2Ch, and large archives are supported.
0Eh: int8 SectorSizeShift : Power of two exponent specifying the number of 512-byte disk sectors in each logical sector in the archive. The size of each logical sector in the archive is 512 * 2^SectorSizeShift. Bugs in the Storm library dictate that this should always be 3 (4096 byte sectors).
10h: int32 HashTableOffset : Offset to the beginning of the hash table, relative to the beginning of the archive.
14h: int32 BlockTableOffset : Offset to the beginning of the block table, relative to the beginning of the archive.
18h: int32 HashTableEntries : Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for the original MoPaQ format, or less than 2^20 for the Burning Crusade format.
1Ch: int32 BlockTableEntries : Number of entries in the block table.
Fields only present in the Burning Crusade format and later:
20h: int64 ExtendedBlockTableOffset : Offset to the beginning of the extended block table, relative to the beginning of the archive.
28h: int16 HashTableOffsetHigh : High 16 bits of the hash table offset for large archives.
2Ah: int16 BlockTableOffsetHigh : High 16 bits of the block table offset for large archives.
The archive header is the first structure in the archive, at archive offset 0; however, the archive does not need to be at offset 0 of the containing file. The offset of the archive in the file is referred to here as ArchiveOffset. If the archive is not at the beginning of the file, it must begin at a disk sector boundary (512 bytes). Early versions of Storm require that the archive be at the end of the containing file (ArchiveOffset + ArchiveSize = file size), but this is not required in newer versions (due to the strong digital signature not being considered a part of the archive).
2.3 BLOCK TABLE
The block table contains entries for each region in the archive. Regions may be either files, empty space, which may be overwritten by new files (typically this space is from deleted file data), or unused block table entries. Empty space entries should have BlockOffset and BlockSize nonzero, and FileSize and Flags zero; unused block table entries should have BlockSize, FileSize, and Flags zero. The block table is encrypted, using the hash of "(block table)" as the key. Each entry is structured as follows:
00h: int32 BlockOffset : Offset of the beginning of the block, relative to the beginning of the archive.
04h: int32 BlockSize : Size of the block in the archive.
08h: int32 FileSize : Size of the file data stored in the block. Only valid if the block is a file; otherwise meaningless, and should be 0. If the file is compressed, this is the size of the uncompressed file data.
0Ch: int32 Flags : Bit mask of the flags for the block. The following values are conclusively identified:
80000000h: Block is a file, and follows the file data format; otherwise, block is free space or unused. If the block is not a file, all other flags should be cleared, and FileSize should be 0.
01000000h: File is stored as a single unit, rather than split into sectors.
00020000h: The file's encryption key is adjusted by the block offset and file size (explained in detail in the File Data section). File must be encrypted.
00010000h: File is encrypted.
00000200h: File is compressed. File cannot be imploded.
00000100h: File is imploded. File cannot be compressed.
2.4 EXTENDED BLOCK TABLE
The extended block table was added to support archives larger than 4 gigabytes (2^32 bytes). The table contains the upper bits of the archive offsets for each block in the block table. It is simply an array of int16s, which become bits 32-47 of the archive offsets for each block, with bits 48-63 being zero. Individual blocks in the archive are still limited to 4 gigabytes in size. This table is only present in Burning Crusade format archives that exceed 4 gigabytes size.
As of the Burning Crusade Friends and Family beta, this table is not encrypted.
2.5 HASH TABLE
Instead of storing file names, for quick access MoPaQs use a fixed, power of two-size hash table of files in the archive. A file is uniquely identified by its file path, its language, and its platform. The home entry for a file in the hash table is computed as a hash of the file path. In the event of a collision (the home entry is occupied by another file), progressive overflow is used, and the file is placed in the next available hash table entry. Searches for a desired file in the hash table proceed from the home entry for the file until either the file is found, the entire hash table is searched, or an empty hash table entry (FileBlockIndex of FFFFFFFFh) is encountered. The hash table is encrypted using the hash of "(hash table)" as the key. Each entry is structured as follows:
00h: int32 FilePathHashA : The hash of the file path, using method A.
04h: int32 FilePathHashB : The hash of the file path, using method B.
08h: int16 Language : The language of the file. This is a Windows LANGID data type, and uses the same values. 0 indicates the default language (American English), or that the file is language-neutral.
0Ah: int8 Platform : The platform the file is used for. 0 indicates the default platform. No other values have been observed.
0Ch: int32 FileBlockIndex : If the hash table entry is valid, this is the index into the block table of the file. Otherwise, one of the following two values:
FFFFFFFFh: Hash table entry is empty, and has always been empty. Terminates searches for a given file.
FFFFFFFEh: Hash table entry is empty, but was valid at some point (in other words, the file was deleted). Does not terminate searches for a given file.
2.6 FILE DATA
The data for each file is composed of the following structure:
00h: int32(SectorsInFile + 1) SectorOffsetTable : Offsets to the start of each sector, relative to the beginning of the file data. The last entry contains the file size, making it possible to easily calculate the size of any given sector. This table is not present if this information can be calculated (see details below).
immediately following SectorOffsetTable: SECTOR Sectors(SectorsInFile) : Data of each sector in the file, packed end to end (see details below).
Normally, file data is split up into sectors, for simple streaming. All sectors, save for the last, will contain as many bytes of file data as specified in the archive header's SectorSizeShift; the last sector may contain less than this, depending on the size of the entire file's data. If the file is compressed or imploded, the sector will be smaller or the same size as the file data it contains. Individual sectors in a compressed or imploded file may be stored uncompressed; this occurs if and only if the file data the sector contains could not be compressed by the algorithm(s) used (if the compressed sector size was greater than or equal to the size of the file data), and is indicated by the sector's size in SectorOffsetTable being equal to the size of the file data in the sector (which may be calculated from the FileSize).
The format of each sector depends on the kind of sector it is. Uncompressed sectors are simply the the raw file data contained in the sector. Imploded sectors are the raw compressed data following compression with the implode algorithm (these sectors can only be in imploded files). Compressed sectors (only found in compressed - not imploded - files) are compressed with one or more compression algorithms, and have the following structure:
00h: byte CompressionMask : Mask of the compression types applied to this sector. If multiple compression types are used, they are applied in the order listed below, and decompression is performed in the opposite order. This byte counts towards the total sector size, meaning that the sector will be stored uncompressed if the data cannot be compressed by at least two bytes; as well, this byte is encrypted with the sector data, if applicable. The following compression types are defined (for implementations of these algorithms, see StormLib):
40h: IMA ADPCM mono
80h: IMA ADPCM stereo
01h: Huffman encoded
02h: Deflated (see ZLib)
08h: Imploded (see PKWare Data Compression Library)
10h: BZip2 compressed (see BZip2)
01h: byte(SectorSize - 1) SectorData : The compressed data for the sector.
If the file is stored as a single unit (indicated in the file's Flags), there is effectively only a single sector, which contains the entire file data.
If the file is encrypted, each sector (after compression/implosion, if applicable) is encrypted with the file's key. The base key for a file is determined by a hash of the file name stripped of the directory (i.e. the key for a file named "directory\file" would be computed as the hash of "file"). If this key is adjusted, as indicated in the file's Flags, the final key is calculated as ((base key + BlockOffset - ArchiveOffset) XOR FileSize) (StormLib incorrectly uses an AND in place of the XOR). Each sector is encrypted using the key + the 0-based index of the sector in the file. The SectorOffsetTable, if present, is encrypted using the key - 1.
The SectorOffsetTable is omitted when the sizes and offsets of all sectors in the file are calculatable from the FileSize. This can happen in several circumstances. If the file is not compressed/imploded, then the size and offset of all sectors is known, based on the archive's SectorSizeShift. If the file is stored as a single unit compressed/imploded, then the SectorOffsetTable is omitted, as the single file "sector" corresponds to BlockSize and FileSize, as mentioned previously. However, the SectorOffsetTable will be present if the file is compressed/imploded and the file is not stored as a single unit, even if there is only a single sector in the file (the size of the file is less than or equal to the archive's sector size).
2.7 LISTFILE
The listfile is a very simple extension to the MoPaQ format that contains the file paths of (most) files in the archive. The languages and platforms of the files are not stored in the listfile. The listfile is contained in the file "(listfile)" (default language and platform), and is simply a text file with file paths separated by ';', 0Dh, 0Ah, or some combination of these. The file "(listfile)" may not be listed in the listfile.
2.8 EXTENDED ATTRIBUTES
The extended attributes are optional file attributes for files in the block table. These attributes were added at times after the MoPaQ format was already finalized, and it is not necessary for every archive to have all (or any) of the extended attributes. If an archive contains a given attribute, there will be an instance of that attribute for every block in the block table, although the attribute will be meaningless if the block is not a file. The order of the attributes for blocks correspond to the order of the blocks in the block table, and are of the same number. The attributes are stored in parallel arrays in the "(attributes)" file (default language and platform), in the archive. The attributes corresponding to this file need not be valid (and logically cannot be). Unlike all the other structures in the MoPaQ format, entries in the extended attributes are NOT guaranteed to be aligned. Also note that in some archives, malicious zeroing of the attributes has been observed, perhaps with the intent of breaking archive viewers. This file is structured as follows:
00h: int32 Version : Specifies the extended attributes format version. For now, must be 100.
04h: int32 AttributesPresent : Bit mask of the extended attributes present in the archive:
00000001h: File CRC32s.
00000002h: File timestamps.
00000004h: File MD5s.
08h: int32(BlockTableEntries) CRC32s : CRC32s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have CRC32s.
immediately after CRC32s: FILETIME(BlockTableEntries) Timestamps : Timestamps for each block in the archive. The format is that of the Windows FILETIME structure. Omitted if the archive does not have timestamps.
immediately after Timestamps: MD5(BlockTableEntries) MD5s : MD5s of the (uncompressed) file data for each block in the archive. Omitted if the archive does not have MD5s.
2.9 WEAK DIGITAL SIGNATURE
The weak digital signature is a digital signature using Microsoft CryptoAPI. It is an implimentation of the RSASSA-PKCS1-v1_5 digital signature protocol, using the MD5 hashing algorithm and a 512-bit (weak) RSA key (for more information about this protocol, see the RSA Labs PKCS1 specification). The public key and exponent are stored in a resource in Storm, the private key is stored in a separate file, whose filename is passed to MPQAPI (the private key is not stored in MPQAPI). The signature is stored uncompressed, unencrypted in the file "(signature)" (default language and platform) in the archive. The archive is hashed from the beginning of the archive (ArchiveOffset in the containing file) to the end of the archive (the length indicated by ArchiveSize, or calculated in the Burning Crusade MoPaQ format); the signature file is added to the archive before signing, and the space occupied by the file is considered to be all binary 0s during signing/verification. This file is structured as follows:
00h: int32 Unknown : Must be 0.
04h: int32 Unknown : Must be 0.
08h: int512 Signature : The digital signature. Like all other numbers in the MoPaQ format, this is stored in little-endian order. The structure of this, when decrypted, follows the RSASSA-PKCS1-v1_5 specification; this format is rather icky to work with (I wrote a program to verify this signature using nothing but an MD5 function and huge integer functions; it wasn't pleasant), and best left to an encryption library such as Cryto++.
2.10 STRONG DIGITAL SIGNATURE
The strong digital signature uses a simple proprietary implementation of RSA signing, using the SHA-1 hashing algorithm and a 2048-bit (strong) RSA key. The default public key and exponent are stored in Storm, but other keys may be used as well. The strong digital signature is stored immediately after the archive, in the containing file; the entire archive (ArchiveSize bytes, starting at ArchiveOffset in the containing file) is hashed as a single block. The signature has the following format:
00h: char(4) Magic : Indicates the presence of a digital signature. Must be "NGIS" ("SIGN" backwards).
04h: int2048 Signature : The digital signature, stored in little-endian format.
When the Signature field is decrypted with the public key and exponent, and the resulting large integer is stored in little-endian order, it is structured as follows:
00h: byte Padding : Must be 0Bh.
01h: byte(235) Padding : Must be BBh.
ECh: byte(20) SHA-1 : SHA-1 hash of the archive, in standard SHA-1 byte order.
3. ALGORITHM SOURCE CODE
All of the sample code here assumes little endian machine byte order, that the short type is 16 bits, that the long type is 32 bits, and that the long long type is 64 bits. Adjustments must be made if these assumptions are not correct on a given platform. All code not credited otherwise was written by myself in the writing of this specification.
3.1 ENCRYPTION/DECRYPTION
Based on code from StormLib.
unsigned long dwCryptTable[0x500];
// The encryption and hashing functions use a number table in their procedures. This table must be initialized before the functions are called the first time.
void InitializeCryptTable()
{
unsigned long seed = 0x00100001;
unsigned long index1 = 0;
unsigned long index2 = 0;
int i;
for (index1 = 0; index1 < 0x100; index1++)
{
for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
{
unsigned long temp1, temp2;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp1 = (seed & 0xFFFF) << 0x10;
seed = (seed * 125 + 3) % 0x2AAAAB;
temp2 = (seed & 0xFFFF);
dwCryptTable[index2] = (temp1 | temp2);
}
}
}
void EncryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
assert(lpbyBuffer);
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEE;
unsigned long ch;
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
seed = *lpdwBuffer + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
void DecryptData(void *lpbyBuffer, unsigned long dwLength, unsigned long dwKey)
{
assert(lpbyBuffer);
unsigned long *lpdwBuffer = (unsigned long *)lpbyBuffer;
unsigned long seed = 0xEEEEEEEEL;
unsigned long ch;
dwLength /= sizeof(unsigned long);
while(dwLength-- > 0)
{
seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
ch = *lpdwBuffer ^ (dwKey + seed);
dwKey = ((~dwKey << 0x15) + 0x11111111L) | (dwKey >> 0x0B);
seed = ch + seed + (seed << 5) + 3;
*lpdwBuffer++ = ch;
}
}
3.2 HASHING AND FILE KEY COMPUTATION
These functions may have been derived from StormLib code at some point in the very distant past. It was so long ago that I don't remember for certain.
// Different types of hashes to make with HashString
#define MPQ_HASH_TABLE_OFFSET 0
#define MPQ_HASH_NAME_A 1
#define MPQ_HASH_NAME_B 2
#define MPQ_HASH_FILE_KEY 3
// Based on code from StormLib.
unsigned long HashString(const char *lpszString, unsigned long dwHashType)
{
assert(lpszString);
assert(dwHashType <= MPQ_HASH_FILE_KEY);
unsigned long seed1 = 0x7FED7FEDL;
unsigned long seed2 = 0xEEEEEEEEL;
int ch;
while (*lpszString != 0)
{
ch = toupper(*lpszString++);
seed1 = dwCryptTable[(dwHashType * 0x100) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
#define BLOCK_OFFSET_ADJUSTED_KEY 0x00020000L
unsigned long ComputeFileKey(const char *lpszFilePath, const BlockTableEntry &blockEntry, unsigned long nArchiveOffset)
{
assert(lpszFilePath);
// Find the file name part of the path
const char *lpszFileName = strrchr(lpszFilePath, '\\');
if (lpszFileName)
lpszFileName++; // Skip the \
else
lpszFileName = lpszFilePath;
// Hash the name to get the base key
unsigned long nFileKey = HashString(lpszFileName, MPQ_HASH_FILE_KEY);
// Offset-adjust the key if necessary
if (blockEntry.Flags & BLOCK_OFFSET_ADJUSTED_KEY)
nFileKey = (nFileKey + blockEntry.BlockOffset) ^ blockEntry.FileSize;
return nFileKey;
}
3.3 FINDING FILES
#define MPQ_HASH_ENTRY_EMPTY 0xFFFFFFFFL
#define MPQ_HASH_ENTRY_DELETED 0xFFFFFFFEL
bool FindFileInHashTable(const HashTableEntry *lpHashTable, unsigned long nHashTableSize, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform, unsigned long &iFileHashEntry)
{
assert(lpHashTable);
assert(nHashTableSize);
assert(lpszFilePath);
// Find the home entry in the hash table for the file
unsigned long iInitEntry = HashString(lpszFilePath, MPQ_HASH_TABLE_OFFSET) & (nHashTableSize - 1);
// Is there anything there at all?
if (lpHashTable[iInitEntry].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
return false;
// Compute the hashes to compare the hash table entry against
unsigned long nNameHashA = HashString(lpszFilePath, MPQ_HASH_NAME_A),
nNameHashB = HashString(lpszFilePath, MPQ_HASH_NAME_B),
iCurEntry = iInitEntry;
// Check each entry in the hash table till a termination point is reached
do
{
if (lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_DELETED)
{
if (lpHashTable[iCurEntry].FilePathHashA == nNameHashA
&& lpHashTable[iCurEntry].FilePathHashB == nNameHashB
&& lpHashTable[iCurEntry].Language == nLang
&& lpHashTable[iCurEntry].Platform == nPlatform)
{
iFileHashEntry = iCurEntry;
return true;
}
}
iCurEntry = (iCurEntry + 1) & (nHashTableSize - 1);
} while (iCurEntry != iInitEntry && lpHashTable[iCurEntry].FileBlockIndex != MPQ_HASH_ENTRY_EMPTY);
return false;
}
3.4 DELETING FILES
bool DeleteFile(HashTableEntry *lpHashTable, unsigned long nHashTableSize, BlockTableEntry *lpBlockTable, const char *lpszFilePath, unsigned short nLang, unsigned char nPlatform)
{
assert(lpHashTable);
assert(nHashTableSize);
assert(lpBlockTable);
// Find the file in the hash table
unsigned long iFileHashEntry;
if (!FindFileInHashTable(lpHashTable, nHashTableSize, lpszFilePath, nLang, nPlatform, iFileHashEntry))
return false;
// Get the block table index before we nuke the hash table entry
unsigned long iFileBlockEntry = lpHashTable[iFileHashEntry].FileBlockIndex;
// Delete the file's entry in the hash table
memset(&lpHashTable[iFileHashEntry], 0xFF, sizeof(HashTableEntry));
// If the next entry is empty, mark this one as empty; otherwise, mark this as deleted.
if (lpHashTable[(iFileHashEntry + 1) & (nHashTableSize - 1)].FileBlockIndex == MPQ_HASH_ENTRY_EMPTY)
lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_EMPTY;
else
lpHashTable[iFileHashEntry].FileBlockIndex = MPQ_HASH_ENTRY_DELETED;
// If the block occupies space, mark the block as free space; otherwise, clear the block table entry.
if (lpBlockTable[iFileBlockEntry].BlockSize > 0)
{
lpBlockTable[iFileBlockEntry].FileSize = 0;
lpBlockTable[iFileBlockEntry].Flags = 0;
}
else
memset(&lpBlockTable[iFileBlockEntry], 0, sizeof(BlockTableEntry);
return true;
}
3.5 CONVERSION OF FILETIME AND time_t
This code assumes that the base ("zero") date for time_t is 01/01/1970. This is true on Windows, Unix System V systems, and Mac OS X. It is unknown whether this is true on all other platforms. You'll need to research this yourself, if you plan on porting it somewhere else.
#define EPOCH_OFFSET 116444736000000000ULL // Number of 100 ns units between 01/01/1601 and 01/01/1970
bool GetTimeFromFileTime(const FILETIME &fileTime, time_t &time)
{
// The FILETIME represents a 64-bit integer: the number of 100 ns units since January 1, 1601
unsigned long long nTime = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
if (nTime < EPOCH_OFFSET)
return false;
nTime -= EPOCH_OFFSET; // Convert the time base from 01/01/1601 to 01/01/1970
nTime /= 10000000ULL; // Convert 100 ns to sec
time = (time_t)nTime;
// Test for overflow (FILETIME is 64 bits, time_t is 32 bits)
if ((nTime - (unsigned long long)time) > 0)
return false;
return true;
}
void GetFileTimeFromTime(const time_t &time, FILETIME &fileTime)
{
unsigned long long nTime = (unsigned long long)time;
nTime *= 10000000ULL;
nTime += EPOCH_OFFSET;
fileTime.dwLowDateTime = (DWORD)nTime;
fileTime.dwHighDateTime = (DWORD)(nTime >> 32);
}
3.6 FORMING A 64-BIT LARGE ARCHIVE OFFSET FROM 32-BIT AND 16-BIT COMPONENTS
unsigned long long MakeLargeArchiveOffset(unsigned long nOffsetLow, unsigned short nOffsetHigh)
{
return ((unsigned long long)nOffsetHigh << 32) + (unsigned long long)nOffsetLow;
}
4. REVISION HISTORY
1.0
- Updated to include most of the changes found in the Burning Crusade Friends and Family beta
0.91.
- Updated several structure member descriptions
- Listed the full set of characters that can separate list file entries
- Noted that (attributes), (listfile), and (signature) use the default language and platform codes
- Redid part of the file data specs to clarify the format of sectors
- Enhanced descriptions of the different kinds of block table entries
- Added ComputeFileKey, FindFileInHashTable, and DeleteFile source

View file

@ -0,0 +1,117 @@
/*****************************************************************************/
/* Storm.cpp Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* This is just a dummy module for building import library for Storm.dll */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 11.04.03 1.00 Lad The first version of Storm.cpp */
/*****************************************************************************/
#include <windows.h>
#define BUILDING_STORM_CPP
#define STORM_ALTERNATE_NAMES
#include "StormDll.h"
BOOL WINAPI SFILE(OpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, HANDLE *hMPQ)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(CloseArchive)(HANDLE hMPQ)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(GetArchiveName)(HANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(OpenFile)(LPCSTR lpFileName, HANDLE *hFile)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(OpenFileEx)(HANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, HANDLE *hFile)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(CloseFile)(HANDLE hFile)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
DWORD WINAPI SFILE(GetFileSize)(HANDLE hFile, LPDWORD lpFileSizeHigh)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(GetFileArchive)(HANDLE hFile, HANDLE *hMPQ)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(GetFileName)(HANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
DWORD WINAPI SFILE(SetFilePointer)(HANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(ReadFile)(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
LCID WINAPI SFILE(SetLocale)(LCID nNewLocale)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(GetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(SetBasePath)(LPCSTR lpNewBasePath)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SFILE(Destroy)()
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SCOMP(Compress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCmp, int uCmpType, int nCmpLevel)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
BOOL WINAPI SCOMP(Decompress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}

View file

@ -0,0 +1,25 @@
; Storm definition file with alternate Storm.dll names
LIBRARY "Storm"
EXPORTS
StormCloseArchive @252 ; 0x0FC
StormCloseFile @253 ; 0x0FD
StormDestroy @262 ; 0x106
StormGetFileArchive @264 ; 0x108
StormGetFileSize @265 ; 0x109
StormOpenArchive @266 ; 0x10A
StormOpenFile @267 ; 0x10B
StormOpenFileEx @268 ; 0x10C
StormReadFile @269 ; 0x10D
StormSetBasePath @270 ; 0x10E
StormSetFilePointer @271 ; 0x10F
StormSetLocale @272 ; 0x110
StormGetBasePath @273 ; 0x111
StormGetArchiveName @275 ; 0x113
StormGetFileName @276 ; 0x114
; StormSetLastError @465 ; 0x
StormCompress @551 ; 0x227
StormDecompress @552 ; 0x228

View file

@ -0,0 +1,67 @@
/*****************************************************************************/
/* Storm.h Copyright Justin Olbrantz(Quantam) 2000 */
/*---------------------------------------------------------------------------*/
/* Storm Interface Library v1.0 for Windows */
/* */
/* Author : Justin Olbrantz(Quantam) */
/* E-mail : omega@dragonfire.net */
/* WWW : www.campaigncreations.com/starcraft/mpq2k/inside_mopaq/ */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* xx.xx.00 1.00 Qua The first version of Storm.h */
/* 11.04.03 1.00 Lad Added some functions */
/*****************************************************************************/
// We need the Windows data types for the Storm prototypes
#include <windows.h>
#ifndef __STORM_H__
#define __STORM_H__
// Somethimes is necessary to change the function names so they
// will not conflict with other MPQ tools.
#ifdef STORM_ALTERNATE_NAMES
#define SFILE(Name) Storm##Name
#define SCOMP(Name) Storm##Name
#else
#define SFILE(Name) SFile##Name
#define SCOMP(Name) SComp##Name
#endif
// Just in case anyone is still using C out there
#ifdef __cplusplus
extern "C" {
#endif
// Storm file function prototypes
BOOL WINAPI SFILE(OpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, HANDLE *hMPQ);
BOOL WINAPI SFILE(CloseArchive)(HANDLE hMPQ);
BOOL WINAPI SFILE(GetArchiveName)(HANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength);
BOOL WINAPI SFILE(OpenFile)(LPCSTR lpFileName, HANDLE *hFile);
BOOL WINAPI SFILE(OpenFileEx)(HANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, HANDLE *hFile);
BOOL WINAPI SFILE(CloseFile)(HANDLE hFile);
DWORD WINAPI SFILE(GetFileSize)(HANDLE hFile, LPDWORD lpFileSizeHigh);
BOOL WINAPI SFILE(GetFileArchive)(HANDLE hFile, HANDLE *hMPQ);
BOOL WINAPI SFILE(GetFileName)(HANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength);
DWORD WINAPI SFILE(SetFilePointer)(HANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
BOOL WINAPI SFILE(ReadFile)(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
LCID WINAPI SFILE(SetLocale)(LCID nNewLocale);
BOOL WINAPI SFILE(GetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength);
BOOL WINAPI SFILE(SetBasePath)(LPCSTR lpNewBasePath);
// Storm (de)compression functions
BOOL WINAPI SCOMP(Compress) (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCmp, int uCmpType, int nCmpLevel);
BOOL WINAPI SCOMP(Decompress)(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength);
#if defined(_MSC_VER) && !defined(BUILDING_STORM_CPP)
#pragma comment(lib, "Storm.lib") // Force linking Storm.lib and thus Storm.dll
#endif
#ifdef __cplusplus
}
#endif
#endif // __STORM_H__

View file

@ -0,0 +1,697 @@
/***********************************************************************
*
* Description: GfxDecode -- functions for reading Diablo's GFX files
* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de>
* Created at: Son Jan 27 15:20:43 CET 2002
* Computer: hangloose.flachland-chemnitz.de
* System: Linux 2.4.16 on i686
*
* Copyright (c) 2002 BMX-Chemnitz.DE All rights reserved.
*
* ---------------------------------------------------------------------
* included are functions for getting:
* - the framecount of .CEL-files -> celGetFrameCount()
* - single frames of .CEL-files -> celGetFrameData()
* - the framecount of .CL2-files -> cl2GetFrameCount()
* - single directions of .CL2-files (all frames) -> cl2GetDirData()
* - single .PCX-files (256 color; v2, v5) -> pcxGetData()
***********************************************************************/
#include <vector>
#include <cmath>
#include <iostream>
#include "StormLib.h"
#define TRANS_COL 256
using std::cerr;
using std::vector;
/****** RAMP stuff *****************************************************
* for a more detailed description/explanation see below
***********************************************************************/
// two variations: one/two ramp(s)
static const uint16_t c_2RampSize = 544; // the frame size
static const uint16_t c_1RampSize = 800; // the frame size
// ramps (both variations) can be either left or right
static const uint16_t c_RampOffsetLeft[17] = {
0, // __
8, // + 8 note that this __--
24, // + 16 "drawing" is __--
48, // + 24 upside down! __-- this area
80, // + 32 __-- is always
120, // + 40 __-- colored
168, // + 48 __--
224, // + 56 __-- lower ramp ends here (+30 == 254)
288, // + 64 --__ upper ramp might be missing
348, // + 60 | --__
400, // + 52 | --__ this area
444, // + 44 | --__ is always
480, // + 36 | --__ colored
508, // + 28 | either trans- --__
528, // + 20 | parent or colored --__
540, // + 12 | --__ +2 Pixels = 544
542 // + 2 | this last one doesn't exist, it's those^ 2 pixels
};
static const uint16_t c_RampOffsetRight[17] = {
2, // __ before this, there are 2 Pixels
14, // + 12 --__ 4^2 - 2
34, // + 20 --__ 6^2 - 2
62, // + 28 this area --__ 8^2 - 2
98, // + 36 is always --__ 10^2 - 2 pattern anyone? ;)
142, // + 44 colored --__
194, // + 52 --__
254, // + 60 lower ramp ends here --__ (-30 == 224)
318, // + 64 upper ramp might be missing __--
374, // + 56 __-- |
422, // + 48 this area __-- | note that this
462, // + 40 is always __-- | "drawing"
494, // + 32 colored __-- eiter trans- | is upside down!
518, // + 24 __-- parent or colored |
534, // + 16 __-- |
542, // + 8 __-- +2 Startpixels = 544 |
542 // + 0 this last one doesn't exist, it | would be EOF
};
/****** FrameBuffer class **********************************************
* holds buffers and size information of the actual target image
* purpose: buffer management and avoidance of ugly globals
**********************************************************************/
class FrameBuf
{
protected:
vector <uint8_t *> vecData;
uint8_t *pCurrRow;
uint8_t *pPalette;
uint16_t uRows;
uint16_t *upYSize;
uint16_t *upMaxX;
public:
uint16_t uCols;
uint16_t uXSize;
uint16_t uMaxBlock;
uint16_t uFrameNum;
bool bHasBlocks;
bool bHasRamps;
FrameBuf(
uint8_t *pPal=NULL, uint16_t frame=0, uint16_t xsize=0,
uint16_t *pysize=NULL, uint16_t *pmaxx=NULL, uint16_t maxblock=0)
{
pCurrRow = new uint8_t[4*xsize];
pPalette = pPal;
uCols = 0;
uRows = 0;
uXSize = xsize;
uFrameNum = frame;
uMaxBlock = maxblock;
upYSize = pysize;
upMaxX = pmaxx;
bHasBlocks= false;
bHasRamps = false;
}
~FrameBuf()
{
delete[] pCurrRow;
for (vector <uint8_t *>::iterator vi=vecData.begin(); vi!=vecData.end(); vi++)
delete[] *vi;
vecData.clear();
}
void addLine()
{
++uRows;
uCols = 0;
vecData.push_back(pCurrRow);
pCurrRow = new uint8_t[4*uXSize];
}
void addPixel(uint16_t uColorNum)
{
if (uColorNum > TRANS_COL) {
cerr << "\n*** there seemed to be an error, illegal color index " << uColorNum;
cerr << "\n +++ at (" << uCols << "," << uRows << "), see for yourself *** \n\n";
uColorNum = TRANS_COL; // sane setting to avoid segfaults
}
memcpy(pCurrRow + 4*uCols, pPalette + 4*uColorNum, 4*sizeof(uint8_t));
if (++uCols == uXSize)
addLine();
else if ((uColorNum != TRANS_COL) && (upMaxX != NULL) && (uCols > *upMaxX))
*upMaxX = uCols;
}
// used to return the actual image data
uint8_t *getData()
{
uint16_t i;
vector <uint8_t *>::reverse_iterator vri;
// allocate a buffer to hold the actual image size
uint8_t *tmp = new uint8_t[4*uXSize*uRows];
// the lines are upside down inside the vector, use reverse iterator
for (i=0, vri=vecData.rbegin(); vri!=vecData.rend(); vri++, i++)
memcpy(tmp+4*uXSize*i, *vri, 4*uXSize*sizeof(uint8_t));
*upYSize = uRows; // set height
if (uCols > 0) {
cerr << "\n*** there seemed to be an error (last line does not match boundary, " << uCols << " pixels left)";
cerr << "\n +++ this is often caused by specifying an invalid width, see for yourself *** \n\n";
}
return tmp;
}
};
uint16_t WINAPI celGetFrameCount(uint8_t *pFileBuf)
{
uint32_t tmp;
memcpy(&tmp, pFileBuf, sizeof(uint32_t));
return (uint16_t)tmp;
}
/***** Block Decoder ***************************************************
* one of three possible decoding techniques necessary for .cel
* possible block contents are either colored (in that case the
* appropriate number of pixels are read) or transparent pixels
* there are neither ramps nor plain pixels allowed here
***********************************************************************/
uint8_t *celDecodeBlocks(uint8_t *pFileBuf, FrameBuf *pFrame, uint32_t *framestart)
{
uint32_t uFilePos=framestart[pFrame->uFrameNum];
uint8_t cRead=0, i=0;
if (!pFrame->bHasBlocks) // sanity check
return NULL;
while (uFilePos < framestart[pFrame->uFrameNum+1]) {
cRead = pFileBuf[uFilePos++];
if ((uFilePos == framestart[pFrame->uFrameNum]+1))
// TODO: what is this 0x0A 0x00 stuff all about?
if ((cRead == 0x0A) && (pFileBuf[uFilePos] == 0x00)) {
uFilePos += 9;
cRead = pFileBuf[uFilePos++];
}
if (cRead > 0x7F)
// transparent block (complement, 256-val)
for (i=0; i<256-cRead; i++)
pFrame->addPixel(TRANS_COL);
else if (cRead < pFrame->uMaxBlock + 1)
// pixel block (block size pixels to be read!)
for (i=0; i<cRead; i++)
pFrame->addPixel(pFileBuf[uFilePos++]);
else
cerr << "\n*** block mode: illegal block (> max_size) ***\n\n";
}
return pFrame->getData();
}
/***** Ramp Decoder ****************************************************
* the second of three possible decoding techniques necessary for .cel
* each block save the first/last is enclosed by two 0x00 pairs
* those blocks affect _TWO_ rows with one being 2 colored pixels shorter
* the first/last "block" affects only one row
***********************************************************************/
uint8_t *celDecodeRamps(uint8_t *pFileBuf, FrameBuf *pFrame, uint32_t *framestart, bool bLeft)
{
uint32_t uFrameLen = framestart[pFrame->uFrameNum+1]-framestart[pFrame->uFrameNum];
uint32_t uFilePos=0;
uint16_t uBlockLen=0, i=0, j=0;
bool bFirstLonger=false;
if (!pFrame->bHasRamps) // sanity check
return NULL;
if (pFrame->uXSize != 32) // only used in that case
return NULL;
if (!bLeft) { // get first two pixels for right side ramps
pFrame->addPixel(pFileBuf[framestart[pFrame->uFrameNum]]);
pFrame->addPixel(pFileBuf[framestart[pFrame->uFrameNum]+1]);
}
// do all the ramp blocks
for (i=0; i<(uFrameLen == c_2RampSize ? 15 : 7); i++) {
uBlockLen = (bLeft ? (c_RampOffsetLeft[i+1] - c_RampOffsetLeft[i]) : (c_RampOffsetRight[i+1] - c_RampOffsetRight[i]));
uFilePos = framestart[pFrame->uFrameNum] + (bLeft ? c_RampOffsetLeft[i] : c_RampOffsetRight[i]) + 2;
bFirstLonger = (i>(bLeft ? 7 : 6));
if (bLeft) {
// OK, first line, starting with transparency
for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 0 : 2); j++)
pFrame->addPixel(TRANS_COL);
// fill it up with the pixel block
for (j=0; j<uBlockLen/2 - (bFirstLonger ? 0 : 2); j++)
pFrame->addPixel(pFileBuf[uFilePos++]);
// second line, starting again with transparency
for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 2 : 0); j++)
pFrame->addPixel(TRANS_COL);
// fill the second line with the remaining pixels
for (j=0; j<uBlockLen/2 - (bFirstLonger ? 2 : 0); j++)
pFrame->addPixel(pFileBuf[uFilePos++]);
} else {
if (pFrame->uCols != 0) // fill current line with trans (if not empty)
for (j=pFrame->uXSize - pFrame->uCols; j>0; j--)
pFrame->addPixel(TRANS_COL);
// OK, insert the first pixels into a new line
for (j=0; j<uBlockLen/2 - (bFirstLonger ? 0 : 2); j++)
pFrame->addPixel(pFileBuf[uFilePos++]);
// fill the line with transparency
for (j=0; j<pFrame->uXSize - uBlockLen/2 + (bFirstLonger ? 0 : 2); j++)
pFrame->addPixel(TRANS_COL);
// start a second line with the remaining pixels
for (j=0; j<uBlockLen/2 - (bFirstLonger ? 2 : 0); j++)
pFrame->addPixel(pFileBuf[uFilePos++]);
}
}
// now read the last 0x00 pair and fill up
uBlockLen = (uFrameLen == c_2RampSize ? 30 : 2); // one or two ramps?
uFilePos = framestart[pFrame->uFrameNum] + (bLeft ? c_RampOffsetLeft[i] : c_RampOffsetRight[i]) + 2;
// the transparency for the last (single) 0x00 pair
for (j=0; j<uBlockLen; j++)
pFrame->addPixel(TRANS_COL);
if (bLeft) { // left side only: the remaining line
for (j=0; j<pFrame->uXSize - uBlockLen; j++)
pFrame->addPixel(pFileBuf[uFilePos++]);
}
// now the rest of the file (plain)
while (uFilePos < framestart[pFrame->uFrameNum+1])
pFrame->addPixel(pFileBuf[uFilePos++]);
// the uppermost line is emtpy when 2 ramps are used
if (uFrameLen == c_2RampSize)
for (j=0; j<pFrame->uXSize; j++)
pFrame->addPixel(TRANS_COL);
return pFrame->getData();
}
/***** celGetFrameData *************************************************
* decode .cel data for given frame and xsize
* Args:
* *vpFileBuf the buffer containing the filecontent
* *palette the palette (4 bytes for each of the 257 entries)
* 256 colors are needed + 1 for alpha
* uXSize this information must be given
* uFrameNume the frame to get
* *uYSize the actual value is returned therein
* *uMaxX this can be used (if != NULL) to get the column
* of the rightmost nontransparent pixel (useable
* eg for fonts)
*
* Returns: an array containing 4 Bytes (RGBA) for each pixel
*
* ---------------------------------------------------------------
* Comments: dirty hack, started from scratch @ 2000-10-11
* cleanly rewritten during incorporation into ladiks StormLib
* status: structured hack ;)
*
* It took me approx. 6 days to understand the format basics (hex viewer)
* For this I had a little help from a dos tool ("ddecode", from
* www.cowlevel.com, binary only, no sources) which, however, gave
* me the general idea what the pictures are actually supposed to look like.
*
* The fine adjustments, however, took quite some time and a little luck.
* After I had written to various people (mickyk and ladik), which could
* not help me, but wished best luck (thanks, btw, it helped ;)), I tried
* some reverse engineering which was not succesful in the end.
*
* I then had incidentally a new idea of what could be going on @ 2002-01-23.
* It just came to my mind that I could retry some actual painting in
* reverse order (had done that before to no avail) and when looking closer
* at it I realized the "ramp" stuff. This really is the trickiest part and
* it took me some eight days to implement it without breaking the other
* parts of the code. Very odd format indeed.
*
* TODO: learn what 0x0A 0x00 means
**********************************************************************/
uint8_t * WINAPI celGetFrameData(uint8_t *pFileBuf, uint8_t *palette, uint16_t uXSize, uint16_t uFrameNum, uint16_t *uYSize, uint16_t *uMaxX)
{
FrameBuf *pFrame;
uint32_t *framestart=NULL, frames=0, uFilePos=0;
uint16_t i, tmpWord=0;
uint8_t cRead=0, *data;
memcpy(&frames, pFileBuf, sizeof(uint32_t));
uFilePos += sizeof(uint32_t);
if (pFileBuf == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (palette == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uFrameNum > frames-1) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uYSize == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// in case we want to know the rightmost pixels column (usable eg. for fonts)
if (uMaxX != NULL)
*uMaxX = 0;
// get the frame offsets
framestart = new uint32_t[frames+1];
for (i=0; i<frames+1; i++) {
memcpy(&framestart[i], pFileBuf+uFilePos, sizeof(uint32_t));
uFilePos += sizeof(uint32_t);
}
/****** block size *************************************************
* depends on the image width
******************************/
double erg = rint(sqrt(pow(2, rint(log((double)(framestart[uFrameNum+1] - framestart[uFrameNum])) / log(2.0)))));
pFrame = new FrameBuf(palette, uFrameNum, uXSize, uYSize, uMaxX, max((uint16_t)min((int)erg, 0x7F), uXSize));
/****** ramp detection -- AFAIK only needed for 32x32 tiles ********
* here I use hard coded constants because this is the only simple
* way to get the detection done; plus this stuff is only to be
* found in such 32x32 (tile) files and so wont hurt anyone ;)
******************************************************************/
uint32_t uFrameLen = framestart[uFrameNum+1] - framestart[uFrameNum];
if ((uXSize == 32) && ((uFrameLen == c_2RampSize) || (uFrameLen == c_1RampSize))) {
// use the static arrays for the check
for (i=0; i<(uFrameLen == c_2RampSize ? 16 : 8); i++) {
memcpy(&tmpWord, pFileBuf+framestart[uFrameNum]+c_RampOffsetLeft[i], sizeof(uint16_t));
if (tmpWord != 0)
break;
}
bool bRampsLeft = pFrame->bHasRamps = (i==(uFrameLen == c_2RampSize ? 16 : 8));
if (!pFrame->bHasRamps) { // only one can apply
for (i=0; i<(uFrameLen == c_2RampSize ? 16 : 8); i++) {
memcpy(&tmpWord, pFileBuf+framestart[uFrameNum]+c_RampOffsetRight[i], sizeof(uint16_t));
if (tmpWord != 0)
break;
}
pFrame->bHasRamps = (i==(uFrameLen == c_2RampSize ? 16 : 8)); // bRampsLeft stays false in this case
}
if (pFrame->bHasRamps) { // decode ramps and be off (if appropriate)
data = celDecodeRamps(pFileBuf, pFrame, framestart, bRampsLeft);
delete pFrame;
delete[] framestart;
return data;
}
}
/*********** block detection ***************************************
* 0x0A as start byte seems to be sufficient (though I still dunno
* what the trailing 10 bytes mean); in any other case we act as if
* blocks were to be used and check afterwards if the image looks
* OK (that is, the last line has no pixels in it)
******************************************************************/
cRead = pFileBuf[framestart[uFrameNum]];
if (cRead == 0x0A) // sufficient
pFrame->bHasBlocks = true;
// if width == 32 && framelen == 32*32, assume plain
else if ((uXSize != 32) || (uFrameLen != 32*32)) { // check needed
uFilePos=framestart[uFrameNum];
i=0;
// rush through the frame
while (uFilePos < framestart[uFrameNum+1]) {
cRead = pFileBuf[uFilePos++];
// transparency blocks
while (cRead > 0x7F) {
i += 256-cRead;
i %= uXSize;
if (uFilePos < framestart[uFrameNum+1])
cRead = pFileBuf[uFilePos++];
else
cRead = 0;
}
// colored pixel block
if (uFilePos < framestart[uFrameNum+1]) {
if (cRead < pFrame->uMaxBlock + 1) {
i+=cRead;
i%=uXSize;
uFilePos+=cRead;
} else {
// when the value is out of valid blockrange
i=1; // trigger error (1%uXSize != 0)
break;
}
}
}
if (i%uXSize == 0) // looks as if we got it right
pFrame->bHasBlocks=true;
}
if (pFrame->bHasBlocks) { // use block decoder if appropriate
data = celDecodeBlocks(pFileBuf, pFrame, framestart);
delete pFrame;
delete[] framestart;
return data;
}
// plain mode (#3), read each color index and write the pixel
uFilePos=framestart[uFrameNum];
while (uFilePos < framestart[uFrameNum+1])
pFrame->addPixel(pFileBuf[uFilePos++]);
// cleanup, return image data and height
data = pFrame->getData();
delete pFrame;
delete[] framestart;
return data;
}
uint16_t WINAPI cl2GetFrameCount(uint8_t *pFileBuf)
{
uint32_t tmp;
memcpy(&tmp, pFileBuf, sizeof(uint32_t));
memcpy(&tmp, pFileBuf+tmp, sizeof(uint32_t));
return (uint16_t)tmp;
}
/***** cl2GetDirData ***************************************************
* decodes all frames of a .cl2 for given direction and xsize
* Args:
* *pFileBuf the buffer containing the filecontent
* *palette the palette (4 bytes for each of the 257 entries)
* 256 colors are needed + 1 for alpha
* uXSize this information must be given
* uDirNum the direction to get the frames from
* *uYSize the actual height is returned herein
*
* Returns: <frames> arrays containing 4 Bytes (RGBA) for each pixel
* where <frames> is read at runtime and handed back via *uFrames
*
* ---------------------------------------------------------------
* Comments: dirty hack, started from scratch @ 2000-10-12
*
* The format basics are similar to .cel, with the main difference
* that the values read have reverse interpretation. In .cel a value
* greater than 0x7F means transparency, while in .cl2 this means
* color and vice-versa. .cl2 has the additional understanding
* of blocks of the same color (0x80 .. 0xBF) where the one color is
* written multiple times.
*
* .cl2 only uses the block scheme, so there is no detection
* necessary in order to get it right. The only thing still unknown
* is that 0x0A 0x00 stuff...
*
* TODO: learn what 0x0A 0x00 means
***********************************************************************/
BYTE ** WINAPI cl2GetDirData(BYTE *pFileBuf, BYTE *palette, WORD uXSize, WORD uDirNum, WORD *uYSize)
{
FrameBuf *pFrame;
uint32_t frames=0, *framestart=NULL, uFilePos=0;
uint16_t i, fc;
uint8_t cRead=0, **data=NULL;
if (pFileBuf == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (palette == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uDirNum > 7) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uYSize == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// get direction offsets
uint32_t dirstart[8];
for (i=0; i<8; i++) {
memcpy(&dirstart[i], pFileBuf+uFilePos, sizeof(uint32_t));
uFilePos += sizeof(uint32_t);
}
uFilePos = dirstart[uDirNum];
memcpy(&frames, pFileBuf+uFilePos, sizeof(uint32_t));
uFilePos += sizeof(uint32_t);
data = new uint8_t*[frames];
// get frame offsets
framestart = new uint32_t[frames+1];
for (i=0; i<frames+1; i++) {
memcpy(&framestart[i], pFileBuf+uFilePos, sizeof(uint32_t));
uFilePos += sizeof(uint32_t);
}
// get frame data
for (fc=0; fc<frames; fc++) {
pFrame = new FrameBuf(palette, 0, uXSize, uYSize, NULL, 0);
uFilePos = dirstart[uDirNum] + framestart[fc];
while (uFilePos < dirstart[uDirNum] + framestart[fc+1]) {
cRead = pFileBuf[uFilePos++];
if (cRead < 0x80) { // transparency
// TODO: what is this 0x0A 0x00 stuff all about?
if ((cRead == 0x0A) && (pFileBuf[uFilePos] == 0) && (uFilePos == dirstart[uDirNum] + framestart[fc] + 1))
uFilePos += 9; // ignore the 9 bytes after 0x0A 0x00 at the framestart
else
for (i=0; i<cRead; i++)
pFrame->addPixel(TRANS_COL);
} else if (cRead < 0xC0) {
// read the next byte and write it <0xBF - cRead> times
for (i=0; i<0xBF - cRead; i++)
pFrame->addPixel(pFileBuf[uFilePos]);
++uFilePos;
} else // cRead > 0xBF
// read a block of the given size and write it
for (i=0; i < 256-cRead; i++)
pFrame->addPixel(pFileBuf[uFilePos++]);
}
// got the frame data, save it
data[fc] = pFrame->getData();
delete pFrame;
}
delete[] framestart;
return data;
}
/****** pcxGetData *****************************************************
* decodes pcx files (256 color, as in diablo mpq)
* Args:
* *pFileBuf the buffer containing the filecontent
* uFileSize the size of the file buffer
* uTransColor the palette entry to be transparent
* *uXSize the actual width is returned herein
* *uYSize the actual height is returned herein
*
* Returns: an array containing 4 Bytes (RGBA) for each pixel
*
* ---------------------------------------------------------------
* Comments: format info and pseudocode taken from:
* Klaus Holtorf, "Das Handbuch der Grafikformate"
* ISBN 3-7723-6393-8
***********************************************************************/
BYTE * WINAPI pcxGetData(BYTE *pFileBuf, DWORD uFileSize, BYTE uTransColor, WORD *uXSize, WORD *uYSize)
{
uint32_t uFilePos=0;
uint32_t uDataRead=0; // potentially big! (logo.pcx: 550 * 216 * 15 = 1,782,000)
uint16_t i=0;
uint8_t *data, *palette;
uint8_t uColorNum=0, uCount=0;
struct pcx_header_t {
uint8_t id;
uint8_t version;
uint8_t compressed;
uint8_t bpp;
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
uint16_t xdpi;
uint16_t ydpi;
uint8_t pal[16][3];
uint8_t reserved;
uint8_t layers;
uint16_t rowbytes;
uint16_t colortype;
uint8_t pad[58];
} pcxHeader;
if (pFileBuf == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uXSize == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (uYSize == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// get image information
memcpy(&pcxHeader, pFileBuf, sizeof(struct pcx_header_t));
*uXSize = (pcxHeader.x1 - pcxHeader.x0 + 1);
*uYSize = (pcxHeader.y1 - pcxHeader.y0 + 1);
if ((pcxHeader.version != 2) && (pcxHeader.version != 5)) {
cerr << "cannot handle pcx v" << pcxHeader.version << "\n";
return NULL;
}
// get palette
palette = new uint8_t[256*4];
if (pFileBuf[uFileSize - 768 - 1] != 0x0C) {
cerr << "palette error at " << uFileSize - 768 - 1 << "\n";
return NULL;
}
for (i=0; i<256; i++) {
memcpy(palette+i*4, pFileBuf+uFileSize-768+i*3, 3*sizeof(uint8_t));
palette[i*4+3] = 0xFF;
}
memset(palette+uTransColor*4, 0, 4*sizeof(uint8_t)); // transparent black
// start right after the header
uFilePos = sizeof(struct pcx_header_t);
data = new uint8_t[*uXSize * *uYSize * 4];
while (uDataRead < (uint32_t)(*uXSize * *uYSize)) {
// decompress
uColorNum = pFileBuf[uFilePos++];
if ((pcxHeader.compressed) && (uColorNum > 0xBF)) {
uCount = (uColorNum & 0x3F);
uColorNum = pFileBuf[uFilePos++];
} else
uCount = 1;
// draw count pixels with color val
for (i=0; i<uCount; i++)
memcpy(data+(uDataRead++)*4, palette+uColorNum*4, 4*sizeof(uint8_t));
}
// cleanup
delete[] palette;
return data;
}

Some files were not shown because too many files have changed in this diff Show more