commit 58872f1f3998195531e67cf8dc18cfd53814e2d8 Author: False.Genesis Date: Fri Jan 5 18:30:22 2007 +0000 initial release. still a lot of stuff to fix before everything works as it should. compilation works, linking produces errors. most code cleanups done. diff --git a/PseuWoW.sln b/PseuWoW.sln new file mode 100644 index 0000000..ac68c16 --- /dev/null +++ b/PseuWoW.sln @@ -0,0 +1,48 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PseuWoW", "src\PseuWoW.vcproj", "{EFFE60F4-DA39-41E8-9E53-E462000A2D91}" + ProjectSection(ProjectDependencies) = postProject + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} + {F548FC51-24A4-45FF-A381-BEBC39F18270} = {F548FC51-24A4-45FF-A381-BEBC39F18270} + {262199E8-EEDF-4700-A1D1-E9CC901CF480} = {262199E8-EEDF-4700-A1D1-E9CC901CF480} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "src\zlib.vcproj", "{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zthread", "src\zthread.vcproj", "{262199E8-EEDF-4700-A1D1-E9CC901CF480}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared", "src\shared.vcproj", "{F548FC51-24A4-45FF-A381-BEBC39F18270}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Debug.ActiveCfg = Debug|Win32 + {EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Debug.Build.0 = Debug|Win32 + {EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release.ActiveCfg = Release|Win32 + {EFFE60F4-DA39-41E8-9E53-E462000A2D91}.Release.Build.0 = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug.ActiveCfg = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug.Build.0 = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release.ActiveCfg = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release.Build.0 = Release|Win32 + {262199E8-EEDF-4700-A1D1-E9CC901CF480}.Debug.ActiveCfg = Debug|Win32 + {262199E8-EEDF-4700-A1D1-E9CC901CF480}.Debug.Build.0 = Debug|Win32 + {262199E8-EEDF-4700-A1D1-E9CC901CF480}.Release.ActiveCfg = Release|Win32 + {262199E8-EEDF-4700-A1D1-E9CC901CF480}.Release.Build.0 = Release|Win32 + {F548FC51-24A4-45FF-A381-BEBC39F18270}.Debug.ActiveCfg = Debug|Win32 + {F548FC51-24A4-45FF-A381-BEBC39F18270}.Debug.Build.0 = Debug|Win32 + {F548FC51-24A4-45FF-A381-BEBC39F18270}.Release.ActiveCfg = Release|Win32 + {F548FC51-24A4-45FF-A381-BEBC39F18270}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/PseuWoW.suo b/PseuWoW.suo new file mode 100644 index 0000000..2b3570e Binary files /dev/null and b/PseuWoW.suo differ diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..7c4ab98 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,237 @@ +///////////////////////////////////////////////////////////// +// PseuWoW changelog // date|time: 20:31 11.12.2006 ///////// +///////////////////////////////////////////////////////////// +//Format: +// + added +// - note +// % removed +// ! important +// O ToDo: open, not yet done +// x Todo: done +///////////////////////////////////////////////////////////// + + + +ToDo (Overall): +================ + +- simulation of no installed addons +- more config possibilities in conf/pseuwow.conf +- redo controller related code and recode controller +- character creation - to be able to create chars with names bl!zz does not allow +- remove hardcoded language names, use lang names via config +-> string table? not sure. +- ppoints system? as a workaround for maps? not sure. +- much much more i cant think of yet :P + +#Far future: +- kind of an AI that it can decide for itself what to do +- add ability to use blizz/mangos maps so that it can really walk around, not only teleport +- to be continued... +- looting, 2D/3D GUI, killing,... you can extend the list as you wish + +ToDo (version after: Alpha 13) / Planned Features: +================================================== + +O add a ZCompressor Class (a ByteBuffer using zlib deflate/inflate) +O [maybe] first touch with the UpdateFields (CMSG[_COMPRESSED]_UPDATE_OBJECT) +O [maybe] add Object/Unit/Player/Creature/... classes. +X cleanups to VarSet class (use vectors to store the vars) +O cleanups to DefScript class: use vectors to store the script text data +O DefScript: instead of only ${var} also be able to use $var like in TCL or PHP +O Implement threaded movement system. tracking of player's waypoints, better following code + (that does NOT tend to crash mangos!) +O improve chat AI? add other AI? not sure. +O logfile output +[...] + + +ToDo (next version: Alpha 12) / Planned features: +================================================= + +X lots of general code cleanups (remove old C functions from PseuWoW Alpha 7 and before; + add objects: PseuInstance, RealmSession, WorldSession, ...; drop the old procedurel code) +X opcode handler table, no more case x case y case z +O move code portions of the chat handler to an external ChatAI.cpp file and improve + the chat AI +O -> implement a WordList class to parse sentences +O a direct local console (like mangos has). drop plans about a remote controller for now. +O lots of bugfixes to the DefScript system +X implement zthread, zlib and remove the SDL thread functions. +X change the network system from SDL_net to the system by Anders Hedstrom (the one mangos uses). no more packet errors (i hope)! +O DefScript: implement a "PermissionMap" to set by the user (for internal funcions) +O config options: EnableIngameCommands, EnableLocalConsole, OverrideLoginGuid (dangerous!), + AutoReconnect, + +O DefScript fuctions: "GetGuid,var playername", "GetName,var GUID" +X add WorldPacket class +X -> add uint64 WorldPacket::GetPackedGUID() +X fix the packed GUID code if needed (not sure if its really bugged) + +O When everything is done: upload to openSVN! + + +20:43 09.11.2006 Alpha Build 11 +===================================== + ++ inluded modified WAD's TrayWoWemu.exe to work with PseuWoW -> TrayPseuWoW.exe =) + +Core: +! connecting to servers running versions above 1.10.2 is now possible! ++ implemented player name cache, first touch with std::vector<> :) +-> players get added to the cache as soon as they move or say something +-> chat messages now show player names, whispers can be sent now. +-> related command: [-]savecache. ++ commands can now given directly ingame saying/whispering "-command" to PseuWoW ++ added DefScript functions _onwhisper (gets triggered when a player whispers to PseuWoW), + emote #id. the emote function still needs to be fixed and linked with targeting once + implemented. ++ included reply.def, that uses the above macros and whisper.def. use: reply to last whisp + in its original language +% removed some old obsoelete cpp files +% removed the old config reader, replaced with dynamic reader using the classes + VarSet, std::string, DefScript. ++ added CMSG_PING and SMSG_PONG (ping every 30 sec, like original WoW) ++ better detection if PseuWoW entered the world successfully ++ added macros: @thiswhisper,@lastwhisper,@thiscmd,@lastcmd,@thismsg,@lastmsg and related. ++ following a player: simply repeat movement opcodes recieved from that player. + looks very shitty and is very buggy xD + -> command/usage: [-]follow PlayerName to start, just [-]follow to stop. ++ you can access all values set in PseuWoW.conf as CAPITALIZED variables, e.g.: + "${REALMLIST}" or ingame "-sayv REALMLIST". ++ once the conf is loaded the script "_setconf" is executed, this removes dangerous vars + like ACCNAME and ACCPASS ++ auto-decline of group-invite and trade attempts +!+ added support for packed GUIDs ++ added def files: outv, sayv, _nopermission, _setconf + + + +DefScript engine: +- renewed variable handler (renaming *local* var to scriptname::var, #var to var, + @var stays @var) +- fixed lots of bugs in the ReplaceVars() function. +- fixed a little bug in the script loader (wrongly loaded lines beginning with '#') ++ added a permission system for scripts called by players. use users.conf to set. + (like that its not possible for non-GMs to execute "-say .shutdown" or similar) + + + +17:23 06.10.2006 Alpha Build 10 +=================================== ++ FULLY working script engine with C++ interface, only very few functions implemented yet. + Dynamic loading: Scripts get only loaded if they are needed. ++ preparations to stop using C malloc/realloc/free and replace it with NEW, + also std::string instead of char* ++ PseuWoW can recieve whisper/say/party/guild/server messages, but not yet link them + to a name. ++ improved packet error/order handling, there are still some packets that get lost, + i need to find out where they go. SDL thread issue? +% removed yelling PseuWoW version on startup. Use the ./scripts/_worldenter.def script + file to modify behaviour when entering the world. +- PseuWoW can now detect if it has sent a chatmessage itself or if it came from someone else +- added a little fun code and a VERY "basic" chat AI for fun :P +- it will say a note if it is sure it has entered the world correctly. it might have been + successful anyway even without it, but at least you can be sure when it will probably work. + requires "SAY ${@version}" in scripts/_enterworld.def + + +18:15 10.09.2006 Alpha Build 9 +=============================== ++ Added CircularBuffer class for world packet reciever ++ Added SDLTCPConnection class for easier connectivity and code readability +- first preparations for builtin script engine, still excluded from build, + needs cleanups and fixes. + -> coded the variable handler + -> coded the script loader + -> coded the script line tokenizer ++ Added connection to world server ++ World Authentication done +% removed old rs_... / ws_... functions, replaced with SDLTCPConnection realmCon/worldCon +% disabled the controller interface for now. it will be included again as soon as the + script interpreter works and everything has been cleaned up. ++ Integrated AuthCrypt class from mangos ++ CHAR_ENUM integrated, char list is now requested and parsed ++ read charname from conf file and login with that char + YES, logging into the world finally WORKS! :DD ++ some checks for invalid or strange packets, which are tried to be interpreted correctly. + packet ordering and fetch queue is still buggy. +- PseuWoW yells its version once it has joined the world, and yells if an error occured. +- only server messages get interpreted correctly so far, player chat recieve does NOT work + +03:12 29.07.2006 Alpha Build 8 +=============================== +- completely rewrote the authentication code, Imported Sha1Hash and BigNumber + classes from MaNGOS (shrunk code size to 1/4 of what it was before). + The code even seems bug-free (hope it stays so) +- Authentication WORKS! (after 2 months of failure) ++ added realmlist parser ++ set realm to login via conf file +- Tested on WoWemu (1.8.0) & MaNGOS (1.10.2), authenticating works well ++ added a neat icon :) by ©haos + + +14:45 12.07.2006 Alpha Build 7 +=============================== +- complete code reorganisation (no more code including only with .h files. + now we have several cpp files with each its own .h) +- emulation of any version +- updated comment parser, finally :) +- you can now set version, build and language via conf file +- merged the 2 controller tcpsocks into 1, controller can still only connect to localhost. + still no conf file reading implemented into the controller. rest will be implemented later. +- removed SS & server b, they were useless +- fixed crash where an attemt was made to delete a const string. + (seems this caused the GarbageStack:: realloc() size=112 failure) +- many other general improvemens and bugfixes + +02:31 10.06.2006 Alpha Build 6 - Memory handling is hard. +=============================== +- fixed crash when realmlist hostname could not be resolved +! forgot to malloc x_str & u_str in proof packet sender -> crash (maybe i got it fixed this time) +- made more funcions work with the garbage collector +- in debug build GarbageStack:: realloc() size=112 fails. dunno why. +- added a server S & server b for testing. they are not important and will get removed later. +- still no correct reversion. + +18:12 05.06.2006 Alpha Build 5 - The I hate C++ version +=============================== +- crash,crash,crash. there must be a bug in the BN_reverse routine. ++ Added a garbage collector +- updated the fileparser, because it got bugged with the garbage collector. + More configs are supported now. comments still must be at the beginning of the line + to be treated as comments. +- still working on correct reversal :C + +22:55 31.05.2006 Alpha Build 4 - The DAMN FUCKING SHIT i don't get it version +=============================== +- damn i just don't find it out. decided to do a random reversal on every failure. +- the program got very unstable. seems i do a mistake i am not aware of. help anyone? +-> added a debug output to find out where the bugged lines are. strage they change + everytime i run the program. fuck. + +18:16 31.05.2006 Alpha Build 3 - The YAAAY it works version +============================== +- finished the packet, server still answers "password wrong". + working on correct reversion now + +16:52 30.05.2006 Alpha Build 2 +=============================== +- added more bignum calculations, now i got until S. +- still not sure how they have to be reversed to be calculated corrctly in the B1!77 way. + SRP demo page (srp.stanford.edu/demo) says my S is correct so far, calculated in the + normal way. At least i got the right formulas. :D +- next thing to do is split S up, hash it, etc... to get M1 & M2 + +21:51 24.05.2006 Alpha Build 1 +=============================== +- first release, not working yet. +- connecting to realm server possible, detection for acc already in use / acc not existing +- OpenSSL BIGNUM and SHA1 integrated. +- first bignum calculations :), i still have to find out how the numbers are + reversed and calculated correctly +- controller connection possible. it uses 2 ports, i will change it to 1 port in future +- config file readout (conf/pseuwow.conf) +- still crashes when it cant find the realmlist. time to fix it... +- controller connection is still buggy when a connection to the realm server has been + established. diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..7b35e74 --- /dev/null +++ b/license.txt @@ -0,0 +1,24 @@ +Find the full license at: +http://www.gnu.org/licenses/gpl.html + + +Summary: + +Copyright (C) 2006 False.Genesis @ SnowStom Software + +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 + + +Every part of program code belongs to its respective owner. diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..42461d8 --- /dev/null +++ b/readme.txt @@ -0,0 +1,308 @@ +#################################################################################### +################################# - PseuWoW ReadMe - ########## 09.11.2006 ######### +#################################################################################### +## ## +## Web: http://my.opera.com/PseuWoW ## +## Email/MSN: hoden386@lycos.de ## +## ## +## 1.) What is PseuWoW? ## +## 2.) Installation & configuration ## +## 3.) The DefScript engine [to be updated] ## +## 4.) The controller [*availible soon*] ## +## 5.) Interaction with PseuWoW ## +## 6.) Compiling your own version ## +## 7.) A word to Blizzard ## +## ... ## +## 8.) Appendix: [*availible soon*] ## +## A) The DefScript interface ## +## B) Macro reference ## +## C) Function reference ## +## ## +## ## +#################################################################################### +#################################################################################### + + +#################################################### +########## 1.) What is PseuWoW? #################### +#################################################### + +A custom wow client, or at least it is supposed to be a "real" client later on. +For now it is thougt to be a bot that can help GMs/admins to manage their *private(!)* WoW server. +It does not need an installation of real WoW to run, and you do not need any +good hardware to run it, since it has no graphics (yet!) and not such extensive +memory usage like the bloated WoW.exe has. +it uses only the console for now, but since it runs on SDL, you *could* easily build up +your own gui using OpenGL. buts it's not designed for that purpose in this early state. + +DO NOT use this program to connect to official servers! +It does NOT work due to Blizzard's IP-Spoof filter, which PseuWoW cant bypass yet. +( YES this IS intended to be that way! For your own safety and for the legality of PseuWoW!) +If you should try anyway, the only thing you can win is the ban/loss of your account. + + + +Performance: +============ +Tested Build 8 on a 300MHz Intel Celeron notebook, took a bit longer to Auth then on a +3GHz Pentium 4 PC, but worked well so far; more benchmarks on slower hardware will follow =) + + + +#################################################### +########## 2.) Installation & Configuration ######## +#################################################### + +Required DLL files: +=================== + +- SDL.dll +- SDL_net.dll +- msvcp71(d).dll +- msvcr71(d).dll + +Be sure you have them put into the same folder as PseuWoW.exe (or your windows/system32 folder). + +How to make it run properly (main configuration): +================================================= + +Open the file "conf/PseuWoW.conf" in a text editor and edit it to your needs. +There should be comments inside the file explaining what the options are good for. + +User permission configuration: +============================== + +Open the file "conf/users.conf". +For every player you want to assign a permission level to enter the name of the player (note correct spelling!!), +followed by a "=" and the permission level ( a number from 0 - 255; 0=least; 255=all permissions ). +The lines should look like this: + +Master=255 +Operator=100 +Playerx=1 +... + +If a player is not listed in this file he will get permission 0 automatically. + +Note that special unicode chars in playernames like óäöüßêýà etc. DO NOT work. + + +Saving the cache: +================= +If you close PseuWoW using the [X] in the top-right corner it will be instantly closed +and NO data will be saved. To save the data you can either quit PseuWoW pressing Ctrl+C, +giving the "-quit" command ingame or just save without quitting giving the ingame command +"-savecache". (explained further down this file) + + + +#################################################### +########## 3.) The DefScript engine ################ +#################################################### + +Information: +============ + +PseuWoW uses a scripting language exclusively designed for it - i admit i didn't know +how to implement Python or LUA :P +DefScript has no controlling structures like IF, FOR, WHILE, etc. yet, this will come in future. + +The Scripts have the extension ".def" and are stored in the "/scripts/" folder of PseuWoW. +Every file represents a single function. + +Syntax: +======= +A typical function call looks like this: + +command,arg1,arg2,arg3,argx defaultarg + +command: name of the script or function you want to execute (UPPER- or lowercase does not matter) +arg1 - argx: OPTIONAL(!) arguments, seperated by commas. +defaultarg: the last ( or better called "typical" ) argument of the function, +seperated by [space]. +Everything after the first space char will be treated as defaultarg! +To prevent this, you can use curly brackets {} to express that the given text is connected. +e.g.: +"SENDCHATMESSAGE,6,{hi there},Keks" -> correct, works. Whispers "hi there" to player "Keks". + +"SENDCHATMESSAGE,6,hi there,Keks" +-> works too, BUT: +"SENDCHATMESSAGE,6,hi" -> this will be the command with its args +"there,Keks" -> this will be the defaultarg +result: the call will not produce the expected result! + + +Variables: +========== + +Setting variables: +"x = 1" -> WRONG! DefScript knows only functions!! +You have tu use this: +"SET,x 1" -> sets the LOCAL variable x to 1. [x will be stored as "scriptname::x" internally] +"SET,#x 1" -> sets the GLOBAL variable x to 1. [#x will be stored as "x" internally] +"SET,#welcomemsg PseuWoW logged on, be careful!" -> sets the GLOBAL variable "welcomemsg" to PseuWoW logged on, be careful!". +Note that the variable name is the first arg, preceded with a comma, and its value is the defaultarg. +Variable names with a preceding "#" will be stored as GLOBAL vars, with the preceding "#" removed. + +"DEFAULT,x 1" -> sets x only if it has not been set or x has no value (=is empty) +"UNSET x" -> removes the variable. you have to remove every variable you do no longer need yourself! + + +A special kind of variables are macros, which values can only be changed by the program itself. +Macros begin with "@". + +Accessing variables: +==================== + +SET,x 1 +SET,mystr hello world +OUT ${mystr}, x has the value ${x} +PAUSE 1000 +SET,mystr ${mystr} goodbye +OUT ${mystr} + +pretty obvious: +${mystr} gets replaced with "hello world" +${x} gets replaced with 1. +and the text "hello world, x has the value 1" will be written to the console. +after one second, mystr will be set to "hello world goodbye" and again written to console. + +accessing globals: OUT ${#myglobal} +accessing macros: OUT ${mymacro} + +[[* more explanations of the variable system will follow *]] + +Load Instructions: +================== +load instructions begin with "#" and are put at the beginning of every script. +You can not use variables in them! +The following are availible: +#permission=x -> sets the permission required to execute this script. 0 by default! x=0...255 +#debug -> produce more output +#load_debug -> lists every line that is loaded +#load_notify -> notifies you once the script has been loaded and is ready for use +...more to come... + + + + + +#################################################### +########## 5.) Interaction with PseuWoW ############ +#################################################### + + +You can either say or whisper the command to PseuWoW; put a "-" before the command name +that PseuWoW recognizes the chat message as a command, like: +"-say hello" +"-say,orcish hello" +"-say,8 hello" +"-emote 12" +"-yell LOL" +"-yell,darnassian LOL" +"-savecache" +"-follow Keks" +"-quit" +etc. + +There is also some VERY basic chat AI, say hi,lol,omg,wtf,download,... when PseuWoW will hear you and it will respond :) +A full (and useful) chat AI will be implemented later. + +All trade and party invite rquests are automatically declined. +Note the "_onwhisper" script that is run everytime a whisper is recieved. + + + + +#################################################### +########## 6.) Compiling your own version ########## +#################################################### + +- i used Microsoft Visual Studio.NET 2003 for compiling +- download the include/lib package (see URL on top). copy the content into the + include/lib directory of the compiler. +- if needed, copy the reqired DLL files into the /bin directory (where the project files are) +- open the project and compile. + + + +#################################################### +########## 7.) A word to Blizzard ################## +#################################################### + +I always liked blizz... until WoW came out. +The management is shitty, almost no customer support, and bans in case they dont know what +to do with players. +Blizzard programmers and designers, YOU ARE GREAT and you made great games before +Blizzard got eaten up by vivendi universal. KEEP UP THE GOOD WORK! +After that, vivendi management fucked it all up. the result is WoW, a always-pay game like +Diablo3 will probably be. +So here are my greetings to the vivendi management: + + + + + + + Eat shit and die, bitches! + + _gm__gz, + ,Z\/` 'c\. + /,! '[W + ]!] . [] + ] ] .-==- b] + ]i ~ -==== !]- + ] ~~ -![ + W d` + 'b W + i[ 'M + ]. ~ 4. + ] -'[ + d -= b + M! @ + @ `-D + ]@ -]A + @P , , . '@ + M| ~` '` /]@ + _._. Y ciP + ,g/G/~Vi ![ '-V[ + ,Z~_/`- b@_ ,[ -` [ + _v4Tv/ .m/TGs,2V~-i ] \/.[ + ,vf ,(f `'iY.A / -[,z --=-__ + ,gY` v)` \-.@! ,--]Wf =/`,~N + ,gY` id / b@[ -/ ]M (b. + vf| - t[ !,i@P! ' ][. /`YZ~V,c. + if, ' , ,(] ]'@` ]b `'/@. `'*W. + K ,)`-'Z _ _ -/i@ i ' @Y |4t /Vmv. + b gz/-Z`'` @ - ] -P] ` , i ,!W ]@ ',/M.- + [ gZ\ ]! * i[ ! Z!d, ]- [W ~ \ ] X8.\ + ,[ '7v` A 'i ` - !' ] [@./ , ,] 4/c- + ] !i- `][ ,] ' e!] i - . m ! 'W = + W s-=` ][ !A /- ] W= ][! + A -Z- @- -! P ,A, , ] ,@ + [ '- ,/4. !' Z` [ . W g`/[ + Y.- ' /[ . ,/ !.'c/b- + Vi'- ' ! ! / ' `` @[ + 'e. ] , . v @[ + Vs. '. .- ` / @` + '5c. \ ! , --@. + \Zs `-. '- \ - -A + '\. - . ' ' - ` .-, = 'i[ + 'e. -' - , -` ,/ !vi\ v i*` + Vs -! -- ' v` ,'.-'/ _/`\` + 'G. ' ! '- / '.c\,` vfm/ - + !i ` -. ,` ` , `'c ,z7!.` - + Yi ' - ! . ,`` - - !` ,zL'` + b i , - - ' - , - - ,Z|!` + Y ` \- , , '- ` , . ,Z7 + 8 -- . ` -` .'.- -P + ] ] -, . - , ,[ + ]. Y- ' / 8 + i| ,' - ` . - ' W + ` , - - , , K + + + +(c) SnowStorm Software, 2006 +(and the finger belogs to SSG cracking group :P ) + diff --git a/src/Client/Auth/AuthCrypt.cpp b/src/Client/Auth/AuthCrypt.cpp new file mode 100644 index 0000000..ffa56d6 --- /dev/null +++ b/src/Client/Auth/AuthCrypt.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 "common.h" +#include "AuthCrypt.h" +#include + +AuthCrypt::AuthCrypt() +{ + _initialized = false; +} + +void AuthCrypt::Init() +{ + _send_i = _send_j = _recv_i = _recv_j = 0; + _initialized = true; +} + +void AuthCrypt::DecryptRecv(uint8 *data, size_t len) +{ + if (!_initialized) return; + if (len < CRYPTED_RECV_LEN) return; + + _recv_i2=_recv_i; + _recv_j2=_recv_j; + + for (size_t t = 0; t < CRYPTED_RECV_LEN; t++) + { + _recv_i %= _key.size(); + uint8 x = (data[t] - _recv_j) ^ _key[_recv_i]; + ++_recv_i; + _recv_j = data[t]; + data[t] = x; + + + } +} + +void AuthCrypt::EncryptSend(uint8 *data, size_t len) +{ + if (!_initialized) return; + if (len < CRYPTED_SEND_LEN) return; + + for (size_t t = 0; t < CRYPTED_SEND_LEN; t++) + { + _send_i %= _key.size(); + uint8 x = (data[t] ^ _key[_send_i]) + _send_j; + ++_send_i; + data[t] = _send_j = x; + } +} + +void AuthCrypt::SetKey(uint8 *key, size_t len) +{ + _key.resize(len); + std::copy(key, key + len, _key.begin()); +} + +void AuthCrypt::DecryptRescue(void) +{ + // undos the last decrypt operation + _recv_i=_recv_i2; + _recv_j=_recv_j2; +} + +AuthCrypt::~AuthCrypt() +{ +} + diff --git a/src/Client/Auth/AuthCrypt.h b/src/Client/Auth/AuthCrypt.h new file mode 100644 index 0000000..59a081e --- /dev/null +++ b/src/Client/Auth/AuthCrypt.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 _AUTHCRYPT_H +#define _AUTHCRYPT_H + +//#include +#include + +class AuthCrypt +{ + public: + AuthCrypt(); + ~AuthCrypt(); + + const static size_t CRYPTED_SEND_LEN = 6; + const static size_t CRYPTED_RECV_LEN = 4; + + void Init(); + + void SetKey(uint8 *, size_t); + + void DecryptRecv(uint8 *, size_t); + void EncryptSend(uint8 *, size_t); + + bool IsInitialized() { return _initialized; } + + void DecryptRescue(void); + + private: + std::vector _key; + uint8 _send_i, _send_j, _recv_i, _recv_j; + uint8 _send_i2, _send_j2, _recv_i2, _recv_j2; + bool _initialized; +}; +#endif diff --git a/src/Client/Auth/BigNumber.cpp b/src/Client/Auth/BigNumber.cpp new file mode 100644 index 0000000..4f983cb --- /dev/null +++ b/src/Client/Auth/BigNumber.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 "BigNumber.h" +#include +#include +#include + +BigNumber::BigNumber() +{ + _bn = BN_new(); + _array = NULL; +} + +BigNumber::BigNumber(const BigNumber &bn) +{ + _bn = BN_dup(bn._bn); + _array = NULL; +} + +BigNumber::BigNumber(uint32 val) +{ + _bn = BN_new(); + BN_set_word(_bn, val); + _array = NULL; +} + +BigNumber::~BigNumber() +{ + BN_free(_bn); + delete[] _array; +} + +void BigNumber::SetDword(uint32 val) +{ + BN_set_word(_bn, val); +} + +void BigNumber::SetQword(uint64 val) +{ + BN_add_word(_bn, (uint32)(val >> 32)); + BN_lshift(_bn, _bn, 32); + BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF)); +} + +void BigNumber::SetBinary(const uint8 *bytes, int len) +{ + uint8 t[1000]; + for (int i = 0; i < len; i++) t[i] = bytes[len - 1 - i]; + BN_bin2bn(t, len, _bn); +} + +void BigNumber::SetHexStr(const char *str) +{ + BN_hex2bn(&_bn, str); +} + +void BigNumber::SetRand(int numbits) +{ + BN_rand(_bn, numbits, 0, 1); +} + +BigNumber BigNumber::operator=(const BigNumber &bn) +{ + BN_copy(_bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator+=(const BigNumber &bn) +{ + BN_add(_bn, _bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator-=(const BigNumber &bn) +{ + BN_sub(_bn, _bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator*=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mul(_bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::operator/=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_div(_bn, NULL, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::operator%=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mod(_bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::Exp(const BigNumber &bn) +{ + BigNumber ret; + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_exp(ret._bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return ret; +} + +BigNumber BigNumber::ModExp(const BigNumber &bn1, const BigNumber &bn2) +{ + BigNumber ret; + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mod_exp(ret._bn, _bn, bn1._bn, bn2._bn, bnctx); + BN_CTX_free(bnctx); + + return ret; +} + +int BigNumber::GetNumBytes(void) +{ + return BN_num_bytes(_bn); +} + +uint32 BigNumber::AsDword() +{ + return (uint32)BN_get_word(_bn); +} + +uint8 *BigNumber::AsByteArray() +{ + if (_array) + { + delete[] _array; + _array = NULL; + } + _array = new uint8[GetNumBytes()]; + BN_bn2bin(_bn, (unsigned char *)_array); + + std::reverse(_array, _array + GetNumBytes()); + + return _array; +} + +/*ByteBuffer BigNumber::AsByteBuffer() +{ + ByteBuffer ret(GetNumBytes()); + ret.append(AsByteArray(), GetNumBytes()); + return ret; +}*/ + +/*std::vector BigNumber::AsByteVector() +{ + std::vector ret; + ret.resize(GetNumBytes()); + memcpy(&ret[0], AsByteArray(), GetNumBytes()); + return ret; +}*/ + +const char *BigNumber::AsHexStr() +{ + return BN_bn2hex(_bn); +} + +const char *BigNumber::AsDecStr() +{ + return BN_bn2dec(_bn); +} diff --git a/src/Client/Auth/BigNumber.h b/src/Client/Auth/BigNumber.h new file mode 100644 index 0000000..ff4cfc9 --- /dev/null +++ b/src/Client/Auth/BigNumber.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 _AUTH_BIGNUMBER_H +#define _AUTH_BIGNUMBER_H + +#include "../../shared/common.h" + +struct bignum_st; + +class BigNumber +{ + public: + BigNumber(); + BigNumber(const BigNumber &bn); + BigNumber(uint32); + ~BigNumber(); + + void SetDword(uint32); + void SetQword(uint64); + void SetBinary(const uint8 *bytes, int len); + void SetHexStr(const char *str); + + void SetRand(int numbits); + + BigNumber operator=(const BigNumber &bn); + + BigNumber operator+=(const BigNumber &bn); + BigNumber operator+(const BigNumber &bn) + { + BigNumber t(*this); + return t += bn; + } + BigNumber operator-=(const BigNumber &bn); + BigNumber operator-(const BigNumber &bn) + { + BigNumber t(*this); + return t -= bn; + } + BigNumber operator*=(const BigNumber &bn); + BigNumber operator*(const BigNumber &bn) + { + BigNumber t(*this); + return t *= bn; + } + BigNumber operator/=(const BigNumber &bn); + BigNumber operator/(const BigNumber &bn) + { + BigNumber t(*this); + return t /= bn; + } + BigNumber operator%=(const BigNumber &bn); + BigNumber operator%(const BigNumber &bn) + { + BigNumber t(*this); + return t %= bn; + } + + BigNumber ModExp(const BigNumber &bn1, const BigNumber &bn2); + BigNumber Exp(const BigNumber &); + + int GetNumBytes(void); + + struct bignum_st *BN() { return _bn; } + + uint32 AsDword(); + uint8* AsByteArray(); + // ByteBuffer AsByteBuffer(); +// std::vector AsByteVector(); + + const char *AsHexStr(); + const char *AsDecStr(); + + private: + struct bignum_st *_bn; + uint8 *_array; +}; +#endif diff --git a/src/Client/Auth/ByteBuffer.h b/src/Client/Auth/ByteBuffer.h new file mode 100644 index 0000000..01ef1a2 --- /dev/null +++ b/src/Client/Auth/ByteBuffer.h @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 _BYTEBUFFER_H +#define _BYTEBUFFER_H + +#include +#include +#include + +class ByteBuffer +{ + public: + class error + { + }; + + const static size_t DEFAULT_SIZE = 0x1000; + + ByteBuffer(): _rpos(0), _wpos(0) + { + _storage.reserve(DEFAULT_SIZE); + } + ByteBuffer(size_t res): _rpos(0), _wpos(0) + { + _storage.reserve(res); + } + ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { } + + void clear() + { + _storage.clear(); + _rpos = _wpos = 0; + } + + template void append(T value) + { + append((uint8 *)&value, sizeof(value)); + } + template void put(size_t pos,T value) + { + put(pos,(uint8 *)&value,sizeof(value)); + } + + ByteBuffer &operator<<(bool value) + { + append((char)value); + return *this; + } + ByteBuffer &operator<<(uint8 value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(uint16 value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(uint32 value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(uint64 value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(float value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(double value) + { + append(value); + return *this; + } + ByteBuffer &operator<<(const std::string &value) + { + append((uint8 *)value.c_str(), value.length()); + append((uint8)0); + return *this; + } + ByteBuffer &operator<<(const char *str) + { + append((uint8 *)str, str ? strlen(str) : 0); + append((uint8)0); + return *this; + } + + ByteBuffer &operator>>(bool &value) + { + value = read() > 0 ? true : false; + return *this; + } + ByteBuffer &operator>>(uint8 &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(uint16 &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(uint32 &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(uint64 &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(float &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(double &value) + { + value = read(); + return *this; + } + ByteBuffer &operator>>(std::string& value) + { + value.clear(); + while (true) + { + char c=read(); + if (c==0) + break; + value+=c; + } + return *this; + } + + uint8 operator[](size_t pos) + { + return read(pos); + } + + size_t rpos() + { + return _rpos; + }; + + size_t rpos(size_t rpos) + { + _rpos = rpos; + return _rpos; + }; + + size_t wpos() + { + return _wpos; + } + + size_t wpos(size_t wpos) + { + _wpos = wpos; + return _wpos; + } + + template T read() + { + T r=read(_rpos); + _rpos += sizeof(T); + return r; + }; + template T read(size_t pos) const + { + return *((T*)&_storage[pos]); + } + + void read(uint8 *dest, size_t len) + { + if (_rpos + len <= size()) + { + memcpy(dest, &_storage[_rpos], len); + } + else + { + throw error(); + } + _rpos += len; + } + + const uint8 *contents() const { return &_storage[0]; }; + + inline size_t size() const { return _storage.size(); }; + + void resize(size_t newsize) + { + _storage.resize(newsize); + _rpos = 0; + _wpos = size(); + }; + void reserve(size_t ressize) + { + if (ressize > size()) _storage.reserve(ressize); + }; + + void append(const std::string& str) + { + append((uint8 *)str.c_str(),str.size() + 1); + } + void append(const char *src, size_t cnt) + { + return append((const uint8 *)src, cnt); + } + void append(const uint8 *src, size_t cnt) + { + if (!cnt) return; + if (_storage.size() < _wpos + cnt) + _storage.resize(_wpos + cnt); + memcpy(&_storage[_wpos], src, cnt); + _wpos += cnt; + } + void append(const ByteBuffer& buffer) + { + if(buffer.size()) append(buffer.contents(),buffer.size()); + } + + void put(size_t pos, const uint8 *src, size_t cnt) + { + memcpy(&_storage[pos], src, cnt); + } + void print_storage() + { + printf("STORAGE_SIZE: %u\n", size() ); + for(uint32 i = 0; i < size(); i++) + printf("%u - ", read(i) ); + printf("\n"); + } + + void textlike() + { + printf("STORAGE_SIZE: %u\n", size() ); + for(uint32 i = 0; i < size(); i++) + printf("%c", read(i) ); + printf("\n"); + } + + void hexlike() + { + uint32 j = 1, k = 1; + printf("STORAGE_SIZE: %u\n", size() ); + for(uint32 i = 0; i < size(); i++) + { + if ((i == (j*8)) && ((i != (k*16)))) + { + if (read(i) < 0x0F) + { + printf("| 0%X ", read(i) ); + } + else + { + printf("| %X ", read(i) ); + } + + j++; + } + else if (i == (k*16)) + { + if (read(i) < 0x0F) + { + printf("\n0%X ", read(i) ); + } + else + { + printf("\n%X ", read(i) ); + } + + k++; + j++; + } + else + { + if (read(i) < 0x0F) + { + printf("0%X ", read(i) ); + } + else + { + printf("%X ", read(i) ); + } + } + } + printf("\n"); + + } + + protected: + + size_t _rpos, _wpos; + std::vector _storage; +}; + +template ByteBuffer &operator<<(ByteBuffer &b, std::vector v) +{ + b << (uint32)v.size(); + for (typename std::vector::iterator i = v.begin(); i != v.end(); i++) + { + b << *i; + } + return b; +} + +template ByteBuffer &operator>>(ByteBuffer &b, std::vector &v) +{ + uint32 vsize; + b >> vsize; + v.clear(); + while(vsize--) + { + T t; + b >> t; + v.push_back(t); + } + return b; +} + +template ByteBuffer &operator<<(ByteBuffer &b, std::list v) +{ + b << (uint32)v.size(); + for (typename std::list::iterator i = v.begin(); i != v.end(); i++) + { + b << *i; + } + return b; +} + +template ByteBuffer &operator>>(ByteBuffer &b, std::list &v) +{ + uint32 vsize; + b >> vsize; + v.clear(); + while(vsize--) + { + T t; + b >> t; + v.push_back(t); + } + return b; +} + +template ByteBuffer &operator<<(ByteBuffer &b, std::map &m) +{ + b << (uint32)m.size(); + for (typename std::map::iterator i = m.begin(); i != m.end(); i++) + { + b << i->first << i->second; + } + return b; +} + +template ByteBuffer &operator>>(ByteBuffer &b, std::map &m) +{ + uint32 msize; + b >> msize; + m.clear(); + while(msize--) + { + K k; + V v; + b >> k >> v; + m.insert(make_pair(k, v)); + } + return b; +} +#endif diff --git a/src/Client/Auth/Sha1.cpp b/src/Client/Auth/Sha1.cpp new file mode 100644 index 0000000..99b00bd --- /dev/null +++ b/src/Client/Auth/Sha1.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 "Sha1.h" +#include + +Sha1Hash::Sha1Hash() +{ + SHA1_Init(&mC); +} + +Sha1Hash::~Sha1Hash() +{ + SHA1_Init(&mC); +} + +void Sha1Hash::UpdateData(const uint8 *dta, int len) +{ + SHA1_Update(&mC, dta, len); +} + +void Sha1Hash::UpdateData(const std::string &str) +{ + UpdateData((uint8 *)str.c_str(), str.length()); +} + +void Sha1Hash::UpdateBigNumbers(BigNumber *bn0, ...) +{ + va_list v; + BigNumber *bn; + + va_start(v, bn0); + bn = bn0; + while (bn) + { + UpdateData(bn->AsByteArray(), bn->GetNumBytes()); + bn = va_arg(v, BigNumber *); + } + va_end(v); +} + +void Sha1Hash::Initialize() +{ + SHA1_Init(&mC); +} + +void Sha1Hash::Finalize(void) +{ + SHA1_Final(mDigest, &mC); +} diff --git a/src/Client/Auth/Sha1.h b/src/Client/Auth/Sha1.h new file mode 100644 index 0000000..1a5f612 --- /dev/null +++ b/src/Client/Auth/Sha1.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 _AUTH_SHA1_H +#define _AUTH_SHA1_H + +#include "common.h" +#include +#include "BigNumber.h" +#include + +class Sha1Hash +{ + public: + Sha1Hash(); + ~Sha1Hash(); + + void UpdateFinalizeBigNumbers(BigNumber *bn0, ...); + void UpdateBigNumbers(BigNumber *bn0, ...); + + void UpdateData(const uint8 *dta, int len); + void UpdateData(const std::string &str); + + void Initialize(); + void Finalize(); + + uint8 *GetDigest(void) { return mDigest; }; + int GetLength(void) { return SHA_DIGEST_LENGTH; }; + + BigNumber GetBigNumber(); + + private: + SHA_CTX mC; + uint8 mDigest[SHA_DIGEST_LENGTH]; +}; +#endif diff --git a/src/Client/Auth/md5.c b/src/Client/Auth/md5.c new file mode 100644 index 0000000..f04d213 --- /dev/null +++ b/src/Client/Auth/md5.c @@ -0,0 +1,385 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +L. Peter Deutsch +ghost@aladdin.com + +*/ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + +The original and principal author of md5.c is L. Peter Deutsch +. Other authors are noted in the change history +that follows (in reverse chronological order): + +2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order +either statically or dynamically; added missing #include +in library. +2002-03-11 lpd Corrected argument list for main(), and added int return +type, in test program and T value program. +2002-02-21 lpd Added missing #include in test program. +2000-07-03 lpd Patched to eliminate warnings about "constant is +unsigned in ANSI C, signed in traditional"; made test program +self-checking. +1999-11-04 lpd Edited comments slightly for automatic TOC extraction. +1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). +1999-05-03 lpd Original version. +*/ + +#include "md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + #if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; + #else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; + #endif + + { + #if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ + #endif + #if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) + { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } + else + { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } + #endif + #if BYTE_ORDER == 0 + else /* dynamic big-endian */ + #endif + #if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + + # if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ + # else + # define xbuf X /* (static only) */ + # endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + #endif + } + + #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ + #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); + #undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ + #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); + #undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ + #define H(x, y, z) ((x) ^ (y) ^ (z)) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); + #undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ + #define I(x, y, z) ((y) ^ ((x) | ~(z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); + #undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) + { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/src/Client/Auth/md5.h b/src/Client/Auth/md5.h new file mode 100644 index 0000000..fa2937e --- /dev/null +++ b/src/Client/Auth/md5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +L. Peter Deutsch +ghost@aladdin.com + +*/ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + +The original and principal author of md5.h is L. Peter Deutsch +. Other authors are noted in the change history +that follows (in reverse chronological order): + +2002-04-13 lpd Removed support for non-ANSI compilers; removed +references to Ghostscript; clarified derivation from RFC 1321; +now handles byte order either statically or dynamically. +1999-11-04 lpd Edited comments slightly for automatic TOC extraction. +1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); +added conditionalization for C++ compilation from Martin +Purschke . +1999-05-03 lpd Original version. +*/ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s +{ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ + #endif + + /* Initialize the algorithm. */ + void md5_init(md5_state_t *pms); + + /* Append a string to the message. */ + void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + + /* Finish the message and return the digest. */ + void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + + #ifdef __cplusplus +} /* end extern "C" */ +#endif +#endif /* md5_INCLUDED */ diff --git a/src/Client/ConfigReader.cpp_ b/src/Client/ConfigReader.cpp_ new file mode 100644 index 0000000..6e6fda3 --- /dev/null +++ b/src/Client/ConfigReader.cpp_ @@ -0,0 +1,133 @@ +#include +#include "common.h" +#include "PseuWoW.h" +#include "DefScript/DefScript.h" +#include "ConfigReader.h" + +bool ConfigReader::ReadConf(std::string fn, VarSet& vs, bool capitalize){ + std::fstream f; + char z; + std::string line,label,value; + + f.open(fn.c_str(), std::ios_base::in); + if(!f) + return false; + while(!f.eof()){ + line.clear(); + while (true) { + f.get(z); + if(z=='\n' || f.eof()) + break; + line+=z; + } + if(line.empty()) + continue; // line is empty, proceed with next line + while( (line.at(0)==' ' || line.at(0)=='\t') ) + line.erase(0,1); + if(line.empty()) + continue; + if(line.at(0)=='/' && line.at(1)=='/') + continue; // line is comment, proceed with next line + label=line.substr(0,line.find('=',0)); + if(capitalize) + label=stringToUpper(label); + value=line.substr(line.find('=',0)+1,line.length()); + + DEBUGMODE(printf("CONF: '%s' = '%s'\n",label.c_str(),value.c_str());); + vs.Set(label,value); + } + f.close(); + return true; +} + +void ConfigReader::SetMainConf(VarSet& vs){ + + if(vs.Exists("DEBUG")){ + DEBUG=atoi(vs.Get("DEBUG").c_str()); + DEBUG1(printf("DEBUG level=%d\n",DEBUG);); + } + if(vs.Exists("REALMLIST")){ + strcpy(realmlist,vs.Get("REALMLIST").c_str()); + if(DEBUG>=1)printf("Realmlist set to \"%s\"\n",realmlist); + } + if(vs.Exists("ACCNAME")){ + strcpy(accname,vs.Get("ACCNAME").c_str()); + if(DEBUG>=1)printf("Account Name set to \"%s\"\n",accname); + } + if(vs.Exists("ACCPASS")){ + strcpy(accpass,vs.Get("ACCPASS").c_str()); + if(DEBUG>=1)printf("Account Password set to \"%s\"\n",accpass); + } + if(vs.Exists("ALLOWCONTROLLER")){ + std::string opt=vs.Get("ALLOWCONTROLLER"); + if( opt=="1" || opt=="true" || opt=="on" ){ + allowcontroller=true; + }else{ + allowcontroller=false; + } + } + if(vs.Exists("EXITONERROR")){ + std::string opt=vs.Get("EXITONERROR"); + if( opt=="1" || opt=="true" || opt=="on" ){ + exitonerror=true; + }else{ + exitonerror=false; + } + } + if(vs.Exists("CONTROLLERPORT")){ + c_port=atoi(vs.Get("CONTROLLERPORT").c_str()); + if(DEBUG>=1)printf("Controller Port set to %d\n",c_port); + } + if(vs.Exists("REALMPORT")){ + rs_port=atoi(vs.Get("REALMPORT").c_str()); + if(DEBUG>=1)printf("Realm Server Port set to %d\n",rs_port); + } + if(vs.Exists("CLIENTVERSION")){ // e.g. 1.10.2 -- max number in this case is 255.255.255 -> address a matrix of 3x3 + std::string opt=vs.Get("CLIENTVERSION")+"."; + std::string num; + uint8 p=0; + for(uint8 i=0;i2) + break; + continue; + } + num+=opt.at(i); + } + DEBUG1(printf("Emulating client version %d.%d.%d\n",clientversion[0],clientversion[1],clientversion[2]);); + } + if(vs.Exists("CLIENTBUILD")){ + clientbuild=atoi(vs.Get("CLIENTBUILD").c_str()); + if(DEBUG>=1)printf("Client Build set to %d\n",clientbuild); + } + if(vs.Exists("CLIENTLANG")){ + char *opt=(char*)vs.Get("CLIENTLANG").c_str(); + clientlang[0]=opt[0]; + clientlang[1]=opt[1]; + clientlang[2]=opt[2]; + clientlang[3]=opt[3]; + DEBUG1(printf("Client language set to \"%c%c%c%c\"\n",clientlang[0],clientlang[1],clientlang[2],clientlang[3]);); + } + if(vs.Exists("REALMNAME")){ + strcpy(realmname,vs.Get("REALMNAME").c_str()); + if(DEBUG>=1)printf("Realm Name set to \"%s\"\n",realmname); + } + if(vs.Exists("CHARNAME")){ + charname=vs.Get("CHARNAME"); + if(DEBUG>=1)printf("Character Name set to \"%s\"\n",charname.c_str()); + } + if(vs.Exists("IDLESLEEPTIME")){ + idleSleepTime=atoi(vs.Get("IDLESLEEPTIME").c_str()); + if(DEBUG>=1)printf("Idle Sleep Time set to \"%u\"\n",idleSleepTime); + } + + defScp.RunScriptByName("_setconf",NULL,255); + + // more conf? + +} + + diff --git a/src/Client/ConfigReader.h_ b/src/Client/ConfigReader.h_ new file mode 100644 index 0000000..a816a49 --- /dev/null +++ b/src/Client/ConfigReader.h_ @@ -0,0 +1,15 @@ +#ifndef _CONFIGREADER_H +#define _CONFIGREADER_H + +#include "DefScript/DefScript.h" + +namespace ConfigReader { + + bool ReadConf(std::string, VarSet&, bool); + void SetMainConf(VarSet&); + void SetUsersConf(VarSet&); + + +}; + +#endif diff --git a/src/Client/DefScript/DefScript.cpp b/src/Client/DefScript/DefScript.cpp new file mode 100644 index 0000000..29681f9 --- /dev/null +++ b/src/Client/DefScript/DefScript.cpp @@ -0,0 +1,639 @@ +#include +#include +#include +#include +#include +#include +#include "VarSet.h" +#include "DefScript.h" +#include "DefScriptFunctions.h" + +struct DefScriptXChgResult { + std::string str; + bool change; +}; + +// --- SECTION FOR SCRIPT PACKAGES --- +DefScriptPackage::DefScriptPackage(){ + scripts=0; + Script=NULL; + curIsDebug=false; + recursionLevel=0; + functions=0; + functionTable=_GetFunctionTable(); + + + +// printf("---> DefScriptPackage inited!\n"); +} + +DefScriptPackage::~DefScriptPackage(){ + Clear(); +} + +void DefScriptPackage::SetParentMethod(void *p) +{ + parentMethod = p; +} + +void DefScriptPackage::Clear(void){ + //for(unsigned int i=0;iscripts) return NULL; + return Script[id].GetName(); +} + +// returns array position! +unsigned int DefScriptPackage::GetScriptID(std::string name){ + for(unsigned int i=0;i Script '" << sn << "' [" << fn << "] successfully loaded.\n"; + + // ... + if(increase_flag) scripts++; + return true; +} + + +// --- SECTION FOR THE INDIVIDUAL SCRIPTS IN A PACKAGE --- + +DefScript::DefScript(){ + lines=0; + Line=NULL; + permission=0; + scriptname="{NONAME}"; + debugmode=false; +// printf("--> DefScript inited!\n"); +} + +DefScript::~DefScript(){ + Clear(); +} + +void DefScript::Clear(void){ + //if(lines) + // delete [] Line; //?! causes crash! + Line=NULL; + lines=0; + permission=0; +} + +void DefScript::SetDebug(bool d){ + debugmode=d; +} + +bool DefScript::GetDebug(void){ + return debugmode; +} + +void DefScript::SetName(std::string name){ + scriptname=name; +} + +std::string DefScript::GetName(void){ + return scriptname; +} + +void DefScript::SetPermission(unsigned char p){ + permission=p; +} + +unsigned char DefScript::GetPermission(void){ + return permission; +} + +unsigned int DefScript::GetLines(void){ + return lines; +} + +std::string DefScript::GetLine(unsigned int id){ + if(id>lines) + return ""; + return Line[id]; +} + +bool DefScript::AddLine(std::string l){ + if(l.empty()) + return false; + std::string *Line_old=new std::string[lines]; + for(unsigned int i=0;iGetScripts()) + return false; + + curIsDebug=GetScript(id).GetDebug(); + + for(unsigned int cur_line=0;cur_line0 && t[i-1]=='$') + isVar=true; + if(!bo) + ob=i; + bo++; + } + + if(t[i]=='}') + { + bo--; + if(!bo) + { + if(!isVar) + { + unsigned int blen=i-ob+1; + std::string subStr=t.substr(ob,blen); + std::string retStr=RemoveBracketsFromString(subStr); + t.erase(ob,blen); + t.insert(ob,retStr); + i=ob-1; + + } + isVar=false; + } + } + } + + return t; +} + +CmdSet DefScriptPackage::RemoveBrackets(CmdSet oldSet){ + CmdSet Set=oldSet; + std::string t; + for(unsigned int a=0;a>ReplaceVars: '"<0 && str[i-1]=='$') + { + hasVar=true; + if(!bracketsOpen) + nextIsVar=true; + } + bracketsOpen++; + } + + if(str[i]=='}') + { + if(bracketsOpen) + bracketsOpen--; + if(!bracketsOpen) + { + closingBracket=i; + if(!nextIsVar && isVar && !hasVar) // remove brackets in var names, like ${var{ia}ble} + { + str.erase(closingBracket,1); + str.erase(openingBracket,1); + i-=2; + continue; + } + else + { + bLen=closingBracket-openingBracket-1; + subStr=str.substr(openingBracket+1,bLen); + retStr=ReplaceVars(subStr,pSet,nextIsVar,vardepth+(nextIsVar?1:0),sc_name); + if( hasVar && !nextIsVar && subStr!=retStr ) + { + str.erase(openingBracket+1,subStr.length()); + str.insert(openingBracket+1,retStr); + hasVar=false; + nextIsVar=false; + i-=(subStr.length()+1); + } + else if( hasVar && nextIsVar && subStr!=retStr ) + { + str.erase(openingBracket-1,bLen+3); // remove {... + i-=(bLen+2); // adjust position + str.insert(i,retStr); + //i--; + hasVar=false; + nextIsVar=false; + } + else + continue; + } + } + } // end if { + } // end for + if(!bracketsOpen && isVar && vardepth) + { + std::string vname=_NormalizeVarName(str, sc_name); + if(vname[0]=='@') + { + std::stringstream vns; + std::string subs=vname.substr(1,str.length()-1); + unsigned int vn=atoi( subs.c_str() ); + vns << vn; + if(pSet && vns.str()==subs) + str=pSet->arg[vn]; + else if(pSet && subs=="def") + str=pSet->defaultarg; + else if(pSet && subs=="cmd") + str=pSet->cmd; + //else if(pSet && subs=="parent") + // str=pSet->parent; + else if(variables.Exists(vname)) + str=variables.Get(vname); + else + { + // TODO: call custom macro table + //... + str.clear(); + } + + + } + else + if(variables.Exists(vname)) + str=variables.Get(vname); + else if(!variables.Exists(vname) && !subStr.empty()) + str="${"+str+"}"; + } + + + return str; +} + +std::string DefScriptPackage::_NormalizeVarName(std::string vn_in, std::string sn){ + std::string vn=vn_in; + if(sn.empty()) + return vn; + if(vn.at(0)=='#') + while(vn.at(0)=='#') + vn.erase(0,1); + else if(vn.at(0)=='@') + ;// do nothing for now + else + vn=sn+"::"+vn; + + return vn; +} + +bool DefScriptPackage::Interpret(CmdSet Set, std::string sc_name, unsigned char p){ + bool result=false; + + for(unsigned int i=0;result==false;i++){ + if(functionTable[i].func==NULL || functionTable[i].name==NULL){ // reached the end of the table? + break; + } + if(Set.cmd==functionTable[i].name){ + result=(this->*functionTable[i].func)(Set); + break; + } + } + + // if still nothing has been found its maybe a script command + if(!result){ + unsigned int perm=GetScript(GetScriptID(Set.cmd)).GetPermission(); + if(p +#include "VarSet.h" + +class DefScriptPackage; + +class CmdSet { + public: + CmdSet(); + ~CmdSet(); + void Clear(); + std::string cmd; + std::string arg[MAXARGS]; + std::string defaultarg; + DefScriptPackage *pack; + std::string caller; + void *ptr; +}; + +struct DefScriptFunctionTable { + char *name; + bool (DefScriptPackage::*func)(CmdSet Set); +}; + +class DefScript { +public: + DefScript(); + ~DefScript(); + std::string GetLine(unsigned int); + unsigned int GetLines(void); + bool AddLine(std::string ); + std::string GetName(void); + void SetName(std::string); + void SetPermission(unsigned char); + unsigned char GetPermission(void); + void Clear(void); + void SetDebug(bool); + bool GetDebug(void); + //DefScriptPackage *GetParent(void); + + +private: + std::string *Line; + unsigned int lines; + std::string scriptname; + unsigned char permission; + bool debugmode; + + //DefScriptPackage *_parent; + //CmdSet _mySet; + +}; + + +class DefScriptPackage { +public: + DefScriptPackage(); + ~DefScriptPackage(); + void SetParentMethod(void*); + void Clear(void); + DefScript GetScript(unsigned int); + unsigned int GetScripts(void); + bool LoadScriptFromFile(std::string,std::string); + bool RunScriptByName(std::string,CmdSet*,unsigned char); + bool RunScriptByID(unsigned int,CmdSet*,unsigned char); + std::string GetScriptName(unsigned int); + unsigned int GetScriptID(std::string); + bool RunSingleLine(std::string, unsigned char); + bool ScriptExists(std::string); + VarSet variables; + void SetPath(std::string); + bool LoadByName(std::string); + void SetFunctionTable(DefScriptFunctionTable*); + std::string _NormalizeVarName(std::string, std::string); + bool DefScriptPackage::CallFunction(bool *func, CmdSet *pSet); + + std::string scPath; + +private: + std::string ReplaceVars(std::string, CmdSet*, bool, unsigned int, std::string); // changes the string directly + CmdSet SplitLine(std::string); + bool Interpret(CmdSet, std::string, unsigned char); + CmdSet RemoveBrackets(CmdSet); + std::string RemoveBracketsFromString(std::string); + DefScriptFunctionTable *_GetFunctionTable(void) const; + + bool curIsDebug; + unsigned int scripts; + DefScript *Script; + unsigned int recursionLevel; + DefScriptFunctionTable *functionTable; + unsigned int functions; + void *parentMethod; + + std::map permissionMap; + + // Usable internal basic functions: + bool func_default(CmdSet); + bool func_set(CmdSet); + bool func_unset(CmdSet); + bool func_loaddef(CmdSet); + bool func_reloaddef(CmdSet); + bool func_out(CmdSet); + bool func_eof(CmdSet); + bool func_shdn(CmdSet); + + // Useable own internal functions: + bool SCpause(CmdSet); + bool SCSendChatMessage(CmdSet); + bool SCsavecache(CmdSet); + bool SCemote(CmdSet); + bool SCfollow(CmdSet); + +}; + + + +#endif \ No newline at end of file diff --git a/src/Client/DefScript/DefScriptFunctions.cpp b/src/Client/DefScript/DefScriptFunctions.cpp new file mode 100644 index 0000000..408bd13 --- /dev/null +++ b/src/Client/DefScript/DefScriptFunctions.cpp @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include "DefScript.h" + + + +bool DefScriptPackage::func_shdn(CmdSet Set){ + exit(0); + return true; +} + +bool DefScriptPackage::func_eof(CmdSet Set){ + // do nothing still + return true; +} + +bool DefScriptPackage::func_out(CmdSet Set){ + printf("%s\n",Set.defaultarg.c_str()); + return true; +} + +bool DefScriptPackage::func_loaddef(CmdSet Set){ + if( ScriptExists(Set.defaultarg) ) + return true; + bool result=false; + std::string fn; + if(Set.arg[0].empty()) + result=LoadByName(Set.defaultarg); + else + { + std::string::size_type pos = Set.arg[0].find('/'); + if(pos == std::string::npos) + fn=scPath+Set.arg[0]; + else + fn=Set.arg[0]; + result=LoadScriptFromFile(fn,Set.defaultarg); + } + //if(!result && curIsDebug) + // std::cout << "Could not load script '" << Set->defaultarg << "' [" << fn << "]\n"; + return result; +} + +bool DefScriptPackage::func_reloaddef(CmdSet Set){ + bool result=false; + std::string fn; + if(Set.arg[0].empty()) + result=LoadByName(Set.defaultarg); + else + { + std::string::size_type pos = Set.arg[0].find('/'); + if(pos == std::string::npos) + fn=scPath+Set.arg[0]; + else + fn=Set.arg[0]; + result=LoadScriptFromFile(fn,Set.defaultarg); + } + //if(!result && curIsDebug) + // std::cout << "Could not load script '" << Set->defaultarg << "' [" << fn << "]\n"; + return result; +} + +bool DefScriptPackage::func_unset(CmdSet Set){ + if(Set.defaultarg.empty()){ + //if(curIsDebug) + // printf("Can't unset, no variable name given.\n"); + return false; + } + if(Set.defaultarg.at(0)=='@'){ + //if(curIsDebug) + // printf("Can't unset macros!\n"); + return false; + } + std::string vn=_NormalizeVarName(Set.defaultarg, Set.caller); + variables.Unset(vn); + //std::cout<<"Unset var '"<defaultarg<<"'\n"; + return true; +} + +bool DefScriptPackage::func_set(CmdSet Set){ + if(Set.arg[0].empty()){ + //if(curIsDebug) + // printf("Can't assign value, no variable name given.\n"); + return false; + } + if(Set.arg[0].at(0)=='@'){ + //if(curIsDebug) + // printf("Can't assign value to a macro!\n"); + return false; + } + std::string vname,vval=Set.defaultarg; + vname=_NormalizeVarName(Set.arg[0], Set.caller); + + if(!stricmp(Set.arg[1].c_str(),"onfail") && vval.find("${")!=std::string::npos) + vval=Set.arg[2]; + + variables.Set(vname,vval); + + return true; +} + +bool DefScriptPackage::func_default(CmdSet Set){ + if(Set.arg[0].empty()){ + //if(curIsDebug) + // printf("Can't assign value, no variable name given.\n"); + return false; + } + if(Set.arg[0].at(0)=='@'){ + //if(curIsDebug) + // printf("Can't assign value to a macro!\n"); + return false; + } + std::string vname,vval=Set.defaultarg; + vname=_NormalizeVarName(Set.arg[0], Set.caller); + + if(variables.Get(vname).empty()) + variables.Set(vname,vval); // set only if it has no value + + return true; +} diff --git a/src/Client/DefScript/ParsingFunctions.cpp_ b/src/Client/DefScript/ParsingFunctions.cpp_ new file mode 100644 index 0000000..d694177 --- /dev/null +++ b/src/Client/DefScript/ParsingFunctions.cpp_ @@ -0,0 +1,50 @@ +#include +#include +#include +#include "ParsingFunctions.h" +#include "../GarbageStack.h" + +char *strparse::fgetlabel(char *line){ + //printf("Extracting label..."); + char *ret; + int i,len; + for(i=0;line[i]!='=';i++); + len=i; + ret=NewTempString(len); + for(i=0;i "blah \0/ crap\0" -> "blah \0" + } + return txt; +} + +char *strparse::TrimSpacesLeft(char *txt){ + int len=strlen(txt); + if(len<1)return txt; + for(int p=0;p<=len;p++) + if(txt[0]==' '||txt[0]==' ') + txt++; + else + return txt; +} + +bool strparse::HasEqual(char *in){ + if(strchr(in,(char)'=')==NULL)return false; else return true; +} diff --git a/src/Client/DefScript/ParsingFunctions.h_ b/src/Client/DefScript/ParsingFunctions.h_ new file mode 100644 index 0000000..9a4394b --- /dev/null +++ b/src/Client/DefScript/ParsingFunctions.h_ @@ -0,0 +1,10 @@ + +namespace strparse { + +char *fgetlabel(char*); +char *fgetvalue(char*); +char *RemoveComments(char*); +char *TrimSpacesLeft(char*); +bool HasEqual(char*); + +} \ No newline at end of file diff --git a/src/Client/DefScript/VarSet.cpp b/src/Client/DefScript/VarSet.cpp new file mode 100644 index 0000000..3f6d59a --- /dev/null +++ b/src/Client/DefScript/VarSet.cpp @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include "VarSet.h" + +VarSet::VarSet() +{ +} + +VarSet::~VarSet() +{ + Clear(); +} + +std::string VarSet::Get(std::string varname) +{ + for(std::list::iterator i=buffer.begin();i!=buffer.end();i++) + if( i->name==varname ) + return i->value; + return ""; // if var has not been set return empty string +} + +void VarSet::Set(std::string varname, std::string varvalue) +{ + if(varname.empty()) + return; + for(std::list::iterator i = buffer.begin();i!=buffer.end();i++) + { + if( i->name==varname ) + { + i->value=varvalue; + return; + } + } + Var v; + v.name=varname; + v.value=varvalue; + buffer.push_back(v); + return; +} + +unsigned int VarSet::Size(void) +{ + return buffer.size(); +} + +bool VarSet::Exists(std::string varname) +{ + for(std::list::iterator i = buffer.begin();i!=buffer.end();i++) + if(i->name==varname) + return true; + return false; +} + +void VarSet::Unset(std::string varname) +{ + if ( varname.empty() ) + return; + for(std::list::iterator i = buffer.begin();i!=buffer.end();i++) + { + if(i->name==varname) + { + buffer.erase(i); + return; + } + } +} + +void VarSet::Clear(void) +{ + buffer.clear(); +} + +bool VarSet::ReadVarsFromFile(std::string fn) +{ + std::fstream fh; + std::string line,prefix,vn,vv; + char c; + bool upper=false,lower=false; + + fh.open(fn.c_str(),std::ios_base::in); + if( !fh.is_open() ) + return false; + while(!fh.eof()) + { + c=fh.get(); + if(c=='\n') + { + vn.clear(); + vv.clear(); + while(line.at(0)==' ' || line.at(0)=='\t') + line.erase(0,1); + while(line.at(line.length()-1)==' ' || line.at(line.length()-1)=='\t') + line.erase(line.length(),1); + if(line.empty() || (line.at(0)=='/' && line.at(0)=='/') ) + continue; + if(line.at(0)=='[' && line.at(line.length()-1)==']') + { + prefix=line.substr(1,line.length()-2); + if(!prefix.empty()) + { + if(prefix.at(0)=='#') + prefix=toLower(prefix); + if(prefix=="#uppercase") + { + upper=true; + lower=false; + } + else if(prefix=="#normal") + { + upper=false; + lower=false; + } + else if(prefix=="#lowercase") + { + lower=true; + upper=false; + } + else + { + prefix+="::"; + } + } + } + else + { + unsigned int pos=line.find("="); + if(pos) + { + std::string v=line.substr(0,pos-1);; + + if(upper) + v=toUpper(v); + else if(lower) + v=toLower(v); + + vn=prefix+v; + vv=line.substr(pos+1,line.length()-1); + Set(vn,vv); + } + // else invalid line, must have '=' + } + line.clear(); + } + else + line+=c; // fill up line until a newline is reached (see above) + } + fh.close(); + return true; +} + +std::string VarSet::toLower(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), std::tolower); + return s; +} + +std::string VarSet::toUpper(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), std::toupper); + return s; +} + + + + \ No newline at end of file diff --git a/src/Client/DefScript/VarSet.h b/src/Client/DefScript/VarSet.h new file mode 100644 index 0000000..7c1bf16 --- /dev/null +++ b/src/Client/DefScript/VarSet.h @@ -0,0 +1,35 @@ +#ifndef __VARSET_H +#define __VARSET_H + +#include +#include + + +struct Var { + std::string name, value; +}; + + +class VarSet { +public: + void Set(std::string,std::string); + std::string Get(std::string); + void Clear(void); + void Unset(std::string); + unsigned int Size(void); + bool Exists(std::string); + bool ReadVarsFromFile(std::string fn); + VarSet(); + ~VarSet(); + // far future: MergeWith(VarSet,bool overwrite); + +private: + std::list buffer; + std::string toLower(std::string); + std::string toUpper(std::string); + + +}; + + +#endif \ No newline at end of file diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp new file mode 100644 index 0000000..9feef43 --- /dev/null +++ b/src/Client/DefScriptInterface.cpp @@ -0,0 +1,84 @@ +#ifndef __DEFSCRIPTINTERFACE_H +#define __DEFSCRIPTINTERFACE_H + +#include "common.h" +#include "PseuWoW.h" +#include "NameTables.h" +#include "DefScript/DefScript.h" +#include "Player.h" +#include "CMSGConstructor.h" +#include "Opcodes.h" +#include "SharedDefines.h" +#include "WorldSession.h" + + +bool DefScriptPackage::SCpause(CmdSet Set){ + SDL_Delay(atoi(Set.defaultarg.c_str())); + return true; +} + +bool DefScriptPackage::SCSendChatMessage(CmdSet Set){ + std::stringstream ss; + uint32 type=atoi(Set.arg[0].c_str()); + uint32 lang=atoi(Set.arg[1].c_str()); + ss << lang; + if(ss.str()!=Set.arg[1]) // given lang is NOT a number + { + for(uint32 i=0;i<=33;i++) + { + if(!stricmp(Set.arg[1].c_str(),LookupName(i,langNames))) + { + lang=i; + break; + } + } + } + std::string msg=Set.arg[2]; + std::string to=Set.arg[3]; + ((PseuInstance*)parentMethod)->GetWSession()->SendChatMessage(type,lang,msg,to); + return true; +} + +bool DefScriptPackage::SCsavecache(CmdSet Set){ + ((PseuInstance*)parentMethod)->SaveAllCache(); + std::stringstream tmp; + std::string str; + tmp << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize(); + str+="Cache saved. [ "+tmp.str()+ " Playernames ]"; + ((PseuInstance*)parentMethod)->GetWSession()->SendChatMessage(CHAT_MSG_SAY,0,str,""); + return true; + + +} + +bool DefScriptPackage::SCemote(CmdSet Set){ + if(Set.defaultarg.empty()) + return true; + uint32 id=atoi(Set.defaultarg.c_str()); + ((PseuInstance*)parentMethod)->GetWSession()->SendEmote(id); + return true; + + +} + +bool DefScriptPackage::SCfollow(CmdSet Set){ + WorldSession *ws=((PseuInstance*)parentMethod)->GetWSession(); + if(Set.defaultarg.empty()){ + ws->SendChatMessage(CHAT_MSG_SAY,0,"Stopping! (Please give me a Playername to follow!)",""); + ws->SetFollowTarget(0); + return true; + } + ws->SetFollowTarget(ws->plrNameCache.GetGuid(Set.defaultarg)); + std::stringstream ss; + if(ws->GetFollowTarget()) + ss << "Following player '"<SendChatMessage(CHAT_MSG_SAY,0,ss.str(),""); + return true; + +} + + + +#endif diff --git a/src/Client/DefScriptInterface.h b/src/Client/DefScriptInterface.h new file mode 100644 index 0000000..55b79bd --- /dev/null +++ b/src/Client/DefScriptInterface.h @@ -0,0 +1,15 @@ +#ifndef __DEFSCRIPTINTERFACE_H +#define __DEFSCRIPTINTERFACE_H + + + + + + + + +DefScriptFunctionTable *_GetSCTable(void); + + + +#endif \ No newline at end of file diff --git a/src/Client/NameTables.h b/src/Client/NameTables.h new file mode 100644 index 0000000..f13e8fb --- /dev/null +++ b/src/Client/NameTables.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 __NAMETABLES_H +#define __NAMETABLES_H + +struct NameTableEntry +{ + uint32 id; + const char *name; +}; + +inline const char* LookupName(uint32 id, NameTableEntry *table) +{ + for(uint32 i = 0; table[i].name != 0; i++) + { + if (table[i].id == id) + return table[i].name; + } + + return "UNKNOWN"; +} + +extern NameTableEntry g_worldOpcodeNames[]; +extern char *className[],*raceName[]; +extern NameTableEntry langNames[]; +#endif diff --git a/src/Client/Pseu1.ico b/src/Client/Pseu1.ico new file mode 100644 index 0000000..11e6b5a Binary files /dev/null and b/src/Client/Pseu1.ico differ diff --git a/src/Client/PseuWoW.aps b/src/Client/PseuWoW.aps new file mode 100644 index 0000000..22dc5a4 Binary files /dev/null and b/src/Client/PseuWoW.aps differ diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp new file mode 100644 index 0000000..31012c3 --- /dev/null +++ b/src/Client/PseuWoW.cpp @@ -0,0 +1,303 @@ +#include "common.h" +#include "PseuWoW.h" +#include +#include + +#include "Auth/ByteBuffer.h" +#include "DefScript/DefScript.h" +#include "DefScriptInterface.h" +#include "Auth/BigNumber.h" +#include "Auth/ByteBuffer.h" +#include "DefScript/DefScript.h" +#include "Realm/RealmSocket.h" +#include "World/WorldSession.h" + +/* TODO: +defscriptpackage fix, xchgresult einbauen, CmdSet.caller einbauen, permissionmap einbauen +WorldSesssion::Update() rein +opcode handler table vervollstädigen + funktionen dafür umschreiben + +*/ + +//###### Start of program code ####### + +void PseuInstanceRunnable::run(void) +{ + PseuInstance *_i = new PseuInstance(); + _i->SetConfDir("./conf/"); + _i->SetScpDir("./scripts/"); + _i->Init(); + // more + _i->Run(); + delete _i; +} + +bool PseuInstance::Init(void) { + + if(_confdir.empty()) + _confdir="./conf/"; + if(_scpdir.empty()) + _scpdir="./scp/"; + + srand((unsigned)time(NULL)); + RAND_set_rand_method(RAND_SSLeay()); // init openssl randomizer + + if(SDL_Init(0)==-1) { + printf("SDL_Init: %s\n", SDL_GetError()); + return false; + } + + _scp=new DefScriptPackage(); + _scp->SetParentMethod((void*)this); + _conf=new PseuInstanceConf(); + _rsession=new RealmSocket(_sh); + _wsession=new WorldSession(this); + + if(!_scp->variables.ReadVarsFromFile(_confdir + "PseuWoW.conf")) + { + printf("Error reading conf file [%s]",_confdir.append("PseuoW.conf").c_str()); + return false; + } + _conf->ApplyFromVarSet(_scp->variables); + + if(!_scp->variables.ReadVarsFromFile(_confdir + "users.conf")) + { + //printf("-> Done.\n"); + } + else + { + printf("Error reading conf file [%s] - NO PERMISSIONS SET!",_confdir.append("users.conf").c_str()); + } + + +// //DEBUG1(printf("Main_Init: Setting up DefScripts path '%s'\n",defScpPath.c_str());); + _scp->SetPath(_scpdir); + + // //DEBUG1(printf("Main_Init: Setting up custom DefScript function interface...\n");); + //_scp->SetFunctionTable(_GetSCTable()); + + // //DEBUG1(printf("Main_Init: Setting up predefined DefScript macros...\n");); + _scp->variables.Set("@version_short",_ver_short); + _scp->variables.Set("@version",_ver); + + + // //DEBUG1(printf("Main_Init: Loading DefScripts from folder '%s'\n",defScpPath.c_str());); + if(!_scp->RunScriptByName("_startup",NULL,255)){ + printf("Main_Init: Error executing '_startup.def'\n"); + } + + if(_stop){ + printf("Errors while initializing, proc halted!!\n"); + if(GetConf()->exitonerror) + exit(0); + while(true)SDL_Delay(1000); + } + +// if(DEBUG)printf("Main_Init: Init complete.\n"); + _initialized=true; + return true; +} + +void PseuInstance::SetConfDir(std::string path) +{ + _confdir=path; +} + +void PseuInstance::SetScpDir(std::string path) +{ + _scpdir=path; +} + +void PseuInstance::Run(void) +{ + if(!_initialized) + return; + + + _rsession->SetHost(GetConf()->realmlist); + _rsession->SetPort(GetConf()->realmport); + _rsession->Start(); + + if(_rsession->IsValid()) + { + _sh.Add(_rsession); + _rsession->SendLogonChallenge(); + _sh.Select(1,0); + } + + while(!_stop) + { + Update(); + } + // save all data here + +} + +void PseuInstance::Update() +{ + if(_sh.GetCount()) + _sh.Select(1,0); // update the realmsocket + //else + // socket invalid + + _wsession->Update(); + +} + + + + /* + printf("%s\n",ver); + for(unsigned int temp=0;temp<=strlen(ver);temp++)printf("~");printf("\n"); + printf("[Compiled on: %s , %s]\n\n",__DATE__,__TIME__); + if (!initproc()) quitproc_error(); + + bool _auth_sent=false; + bool _first_wpacket=true; + clock_t ping_time=clock()-25000; + + while (true) { + + if(something_went_wrong){ + if(inworld){ + SendChatMessage(CHAT_MSG_YELL,0,"ERROR! Something went wrong, exiting...",""); + } + printf("!!! Something went wrong, proc halted.!!!\n"); + ctrlCon.Close(); + worldCon.Close(); + realmCon.Close(); + if(exitonerror)quitproc(); + while(true)SDL_Delay(1000); + } + + if( !realmCon.IsConnected() && !worldCon.IsConnected() && !something_went_wrong){ + printf("Opening realm TCP connection <%s:%d>\n",realmlist,rs_port); + while(!realmCon.ConnectTo(realmlist,rs_port)); + _auth_sent=false; + } + + if(realmCon.IsConnected() && !worldCon.IsConnected() && !something_went_wrong){ + if(!_auth_sent){ + CLIENT_LOGON_CHALLENGE(accname, accpass); + _auth_sent=true; + } + } + if(realmCon.HasData()){ + Buf buf; + buf=realmCon.GetData(); + rs_parser(buf.str,buf.len); // TODO: change type to Buf (also the func arg!) + } + + + + while(worldCon.GetBufferLevel()>1){ + ////DEBUG3( + // printf("WS_IN, %d bytes. Buffer Level=%u\n",worldCon.GetKeepData().len,worldCon.GetBufferLevel()); + // printchex(worldCon.GetKeepData().str,worldCon.GetKeepData().len,true); + //) + //_first_wpacket=false; + ByteBuffer pk2; + pk2.append(worldCon.GetDataString()); + pk2.resize(pk2.size()-1); + HandleWorldPacket(pk2); + } + + // this covers the first serverseed packet, which get sometimes merged into 1 packet instead of 2 + if(worldCon.HasData() && _first_wpacket && worldCon.GetKeepData().len==8){ + _first_wpacket=false; + ByteBuffer pk2; + pk2.append(worldCon.GetDataString()); + pk2.resize(pk2.size()-1); + HandleWorldPacket(pk2); + } + + + if(!worldCon.IsConnected() && inworld){ + printf("Disconnected from World server!\n"); + inworld=false; + _first_wpacket=true; + _auth_sent=false; + } + + if(clock()-ping_time>30000) + { + ping_time=clock(); + SendPing(ping_time); + } + + + SDL_Delay(idleSleepTime); + if (error)return error; + + + + +void _SaveAllCache(void){ + bool result; + result=plrNameCache.SaveToFile(); + // +++ +} +*/ + + +PseuInstance::PseuInstance() +{ + _ver="PseuWoW Alpha Build 12 dev 2" DEBUG_APPENDIX; + _ver_short="A12-dev1" DEBUG_APPENDIX; + _wsession=NULL; + _rsession=NULL; + + +} + +PseuInstanceConf::PseuInstanceConf() +{ +} + +void PseuInstanceConf::ApplyFromVarSet(VarSet &v) +{ + debug=atoi(v.Get("DEBUG").c_str()); + realmlist=v.Get("REALMLIST"); + accname=v.Get("ACCNAME"); + accpass=v.Get("ACCPASS"); + exitonerror=(bool)atoi(v.Get("EXITONERROR").c_str()); + realmport=atoi(v.Get("REALMPORT").c_str()); + clientversion_string=v.Get("CLIENTVERSION"); + clientbuild=atoi(v.Get("CLIENTBUILD").c_str()); + clientlang=v.Get("CLIENTLANG"); + realmname=v.Get("REALMNAME"); + charname=v.Get("CHARNAME"); + networksleeptime=atoi(v.Get("NETWORKSLEEPTIME").c_str()); + + // clientversion is a bit more complicated to add + { + std::string opt=clientversion_string + "."; + std::string num; + uint8 p=0; + for(uint8 i=0;i2) + break; + continue; + } + num+=opt.at(i); + } + } +} + + + + +PseuInstanceConf::~PseuInstanceConf() +{ + //... +} + + + + diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h new file mode 100644 index 0000000..9417adb --- /dev/null +++ b/src/Client/PseuWoW.h @@ -0,0 +1,148 @@ + +#ifndef _PSEUWOW_H +#define _PSEUWOW_H + +#include "../shared/common.h" +#include "Auth/BigNumber.h" +#include "DefScript/DefScript.h" +#include "../shared/Network/SocketHandler.h" + + +class RealmSocket; +class WorldSession; +class Sockethandler; + +class PseuInstanceConf +{ + public: + + PseuInstanceConf(); + ~PseuInstanceConf(); + void ApplyFromVarSet(VarSet &v); + + + uint8 debug; + std::string realmlist; + std::string accname; + std::string accpass; + bool exitonerror; + uint16 realmport; + uint16 worldport; + uint8 clientversion[3]; + std::string clientversion_string; + uint16 clientbuild; + std::string clientlang; + std::string realmname; + std::string charname; + std::string worldhost; + uint16 networksleeptime; + + +}; + + +class PseuInstance +{ + public: + + PseuInstance(); + ~PseuInstance(); + + + WorldSession *GetWSession(void); + RealmSocket *GetRSession(void); + PseuInstanceConf *GetConf(void); + DefScriptPackage *GetScripts(void); + void SetConfDir(std::string); + void SetScpDir(std::string); + void SetSessionKey(BigNumber); + BigNumber GetSessionKey(void); + + + + + bool Init(); + void SaveAllCache(void); + void Stop(void) { _stop = true; } + void Quit(void); + void Run(void); + void Update(void); + + + + private: + + RealmSocket *_rsession; + WorldSession *_wsession; + PseuInstanceConf *_conf; + DefScriptPackage *_scp; + std::string _confdir,_scpdir; + bool _initialized; + bool _stop; + BigNumber _sessionkey; + char *_ver,*_ver_short; + SocketHandler _sh; + + +}; + +class PseuInstanceRunnable : public ZThread::Runnable +{ +public: + void run(); +}; + + + + +// OBOELETE +/* + +class SDLTCPConnection; +class DefScriptPackage; +class PlayerNameCache; +class VarSet; + +extern char DEBUG; +extern char *ver; +extern char *realmlist,*accname,*accpass,*realmname; +extern bool quit,quitted,exitonerror; +extern unsigned char error; +extern unsigned char clientversion[3]; +extern unsigned short clientbuild; +extern char clientlang[4]; +extern bool something_went_wrong; + +extern unsigned int c_port; +extern bool allowcontroller; +extern char *c_password; + +extern unsigned int rs_port; +extern unsigned short clientbuild; +extern char clientlang[4]; + +extern unsigned int ws_port; +extern std::string worldhost, charname; +extern SDLTCPConnection worldCon,realmCon,ctrlCon; +extern bool inworld; +extern unsigned short idleSleepTime; + +extern DefScriptPackage defScp; +extern std::string defScpPath; + +extern PlayerNameCache plrNameCache; + +extern VarSet playerPermissions; + +extern uint64 _myGUID, _targetGUID, _followGUID; + + +// --- Some Functions --- + +void quitproc_error(void); +void quitproc(void); +void _SaveAllCache(void); + +*/ + +#endif \ No newline at end of file diff --git a/src/Client/PseuWoW.rc b/src/Client/PseuWoW.rc new file mode 100644 index 0000000..99a9f98 --- /dev/null +++ b/src/Client/PseuWoW.rc @@ -0,0 +1,84 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "Pseu1.ico" +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/Client/RCa00480 b/src/Client/RCa00480 new file mode 100644 index 0000000..f995162 Binary files /dev/null and b/src/Client/RCa00480 differ diff --git a/src/Client/ReadMe.txt b/src/Client/ReadMe.txt new file mode 100644 index 0000000..8f43536 --- /dev/null +++ b/src/Client/ReadMe.txt @@ -0,0 +1,34 @@ +======================================================================== + CONSOLE APPLICATION : PseuWoW +======================================================================== + + +AppWizard has created this PseuWoW application for you. + +This file contains a summary of what you will find in each of the files that +make up your PseuWoW application. + +PseuWoW.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +PseuWoW.cpp + This is the main application source file. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named PseuWoW.pch and a precompiled types file named StdAfx.obj. + + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/Client/Realm/RealmAuth.cpp_ b/src/Client/Realm/RealmAuth.cpp_ new file mode 100644 index 0000000..fa94107 --- /dev/null +++ b/src/Client/Realm/RealmAuth.cpp_ @@ -0,0 +1,150 @@ +#include "basics.h" +#include "PseuWoW.h" +#include "RealmAuth.h" +#include "Auth/BigNumber.h" +#include "Auth/Sha1.h" +#include "realmfunc.h" + +#define BNLEN 32 // length of the hard-coded N blizz uses, has been 32 since the first alpha of WoW + +extern BigNumber sessionkey; // defined in WorldPacketHandler.cpp + +void ProcessClientLogonProof(char *pkt){ + BigNumber N,A,B,a,u,x,v,S,salt,unk1,g,k(3); // init BNs, default k to 3 + char _auth[128]; + strcpy(_auth,strupr(accname)); + strcat(_auth,":"); + strcat(_auth,strupr(accpass)); + DEBUG3(printf("Authentication String=\"%s\"\n",_auth);) + char N_str[BNLEN+1],g_str[2],salt_str[BNLEN+1],unk1_str[16+1],B_str[BNLEN+1]; // +1 for '\0' + + // extract data from packet + memcpy(B_str,&pkt[3],32);B_str[32]=0; + memcpy(g_str,&pkt[36],1);g_str[1]=0; + memcpy(N_str,&pkt[38],32);N_str[32]=0; + memcpy(salt_str,&pkt[70],32);salt_str[32]=0; + memcpy(unk1_str,&pkt[102],16);unk1_str[16]=0; + + // debug output + DEBUG3(printchex(B_str,BNLEN,true);) + DEBUG3(printchex(g_str,1,true);) + DEBUG3(printchex(N_str,BNLEN,true);) + DEBUG3(printchex(salt_str,BNLEN,true);) + DEBUG3(printchex(unk1_str,16,true);) + + // convert into BigNumbers + B.SetBinary((const uint8*)B_str,BNLEN); + g.SetBinary((const uint8*)g_str,1); + N.SetBinary((const uint8*)N_str,BNLEN); + salt.SetBinary((const uint8*)salt_str,BNLEN); + unk1.SetBinary((const uint8*)unk1_str,16); + + // client-side BN calculations: + DEBUG3(printf("--> k=%s\n",k.AsHexStr());) + a.SetRand(19*8); + Sha1Hash userhash,xhash,uhash; + std::string _authstr(_auth); + userhash.UpdateData(_authstr); + userhash.Finalize(); + xhash.UpdateData(salt.AsByteArray(),salt.GetNumBytes()); + xhash.UpdateData(userhash.GetDigest(),userhash.GetLength()); + xhash.Finalize(); + x.SetBinary(xhash.GetDigest(),xhash.GetLength()); + DEBUG3(printf("--> x=%s\n",x.AsHexStr());) + v=g.ModExp(x,N); + DEBUG3(printf("--> v=%s\n",v.AsHexStr());) + A=g.ModExp(a,N); + DEBUG3(printf("--> A=%s\n",A.AsHexStr());) + uhash.UpdateBigNumbers(&A, &B, NULL); + uhash.Finalize(); + u.SetBinary(uhash.GetDigest(), 20); + DEBUG3(printf("--> u=%s\n",u.AsHexStr());) + S=(B - k*g.ModExp(x,N) ).ModExp((a + u * x),N); + DEBUG3(printf("--> S=%s\n",S.AsHexStr());) + + // calc M1 & M2 + unsigned int i=0; + char S1[16+1],S2[16+1]; // 32/2=16 :) +1 for \0 + // split it into 2 seperate strings, interleaved + + for(i=0;i<=15;i++){ + S1[i]=S.AsByteArray()[i*2]; + S2[i]=S.AsByteArray()[i*2+1]; + } + //printchex(S1);printchex(S2); + // hash each one: + Sha1Hash S1hash,S2hash; + S1hash.UpdateData((const uint8*)S1,16); + S1hash.Finalize(); + S2hash.UpdateData((const uint8*)S2,16); + S2hash.Finalize(); + // Re-combine them + char S_hash[40+1]; // 2*Sha1Len+1 for \0 + for(i=0;i<20;i++){ + S_hash[i*2]=S1hash.GetDigest()[i]; + S_hash[i*2+1]=S2hash.GetDigest()[i]; + } + sessionkey.SetBinary((uint8*)S_hash,40); // used later when authing to world + //printf("-> S_hash=");printchex(S_hash,40,true); + + char Ng_hash[20+1]; + Sha1Hash userhash2,Nhash,ghash; + userhash2.UpdateData((const uint8*)strupr(accname),strlen(accname)); + userhash2.Finalize(); + //printchex((char*)userhash2.GetDigest(),userhash2.GetLength(),true); + Nhash.UpdateBigNumbers(&N,NULL); + Nhash.Finalize(); + ghash.UpdateBigNumbers(&g,NULL); + ghash.Finalize(); + for(i=0;i<20;i++)Ng_hash[i] = Nhash.GetDigest()[i]^ghash.GetDigest()[i]; + //printchex(Ng_hash,20,true); + + BigNumber t_acc,t_Ng_hash; + t_acc.SetBinary((const uint8*)userhash2.GetDigest(),userhash2.GetLength()); + t_Ng_hash.SetBinary((const uint8*)Ng_hash,20); + + + Sha1Hash M1hash,M2hash; + + M1hash.UpdateBigNumbers(&t_Ng_hash,&t_acc,&salt,&A,&B,NULL); + M1hash.UpdateData((const uint8*)S_hash,40); + M1hash.Finalize(); + + M2hash.UpdateBigNumbers(&A,NULL); + M2hash.UpdateData((const uint8*)M1hash.GetDigest(),M1hash.GetLength()); + M2hash.UpdateData((const uint8*)S_hash,40); + M2hash.Finalize(); + + + DEBUG3( + printf("--> M1=");printchex((char*)M1hash.GetDigest(),20,true);\ + printf("--> M2=");printchex((char*)M2hash.GetDigest(),20,true);\ + ) + + // Calc CRC & CRC_hash + // i don't know yet how to calc it, so set it to zero + char crc_hash[20+1]; + nullify(crc_hash,20); + + + // now lets prepare the packet + DEBUG2(printf("Calculations finished, preparing packet...\n");) + char outpkt[100]; + memset(outpkt,0,100); + outpkt[0]=0x01; // opcode: CLIENT_GOGON_PROOF + memcpy(&outpkt[1],A.AsByteArray(),BNLEN); + memcpy(&outpkt[33],M1hash.GetDigest(),M1hash.GetLength()); + memcpy(&outpkt[53],crc_hash,20); // TODO: as soon as crc_hash is calculated, correct this line! + outpkt[73]=0; // number_of_keys=0 + outpkt[74]=0; // unk=0 (added in 1.12.1) + DEBUG3(printf("... finished, packet content=");printchex(outpkt,73,true);) + memcpy(Auth_M2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later + DEBUG2(printf("Sending packet\n");) + if(clientbuild>5302) + realmCon.Send(outpkt,75); // 1.11.x and upwards + else + realmCon.Send(outpkt,74); // < 1.11.x compatibility + + + +} \ No newline at end of file diff --git a/src/Client/Realm/RealmAuth.h_ b/src/Client/Realm/RealmAuth.h_ new file mode 100644 index 0000000..940da86 --- /dev/null +++ b/src/Client/Realm/RealmAuth.h_ @@ -0,0 +1,6 @@ +#ifndef _REALMAUTH_H +#define _REALMAUTH_H + +void ProcessClientLogonProof(char*); + +#endif \ No newline at end of file diff --git a/src/Client/Realm/RealmListHandler.cpp_ b/src/Client/Realm/RealmListHandler.cpp_ new file mode 100644 index 0000000..6202214 --- /dev/null +++ b/src/Client/Realm/RealmListHandler.cpp_ @@ -0,0 +1,62 @@ +#include "basics.h" +#include "PseuWoW.h" +#include "Auth/ByteBuffer.h" +#include "RealmListHandler.h" +#include "realmfunc.h" + +// process a given realmlist packet + +struct SRealmInfo + { + uint32 icon; // icon near realm + uint8 color; // color of record + std::string name; // Text zero terminated name of Realm + std::string addr_port; // Text zero terminated address of Realm ("ip:port") + float population; // 1.6 -> population value. lower == lower population and vice versa + uint8 chars_here; // number of characters on this server + uint8 timezone; // timezone + uint8 unknown; // + } * realms; + + + +bool HandleRealmList(ByteBuffer pkt){ + uint8 PosOfRealm=0; + bool FoundRealm=false; + uint32 i=0,pktpos=0, unk1=0; + uint16 datalen; + uint8 count, trash; + pkt >> trash >> datalen >> unk1 >> count; + DEBUG3(printf("Length of realm data: %d\n",datalen);) + DEBUG1(printf("Realms in List: %d\n",count);); + if(count==0) + something_went_wrong=true; + realms=new SRealmInfo[count]; + for(i=0;i> realms[i].icon >> realms[i].color >> realms[i].name >> realms[i].addr_port >> realms[i].population >> realms[i].chars_here >> realms[i].timezone >> realms[i].unknown; + if(stricmp(realmname,realms[i].name.c_str())==0){PosOfRealm=i;FoundRealm=true;} + printf("Realm: %s (%s)",realms[i].name.c_str(),realms[i].addr_port.c_str()); + DEBUG1(printf("[chars:%d][population:%f][timezone:%d]",realms[i].chars_here,realms[i].population,realms[i].timezone);); + printf("\n"); + } + // the rest of the packet is not interesting + + // now setup where the woldserver is and how to login there + if(!FoundRealm){ + printf("Realm \"%s\" was not found on the realmlist!\n",realmname); + something_went_wrong=true; + realmCon.Close(); + return false; + } + + // transform "hostname:port" into something useful + // -> convert the worldserver port from string to int + // -> and remove it from the hostname, then write the remains into worldhost + + uint16 colonpos=realms[PosOfRealm].addr_port.find(":"); + worldhost=realms[PosOfRealm].addr_port.substr(0,colonpos); + ws_port=atoi(realms[PosOfRealm].addr_port.substr(colonpos+1,realms[PosOfRealm].addr_port.length()-colonpos-1).c_str()); + + return true; + +} \ No newline at end of file diff --git a/src/Client/Realm/RealmListHandler.h_ b/src/Client/Realm/RealmListHandler.h_ new file mode 100644 index 0000000..eef919a --- /dev/null +++ b/src/Client/Realm/RealmListHandler.h_ @@ -0,0 +1,6 @@ +#ifndef _REALMLISTHANDLER_H +#define _REALMLISTHANDLER_H + +bool HandleRealmList(ByteBuffer); + +#endif \ No newline at end of file diff --git a/src/Client/Realm/RealmSocket.cpp b/src/Client/Realm/RealmSocket.cpp new file mode 100644 index 0000000..d299440 --- /dev/null +++ b/src/Client/Realm/RealmSocket.cpp @@ -0,0 +1,466 @@ +#include "common.h" +#include "PseuWoW.h" +#include "Auth/ByteBuffer.h" +#include "Auth/Sha1.h" +#include "Auth/BigNumber.h" +#include "RealmSocket.h" + + + +enum AuthCmd +{ + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + REALM_LIST = 0x10, +}; + +struct SRealmHeader +{ + uint8 cmd; // OP code = CMD_REALM_LIST + uint16 size; // size of the rest of packet, without this part + uint32 unknown; // 0x00 00 00 00 + uint8 count; // quantity of realms +}; + +struct SRealmInfo +{ + uint32 icon; // icon near realm + uint8 color; // color of record + std::string name; // Text zero terminated name of Realm + std::string addr_port; // Text zero terminated address of Realm ("ip:port") + float population; // 1.6 -> population value. lower == lower population and vice versa + uint8 chars_here; // number of characters on this server + uint8 timezone; // timezone + uint8 unknown; // +}; + +struct AuthHandler +{ + uint32 cmd; + void (RealmSocket::*handler)(void); +}; + +struct sAuthLogonChallenge_S +{ + uint8 cmd; + uint8 error; + uint8 unk2; + uint8 B[32]; + uint8 g_len; + uint8 g[1]; + uint8 N_len; + uint8 N[32]; + uint8 salt[32]; + uint8 unk3[16]; +}; + +struct sAuthLogonProof_S +{ + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk2; +}; + +const AuthHandler table[]= +{ + {AUTH_LOGON_CHALLENGE,&RealmSocket::_HandleLogonChallenge}, + {AUTH_LOGON_PROOF,&RealmSocket::_HandleLogonProof}, + {REALM_LIST,&RealmSocket::_HandleRealmList}, + {0,NULL} +}; + +RealmSocket::RealmSocket(SocketHandler& h) : TcpSocket(h) +{ + _instance=NULL; + _valid=false; + _rport=3724; +} + +RealmSocket::~RealmSocket() +{ + Stop(); +} + +bool RealmSocket::IsValid(void) +{ + return _valid; +} + +void RealmSocket::SetHost(std::string h) +{ + _rhost=h; +} + +void RealmSocket::SetPort(uint16 p) +{ + _rport=p; +} + +void RealmSocket::SetInstance(PseuInstance *pi) +{ + _instance=pi; +} + +void RealmSocket::Start(void) +{ + if(this->_rhost.empty() || _rport==0 || !_valid || _instance==NULL) + return; + +// _socket.Init() +// _socket.SetHost(_host); +// _socket.SetPort(_port); + Open(_rhost,_rport); + //... + _valid=true; +} + +void RealmSocket::Stop(void) +{ + _valid=false; + this->Close(); + memset(_m2,0,20); + _key=0; +} + +void RealmSocket::_HandleRealmList(void) +{ + SRealmHeader hd; + std::string realmAddr; + ibuf.Read((char*)&hd, sizeof(SRealmHeader)); // TODO: FIX THIS ITS NOT CORRECT!!!!! + + + ////DEBUG1(printf("Realms in List: %d\n",count);); + // no realm?! + if(hd.count==0) + return; + + // alloc space for as many realms as needed + SRealmInfo *realms=new SRealmInfo[hd.count]; + + // readout realms + for(uint8 i=0;iGetConf()->realmname) + { + realmAddr=realms[i].addr_port; + } + printf("Realm: %s (%s)",realms[i].name.c_str(),realms[i].addr_port.c_str()); + printf("[chars:%d][population:%f][timezone:%d]",realms[i].chars_here,realms[i].population,realms[i].timezone); + printf("\n"); + } + + // now setup where the woldserver is and how to login there + if(realmAddr.empty()){ + printf("Realm \"%s\" was not found on the realmlist!\n",GetInstance()->GetConf()->realmname.c_str()); + //something_went_wrong=true; + //realmCon.Close(); + return; + } + + // transform "hostname:port" into something useful + // -> convert the worldserver port from string to int + // -> write it into the config & set appropriate vars + + uint16 colonpos=realmAddr.find(":"); + GetInstance()->GetConf()->worldhost=realmAddr.substr(0,colonpos); + GetInstance()->GetConf()->worldport=atoi(realmAddr.substr(colonpos+1,realmAddr.length()-colonpos-1).c_str()); + // set vars + GetInstance()->GetScripts()->variables.Set("WORLDHOST",GetInstance()->GetConf()->worldhost); + GetInstance()->GetScripts()->variables.Set("WORLDPORT",toString((uint64)(GetInstance()->GetConf()->worldport))); +} + + +void RealmSocket::OnRead(void) +{ + TcpSocket::OnRead(); + if(!ibuf.GetLength()) + return; + uint8 cmd, i=0; + ibuf.SoftRead((char*)&cmd, 1); + while(table[i].handler!=NULL) + { + if(table[i].cmd==cmd) + { + (*this.*table[i].handler)(); + break; + } + } + // unk packet +} + +/* + switch(rs_state){ + unsigned int i; + case 1:{ + if(pkt[2]==4){ + printf("Realm Server did not find account \"%s\"!\n",accname); + something_went_wrong=true; + realmCon.Close(); + } else + if(pkt[2]==6){ + printf("Account \"%s\" is already logged in!\n",accname); + realmCon.Close(); + something_went_wrong=true; + } else + if(pkt[2]!=0){ + printf("Unknown realm server response! opcode=0x%x\n",(unsigned char)pkt[2]); + something_went_wrong=true; + realmCon.Close(); + } else + if(pkt[2]==0){ + //DEBUG1(printf("Login successful, now calculating proof packet...\n");); + ProcessClientLogonProof(pkt); + rs_state=2; // 2=waiting for server proof + } + }break; + + case 2:{ + if(pkt[1]==4){ + printf("Wrong password!\n"); + something_went_wrong=true; + realmCon.Close(); + } else + if(pkt[0]==1 && pkt[1]==0 && memcmp(&pkt[2],Auth_M2,20)!=0){ + printf("Something with Authenticating went wrong, although the password seems correct!\n"); + //DEBUG1(printf("-> expected M2=");printchex(Auth_M2,20,true);) + //DEBUG1(printf("-> got M2=");printchex(&pkt[2],20,true);) + something_went_wrong=true; + realmCon.Close(); + } else + if(pkt[0]==1 && pkt[1]==0 && memcmp(&pkt[2],Auth_M2,20)==0){ + printf("Password is correct!! Requesting Realmlist.\n"); + rs_state=3; // requesting realmlist + // Request Realmlist + char realmrequest[]={0x10,0,0,0,0}; // 0x10 is opcode, rest is an uint32, nulled + realmCon.Send(realmrequest,5); + } + else { + printf("Unknown ErrorID recieved, check the packet hexdump.\n"); + printf("-> IDs=");printchex(pkt,2,true); + something_went_wrong=true; + realmCon.Close(); + } + }break; + + case 3:{ + if(pkt[0]!=0x10){ + printf("Expected a realmlist packet, got something different. opcode=0x%x\n",(unsigned char)pkt[0]); + something_went_wrong=true; + realmCon.Close(); + } + ByteBuffer bbuf; + bbuf.append(pkt,size); + if(HandleRealmList(bbuf)==true){ + printf("Connecting to realm \"%s\" at \"%s\", port %d\n",realmname,worldhost.c_str(),ws_port); + while(!worldCon.IsConnected()){ + worldCon.ConnectTo((char*)worldhost.c_str(),ws_port); // init world server connection, we have all info we need to enter + } + realmCon.Close(); // close the realm server connection, its no longer needed now + } + }break; + // more? + default:{ + //... + } + } +} +*/ + + + +void RealmSocket::SendLogonChallenge(void) +{ + std::string acc = stringToUpper(GetInstance()->GetConf()->accname); + ByteBuffer packet; + packet << (uint8)AUTH_LOGON_CHALLENGE; + packet << (uint8)2; + packet << (uint8)(acc.length()+30); // length of the rest of the packet + packet << "WOW"; // game name = World Of Warcraft + packet.append(GetInstance()->GetConf()->clientversion,3); // 1.12.2 etc + packet << GetInstance()->GetConf()->clientbuild; // (uint16) 5875 + packet << "68x" << "niW"; // "x86" - platform; "Win" - Operating system; both reversed and zero terminated + for(uint8 i=2;i>0;i--) + packet << (uint8)GetInstance()->GetConf()->clientlang[i]; // "enUS" -> "SUne" : reversed and NOT zero terminated + packet << (uint32)0x3c; // timezone + packet << (uint32)GetClientRemoteAddr(); // my IP address + packet << (uint8)acc.length(); // length of acc name without \0 + packet.append(acc.c_str(),acc.length()); // append accname, skip \0 + + this->SendBuf((char*)packet.contents(),packet.size()); + +} + +PseuInstance *RealmSocket::GetInstance(void) +{ + return _instance; +} + +void RealmSocket::_HandleLogonChallenge(void) +{ + sAuthLogonChallenge_S lc; + ibuf.Read((char*)&lc, sizeof(sAuthLogonChallenge_S)); + + switch (lc.error) + { + case 4: + printf("Realm Server did not find account \"%s\"!\n",GetInstance()->GetConf()->accname.c_str()); + break; + case 6: + printf("Account \"%s\" is already logged in!\n",GetInstance()->GetConf()->accname.c_str()); + break; + case 0: + printf("Login successful, now calculating proof packet...\n"); + + // now lets start calculating + BigNumber N,A,B,a,u,x,v,S,salt,unk1,g,k(3); // init BNs, default k to 3 + std::string user=stringToUpper( GetInstance()->GetConf()->accname ); + std::string _authstr=stringToUpper( user +":"+GetInstance()->GetConf()->accpass ); + + B.SetBinary(lc.B,32); + g.SetBinary(lc.g,lc.g_len); + N.SetBinary(lc.N,lc.N_len); + salt.SetBinary(lc.salt,32); + unk1.SetBinary(lc.unk3,16); + + /* + // debug output + //DEBUG3(printchex(B_str,BNLEN,true);) + //DEBUG3(printchex(g_str,1,true);) + //DEBUG3(printchex(N_str,BNLEN,true);) + //DEBUG3(printchex(salt_str,BNLEN,true);) + //DEBUG3(printchex(unk1_str,16,true);) + */ + + // client-side BN calculations: + ////DEBUG3(printf("--> k=%s\n",k.AsHexStr());) + a.SetRand(19*8); + Sha1Hash userhash,xhash,uhash; + userhash.UpdateData(_authstr); + userhash.Finalize(); + xhash.UpdateData(salt.AsByteArray(),salt.GetNumBytes()); + xhash.UpdateData(userhash.GetDigest(),userhash.GetLength()); + xhash.Finalize(); + x.SetBinary(xhash.GetDigest(),xhash.GetLength()); + ////DEBUG3(printf("--> x=%s\n",x.AsHexStr());) + v=g.ModExp(x,N); + ////DEBUG3(printf("--> v=%s\n",v.AsHexStr());) + A=g.ModExp(a,N); + ////DEBUG3(printf("--> A=%s\n",A.AsHexStr());) + uhash.UpdateBigNumbers(&A, &B, NULL); + uhash.Finalize(); + u.SetBinary(uhash.GetDigest(), 20); + ////DEBUG3(printf("--> u=%s\n",u.AsHexStr());) + S=(B - k*g.ModExp(x,N) ).ModExp((a + u * x),N); + ////DEBUG3(printf("--> S=%s\n",S.AsHexStr());) + + // calc M1 & M2 + unsigned int i=0; + char S1[16+1],S2[16+1]; // 32/2=16 :) +1 for \0 + // split it into 2 seperate strings, interleaved + for(i=0;i<=15;i++){ + S1[i]=S.AsByteArray()[i*2]; + S2[i]=S.AsByteArray()[i*2+1]; + } + + // hash each one: + Sha1Hash S1hash,S2hash; + S1hash.UpdateData((const uint8*)S1,16); + S1hash.Finalize(); + S2hash.UpdateData((const uint8*)S2,16); + S2hash.Finalize(); + // Re-combine them + char S_hash[40]; // 2*Sha1Len+1 for \0 + for(i=0;i<20;i++){ + S_hash[i*2]=S1hash.GetDigest()[i]; + S_hash[i*2+1]=S2hash.GetDigest()[i]; + } + _key.SetBinary((uint8*)S_hash,40); // used later when authing to world + + char Ng_hash[20]; + Sha1Hash userhash2,Nhash,ghash; + userhash2.UpdateData((const uint8*)user.c_str(),user.length()); + userhash2.Finalize(); + //printchex((char*)userhash2.GetDigest(),userhash2.GetLength(),true); + Nhash.UpdateBigNumbers(&N,NULL); + Nhash.Finalize(); + ghash.UpdateBigNumbers(&g,NULL); + ghash.Finalize(); + for(i=0;i<20;i++)Ng_hash[i] = Nhash.GetDigest()[i]^ghash.GetDigest()[i]; + //printchex(Ng_hash,20,true); + + BigNumber t_acc,t_Ng_hash; + t_acc.SetBinary((const uint8*)userhash2.GetDigest(),userhash2.GetLength()); + t_Ng_hash.SetBinary((const uint8*)Ng_hash,20); + + + Sha1Hash M1hash,M2hash; + + M1hash.UpdateBigNumbers(&t_Ng_hash,&t_acc,&salt,&A,&B,NULL); + M1hash.UpdateData((const uint8*)S_hash,40); + M1hash.Finalize(); + + M2hash.UpdateBigNumbers(&A,NULL); + M2hash.UpdateData((const uint8*)M1hash.GetDigest(),M1hash.GetLength()); + M2hash.UpdateData((const uint8*)S_hash,40); + M2hash.Finalize(); + + + ////DEBUG3( + // printf("--> M1=");printchex((char*)M1hash.GetDigest(),20,true);\ + // printf("--> M2=");printchex((char*)M2hash.GetDigest(),20,true);\ + //) + + // Calc CRC & CRC_hash + // i don't know yet how to calc it, so set it to zero + char crc_hash[20]; + memset(crc_hash,0,20); + + + // now lets prepare the packet + ByteBuffer packet; + packet << (uint8)AUTH_LOGON_PROOF; + packet.append(A.AsByteArray(),A.GetNumBytes()); + packet.append(M1hash.GetDigest(),M1hash.GetLength()); + packet.append(crc_hash,20); + packet << (uint8)0; // number of keys = 0 + + if(GetInstance()->GetConf()->clientbuild > 5302) + packet << (uint8)0; // 1.11.x compatibility (needs one more 0) + + GetInstance()->SetSessionKey(_key); + memcpy(this->_m2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later + + SendBuf((char*)packet.contents(),packet.size()); + break; + + //default: + // printf("Unknown realm server response! opcode=0x%x\n",(unsigned char)lc.error); + // break; + } +} + + +void RealmSocket::_HandleLogonProof(void) +{ + sAuthLogonProof_S lp; + ibuf.Read((char*)&lp, sizeof(sAuthLogonProof_S)); + if(!memcmp(lp.M2,this->_m2,20)) + { + // auth successful + ByteBuffer packet; + packet << (uint8)REALM_LIST; + packet << (uint32)0; + SendBuf((char*)packet.contents(),packet.size()); + } + else + { + // auth failed, M2 differs + //... + } +} + diff --git a/src/Client/Realm/RealmSocket.h b/src/Client/Realm/RealmSocket.h new file mode 100644 index 0000000..3afdf23 --- /dev/null +++ b/src/Client/Realm/RealmSocket.h @@ -0,0 +1,60 @@ + + + +#ifndef _REALMSOCKET_H +#define _REALMSOCKET_H + +#include "Network/ResolvSocket.h" + +class RealmSocket : public TcpSocket +{ +public: + RealmSocket(SocketHandler &h); + ~RealmSocket(); + PseuInstance *GetInstance(void); + bool IsValid(void); + void SetInstance(PseuInstance*); + + void SetHost(std::string); + void SetPort(uint16); + + + + void Start(void); + void Stop(void); + void Update(void); + void SendLogonChallenge(void); + + // dont use from outside!! + void _HandleRealmList(void); + void _HandleLogonProof(void); + void _HandleLogonChallenge(void); + + void OnRead(void); + //void OnAccept(void); + void OnConnect(void); + + +private: + + + + uint16 _rport; + std::string _rhost; + uint8 _m2[20]; + PseuInstance *_instance; + BigNumber _key; + bool _valid; + ByteBuffer _data; + + +}; + + + + + + + + +#endif \ No newline at end of file diff --git a/src/Client/Script1.aps b/src/Client/Script1.aps new file mode 100644 index 0000000..edf84d7 Binary files /dev/null and b/src/Client/Script1.aps differ diff --git a/src/Client/Script1.rc b/src/Client/Script1.rc new file mode 100644 index 0000000..c7d4ca9 --- /dev/null +++ b/src/Client/Script1.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "Pseu1.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/Client/World/CMSGConstructor.cpp b/src/Client/World/CMSGConstructor.cpp new file mode 100644 index 0000000..b2d4601 --- /dev/null +++ b/src/Client/World/CMSGConstructor.cpp @@ -0,0 +1,68 @@ +#include "common.h" +#include "PseuWoW.h" +#include "WorldPacket.h" +#include "Opcodes.h" +#include "Player.h" +#include "WorldSession.h" + +void WorldSession::SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to){ + if((!_logged) || msg.empty()) + return; + WorldPacket packet; + packet<: \"%s\"\n",msg.c_str());); + break; + case CHAT_MSG_WHISPER: + if(to.empty()) + return; + packet< + * + * 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 "common.h" +#include "SharedDefines.h" +#include "Opcodes.h" +#include "NameTables.h" + +NameTableEntry g_worldOpcodeNames[] = +{ + + { MSG_NULL_ACTION, "MSG_NULL_ACTION"}, + { CMSG_BOOTME, "CMSG_BOOTME"}, + { CMSG_DBLOOKUP, "CMSG_DBLOOKUP"}, + { SMSG_DBLOOKUP, "SMSG_DBLOOKUP"}, + { CMSG_QUERY_OBJECT_POSITION, "CMSG_QUERY_OBJECT_POSITION"}, + { SMSG_QUERY_OBJECT_POSITION, "SMSG_QUERY_OBJECT_POSITION"}, + { CMSG_QUERY_OBJECT_ROTATION, "CMSG_QUERY_OBJECT_ROTATION"}, + { SMSG_QUERY_OBJECT_ROTATION, "SMSG_QUERY_OBJECT_ROTATION"}, + { CMSG_WORLD_TELEPORT, "CMSG_WORLD_TELEPORT"}, + { CMSG_TELEPORT_TO_UNIT, "CMSG_TELEPORT_TO_UNIT"}, + { CMSG_ZONE_MAP, "CMSG_ZONE_MAP"}, + { SMSG_ZONE_MAP, "SMSG_ZONE_MAP"}, + { CMSG_DEBUG_CHANGECELLZONE, "CMSG_DEBUG_CHANGECELLZONE"}, + { CMSG_EMBLAZON_TABARD_OBSOLETE, "CMSG_EMBLAZON_TABARD_OBSOLETE"}, + { CMSG_UNEMBLAZON_TABARD_OBSOLETE, "CMSG_UNEMBLAZON_TABARD_OBSOLETE"}, + { CMSG_RECHARGE, "CMSG_RECHARGE"}, + { CMSG_LEARN_SPELL, "CMSG_LEARN_SPELL"}, + { CMSG_CREATEMONSTER, "CMSG_CREATEMONSTER"}, + { CMSG_DESTROYMONSTER, "CMSG_DESTROYMONSTER"}, + { CMSG_CREATEITEM, "CMSG_CREATEITEM"}, + { CMSG_CREATEGAMEOBJECT, "CMSG_CREATEGAMEOBJECT"}, + { CMSG_MAKEMONSTERATTACKME_OBSOLETE, "CMSG_MAKEMONSTERATTACKME_OBSOLETE"}, + { CMSG_MAKEMONSTERATTACKGUID, "CMSG_MAKEMONSTERATTACKGUID"}, + { CMSG_ENABLEDEBUGCOMBATLOGGING_OBSOLETE, "CMSG_ENABLEDEBUGCOMBATLOGGING_OBSOLETE"}, + { CMSG_FORCEACTION, "CMSG_FORCEACTION"}, + { CMSG_FORCEACTIONONOTHER, "CMSG_FORCEACTIONONOTHER"}, + { CMSG_FORCEACTIONSHOW, "CMSG_FORCEACTIONSHOW"}, + { SMSG_FORCEACTIONSHOW, "SMSG_FORCEACTIONSHOW"}, + { SMSG_ATTACKERSTATEUPDATEDEBUGINFO_OBSOLETE, "SMSG_ATTACKERSTATEUPDATEDEBUGINFO_OBSOLETE"}, + { SMSG_DEBUGINFOSPELL_OBSOLETE, "SMSG_DEBUGINFOSPELL_OBSOLETE"}, + { SMSG_DEBUGINFOSPELLMISS_OBSOLETE, "SMSG_DEBUGINFOSPELLMISS_OBSOLETE"}, + { SMSG_DEBUG_PLAYER_RANGE_OBSOLETE, "SMSG_DEBUG_PLAYER_RANGE_OBSOLETE"}, + { CMSG_UNDRESSPLAYER, "CMSG_UNDRESSPLAYER"}, + { CMSG_BEASTMASTER, "CMSG_BEASTMASTER"}, + { CMSG_GODMODE, "CMSG_GODMODE"}, + { SMSG_GODMODE, "SMSG_GODMODE"}, + { CMSG_CHEAT_SETMONEY, "CMSG_CHEAT_SETMONEY"}, + { CMSG_LEVEL_CHEAT, "CMSG_LEVEL_CHEAT"}, + { CMSG_PET_LEVEL_CHEAT, "CMSG_PET_LEVEL_CHEAT"}, + { CMSG_LEVELUP_CHEAT_OBSOLETE, "CMSG_LEVELUP_CHEAT_OBSOLETE"}, + { CMSG_COOLDOWN_CHEAT, "CMSG_COOLDOWN_CHEAT"}, + { CMSG_USE_SKILL_CHEAT, "CMSG_USE_SKILL_CHEAT"}, + { CMSG_FLAG_QUEST, "CMSG_FLAG_QUEST"}, + { CMSG_FLAG_QUEST_FINISH, "CMSG_FLAG_QUEST_FINISH"}, + { CMSG_CLEAR_QUEST, "CMSG_CLEAR_QUEST"}, + { CMSG_SEND_EVENT, "CMSG_SEND_EVENT"}, + { CMSG_DEBUG_AISTATE, "CMSG_DEBUG_AISTATE"}, + { SMSG_DEBUG_AISTATE, "SMSG_DEBUG_AISTATE"}, + { CMSG_DISABLE_PVP_CHEAT, "CMSG_DISABLE_PVP_CHEAT"}, + { CMSG_ADVANCE_SPAWN_TIME, "CMSG_ADVANCE_SPAWN_TIME"}, + { CMSG_PVP_PORT_OBSOLETE, "CMSG_PVP_PORT_OBSOLETE"}, + { CMSG_AUTH_SRP6_BEGIN, "CMSG_AUTH_SRP6_BEGIN"}, + { CMSG_AUTH_SRP6_PROOF, "CMSG_AUTH_SRP6_PROOF"}, + { CMSG_AUTH_SRP6_RECODE, "CMSG_AUTH_SRP6_RECODE"}, + { CMSG_CHAR_CREATE, "CMSG_CHAR_CREATE"}, + { CMSG_CHAR_ENUM, "CMSG_CHAR_ENUM"}, + { CMSG_CHAR_DELETE, "CMSG_CHAR_DELETE"}, + { SMSG_AUTH_SRP6_RESPONSE, "SMSG_AUTH_SRP6_RESPONSE"}, + { SMSG_CHAR_CREATE, "SMSG_CHAR_CREATE"}, + { SMSG_CHAR_ENUM, "SMSG_CHAR_ENUM"}, + { SMSG_CHAR_DELETE, "SMSG_CHAR_DELETE"}, + { CMSG_PLAYER_LOGIN, "CMSG_PLAYER_LOGIN"}, + { SMSG_NEW_WORLD, "SMSG_NEW_WORLD"}, + { SMSG_TRANSFER_PENDING, "SMSG_TRANSFER_PENDING"}, + { SMSG_TRANSFER_ABORTED, "SMSG_TRANSFER_ABORTED"}, + { SMSG_CHARACTER_LOGIN_FAILED, "SMSG_CHARACTER_LOGIN_FAILED"}, + { SMSG_LOGIN_SETTIMESPEED, "SMSG_LOGIN_SETTIMESPEED"}, + { SMSG_GAMETIME_UPDATE, "SMSG_GAMETIME_UPDATE"}, + { CMSG_GAMETIME_SET, "CMSG_GAMETIME_SET"}, + { SMSG_GAMETIME_SET, "SMSG_GAMETIME_SET"}, + { CMSG_GAMESPEED_SET, "CMSG_GAMESPEED_SET"}, + { SMSG_GAMESPEED_SET, "SMSG_GAMESPEED_SET"}, + { CMSG_SERVERTIME, "CMSG_SERVERTIME"}, + { SMSG_SERVERTIME, "SMSG_SERVERTIME"}, + { CMSG_PLAYER_LOGOUT, "CMSG_PLAYER_LOGOUT"}, + { CMSG_LOGOUT_REQUEST, "CMSG_LOGOUT_REQUEST"}, + { SMSG_LOGOUT_RESPONSE, "SMSG_LOGOUT_RESPONSE"}, + { SMSG_LOGOUT_COMPLETE, "SMSG_LOGOUT_COMPLETE"}, + { CMSG_LOGOUT_CANCEL, "CMSG_LOGOUT_CANCEL"}, + { SMSG_LOGOUT_CANCEL_ACK, "SMSG_LOGOUT_CANCEL_ACK"}, + { CMSG_NAME_QUERY, "CMSG_NAME_QUERY"}, + { SMSG_NAME_QUERY_RESPONSE, "SMSG_NAME_QUERY_RESPONSE"}, + { CMSG_PET_NAME_QUERY, "CMSG_PET_NAME_QUERY"}, + { SMSG_PET_NAME_QUERY_RESPONSE, "SMSG_PET_NAME_QUERY_RESPONSE"}, + { CMSG_GUILD_QUERY, "CMSG_GUILD_QUERY"}, + { SMSG_GUILD_QUERY_RESPONSE, "SMSG_GUILD_QUERY_RESPONSE"}, + { CMSG_ITEM_QUERY_SINGLE, "CMSG_ITEM_QUERY_SINGLE"}, + { CMSG_ITEM_QUERY_MULTIPLE, "CMSG_ITEM_QUERY_MULTIPLE"}, + { SMSG_ITEM_QUERY_SINGLE_RESPONSE, "SMSG_ITEM_QUERY_SINGLE_RESPONSE"}, + { SMSG_ITEM_QUERY_MULTIPLE_RESPONSE, "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE"}, + { CMSG_PAGE_TEXT_QUERY, "CMSG_PAGE_TEXT_QUERY"}, + { SMSG_PAGE_TEXT_QUERY_RESPONSE, "SMSG_PAGE_TEXT_QUERY_RESPONSE"}, + { CMSG_QUEST_QUERY, "CMSG_QUEST_QUERY"}, + { SMSG_QUEST_QUERY_RESPONSE, "SMSG_QUEST_QUERY_RESPONSE"}, + { CMSG_GAMEOBJECT_QUERY, "CMSG_GAMEOBJECT_QUERY"}, + { SMSG_GAMEOBJECT_QUERY_RESPONSE, "SMSG_GAMEOBJECT_QUERY_RESPONSE"}, + { CMSG_CREATURE_QUERY, "CMSG_CREATURE_QUERY"}, + { SMSG_CREATURE_QUERY_RESPONSE, "SMSG_CREATURE_QUERY_RESPONSE"}, + { CMSG_WHO, "CMSG_WHO"}, + { SMSG_WHO, "SMSG_WHO"}, + { CMSG_WHOIS, "CMSG_WHOIS"}, + { SMSG_WHOIS, "SMSG_WHOIS"}, + { CMSG_FRIEND_LIST, "CMSG_FRIEND_LIST"}, + { SMSG_FRIEND_LIST, "SMSG_FRIEND_LIST"}, + { SMSG_FRIEND_STATUS, "SMSG_FRIEND_STATUS"}, + { CMSG_ADD_FRIEND, "CMSG_ADD_FRIEND"}, + { CMSG_DEL_FRIEND, "CMSG_DEL_FRIEND"}, + { SMSG_IGNORE_LIST, "SMSG_IGNORE_LIST"}, + { CMSG_ADD_IGNORE, "CMSG_ADD_IGNORE"}, + { CMSG_DEL_IGNORE, "CMSG_DEL_IGNORE"}, + { CMSG_GROUP_INVITE, "CMSG_GROUP_INVITE"}, + { SMSG_GROUP_INVITE, "SMSG_GROUP_INVITE"}, + { CMSG_GROUP_CANCEL, "CMSG_GROUP_CANCEL"}, + { SMSG_GROUP_CANCEL, "SMSG_GROUP_CANCEL"}, + { CMSG_GROUP_ACCEPT, "CMSG_GROUP_ACCEPT"}, + { CMSG_GROUP_DECLINE, "CMSG_GROUP_DECLINE"}, + { SMSG_GROUP_DECLINE, "SMSG_GROUP_DECLINE"}, + { CMSG_GROUP_UNINVITE, "CMSG_GROUP_UNINVITE"}, + { CMSG_GROUP_UNINVITE_GUID, "CMSG_GROUP_UNINVITE_GUID"}, + { SMSG_GROUP_UNINVITE, "SMSG_GROUP_UNINVITE"}, + { CMSG_GROUP_SET_LEADER, "CMSG_GROUP_SET_LEADER"}, + { SMSG_GROUP_SET_LEADER, "SMSG_GROUP_SET_LEADER"}, + { CMSG_LOOT_METHOD, "CMSG_LOOT_METHOD"}, + { CMSG_GROUP_DISBAND, "CMSG_GROUP_DISBAND"}, + { SMSG_GROUP_DESTROYED, "SMSG_GROUP_DESTROYED"}, + { SMSG_GROUP_LIST, "SMSG_GROUP_LIST"}, + { SMSG_PARTY_MEMBER_STATS, "SMSG_PARTY_MEMBER_STATS"}, + { SMSG_PARTY_COMMAND_RESULT, "SMSG_PARTY_COMMAND_RESULT"}, + { UMSG_UPDATE_GROUP_MEMBERS, "UMSG_UPDATE_GROUP_MEMBERS"}, + { CMSG_GUILD_CREATE, "CMSG_GUILD_CREATE"}, + { CMSG_GUILD_INVITE, "CMSG_GUILD_INVITE"}, + { SMSG_GUILD_INVITE, "SMSG_GUILD_INVITE"}, + { CMSG_GUILD_ACCEPT, "CMSG_GUILD_ACCEPT"}, + { CMSG_GUILD_DECLINE, "CMSG_GUILD_DECLINE"}, + { SMSG_GUILD_DECLINE, "SMSG_GUILD_DECLINE"}, + { CMSG_GUILD_INFO, "CMSG_GUILD_INFO"}, + { SMSG_GUILD_INFO, "SMSG_GUILD_INFO"}, + { CMSG_GUILD_ROSTER, "CMSG_GUILD_ROSTER"}, + { SMSG_GUILD_ROSTER, "SMSG_GUILD_ROSTER"}, + { CMSG_GUILD_PROMOTE, "CMSG_GUILD_PROMOTE"}, + { CMSG_GUILD_DEMOTE, "CMSG_GUILD_DEMOTE"}, + { CMSG_GUILD_LEAVE, "CMSG_GUILD_LEAVE"}, + { CMSG_GUILD_REMOVE, "CMSG_GUILD_REMOVE"}, + { CMSG_GUILD_DISBAND, "CMSG_GUILD_DISBAND"}, + { CMSG_GUILD_LEADER, "CMSG_GUILD_LEADER"}, + { CMSG_GUILD_MOTD, "CMSG_GUILD_MOTD"}, + { SMSG_GUILD_EVENT, "SMSG_GUILD_EVENT"}, + { SMSG_GUILD_COMMAND_RESULT, "SMSG_GUILD_COMMAND_RESULT"}, + { UMSG_UPDATE_GUILD, "UMSG_UPDATE_GUILD"}, + { CMSG_MESSAGECHAT, "CMSG_MESSAGECHAT"}, + { SMSG_MESSAGECHAT, "SMSG_MESSAGECHAT"}, + { CMSG_JOIN_CHANNEL, "CMSG_JOIN_CHANNEL"}, + { CMSG_LEAVE_CHANNEL, "CMSG_LEAVE_CHANNEL"}, + { SMSG_CHANNEL_NOTIFY, "SMSG_CHANNEL_NOTIFY"}, + { CMSG_CHANNEL_LIST, "CMSG_CHANNEL_LIST"}, + { SMSG_CHANNEL_LIST, "SMSG_CHANNEL_LIST"}, + { CMSG_CHANNEL_PASSWORD, "CMSG_CHANNEL_PASSWORD"}, + { CMSG_CHANNEL_SET_OWNER, "CMSG_CHANNEL_SET_OWNER"}, + { CMSG_CHANNEL_OWNER, "CMSG_CHANNEL_OWNER"}, + { CMSG_CHANNEL_MODERATOR, "CMSG_CHANNEL_MODERATOR"}, + { CMSG_CHANNEL_UNMODERATOR, "CMSG_CHANNEL_UNMODERATOR"}, + { CMSG_CHANNEL_MUTE, "CMSG_CHANNEL_MUTE"}, + { CMSG_CHANNEL_UNMUTE, "CMSG_CHANNEL_UNMUTE"}, + { CMSG_CHANNEL_INVITE, "CMSG_CHANNEL_INVITE"}, + { CMSG_CHANNEL_KICK, "CMSG_CHANNEL_KICK"}, + { CMSG_CHANNEL_BAN, "CMSG_CHANNEL_BAN"}, + { CMSG_CHANNEL_UNBAN, "CMSG_CHANNEL_UNBAN"}, + { CMSG_CHANNEL_ANNOUNCEMENTS, "CMSG_CHANNEL_ANNOUNCEMENTS"}, + { CMSG_CHANNEL_MODERATE, "CMSG_CHANNEL_MODERATE"}, + { SMSG_UPDATE_OBJECT, "SMSG_UPDATE_OBJECT"}, + { SMSG_DESTROY_OBJECT, "SMSG_DESTROY_OBJECT"}, + { CMSG_USE_ITEM, "CMSG_USE_ITEM"}, + { CMSG_OPEN_ITEM, "CMSG_OPEN_ITEM"}, + { CMSG_READ_ITEM, "CMSG_READ_ITEM"}, + { SMSG_READ_ITEM_OK, "SMSG_READ_ITEM_OK"}, + { SMSG_READ_ITEM_FAILED, "SMSG_READ_ITEM_FAILED"}, + { SMSG_ITEM_COOLDOWN, "SMSG_ITEM_COOLDOWN"}, + { CMSG_GAMEOBJ_USE, "CMSG_GAMEOBJ_USE"}, + { CMSG_GAMEOBJ_CHAIR_USE_OBSOLETE, "CMSG_GAMEOBJ_CHAIR_USE_OBSOLETE"}, + { SMSG_GAMEOBJECT_CUSTOM_ANIM, "SMSG_GAMEOBJECT_CUSTOM_ANIM"}, + { CMSG_AREATRIGGER, "CMSG_AREATRIGGER"}, + { MSG_MOVE_START_FORWARD, "MSG_MOVE_START_FORWARD"}, + { MSG_MOVE_START_BACKWARD, "MSG_MOVE_START_BACKWARD"}, + { MSG_MOVE_STOP, "MSG_MOVE_STOP"}, + { MSG_MOVE_START_STRAFE_LEFT, "MSG_MOVE_START_STRAFE_LEFT"}, + { MSG_MOVE_START_STRAFE_RIGHT, "MSG_MOVE_START_STRAFE_RIGHT"}, + { MSG_MOVE_STOP_STRAFE, "MSG_MOVE_STOP_STRAFE"}, + { MSG_MOVE_JUMP, "MSG_MOVE_JUMP"}, + { MSG_MOVE_START_TURN_LEFT, "MSG_MOVE_START_TURN_LEFT"}, + { MSG_MOVE_START_TURN_RIGHT, "MSG_MOVE_START_TURN_RIGHT"}, + { MSG_MOVE_STOP_TURN, "MSG_MOVE_STOP_TURN"}, + { MSG_MOVE_START_PITCH_UP, "MSG_MOVE_START_PITCH_UP"}, + { MSG_MOVE_START_PITCH_DOWN, "MSG_MOVE_START_PITCH_DOWN"}, + { MSG_MOVE_STOP_PITCH, "MSG_MOVE_STOP_PITCH"}, + { MSG_MOVE_SET_RUN_MODE, "MSG_MOVE_SET_RUN_MODE"}, + { MSG_MOVE_SET_WALK_MODE, "MSG_MOVE_SET_WALK_MODE"}, + { MSG_MOVE_TOGGLE_LOGGING, "MSG_MOVE_TOGGLE_LOGGING"}, + { MSG_MOVE_TELEPORT, "MSG_MOVE_TELEPORT"}, + { MSG_MOVE_TELEPORT_CHEAT, "MSG_MOVE_TELEPORT_CHEAT"}, + { MSG_MOVE_TELEPORT_ACK, "MSG_MOVE_TELEPORT_ACK"}, + { MSG_MOVE_TOGGLE_FALL_LOGGING, "MSG_MOVE_TOGGLE_FALL_LOGGING"}, + { MSG_MOVE_FALL_LAND, "MSG_MOVE_FALL_LAND"}, + { MSG_MOVE_START_SWIM, "MSG_MOVE_START_SWIM"}, + { MSG_MOVE_STOP_SWIM, "MSG_MOVE_STOP_SWIM"}, + { MSG_MOVE_SET_RUN_SPEED_CHEAT, "MSG_MOVE_SET_RUN_SPEED_CHEAT"}, + { MSG_MOVE_SET_RUN_SPEED, "MSG_MOVE_SET_RUN_SPEED"}, + { MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT, "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT"}, + { MSG_MOVE_SET_RUN_BACK_SPEED, "MSG_MOVE_SET_RUN_BACK_SPEED"}, + { MSG_MOVE_SET_WALK_SPEED_CHEAT, "MSG_MOVE_SET_WALK_SPEED_CHEAT"}, + { MSG_MOVE_SET_WALK_SPEED, "MSG_MOVE_SET_WALK_SPEED"}, + { MSG_MOVE_SET_SWIM_SPEED_CHEAT, "MSG_MOVE_SET_SWIM_SPEED_CHEAT"}, + { MSG_MOVE_SET_SWIM_SPEED, "MSG_MOVE_SET_SWIM_SPEED"}, + { MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT, "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT"}, + { MSG_MOVE_SET_SWIM_BACK_SPEED, "MSG_MOVE_SET_SWIM_BACK_SPEED"}, + { MSG_MOVE_SET_ALL_SPEED_CHEAT, "MSG_MOVE_SET_ALL_SPEED_CHEAT"}, + { MSG_MOVE_SET_TURN_RATE_CHEAT, "MSG_MOVE_SET_TURN_RATE_CHEAT"}, + { MSG_MOVE_SET_TURN_RATE, "MSG_MOVE_SET_TURN_RATE"}, + { MSG_MOVE_TOGGLE_COLLISION_CHEAT, "MSG_MOVE_TOGGLE_COLLISION_CHEAT"}, + { MSG_MOVE_SET_FACING, "MSG_MOVE_SET_FACING"}, + { MSG_MOVE_SET_PITCH, "MSG_MOVE_SET_PITCH"}, + { MSG_MOVE_WORLDPORT_ACK, "MSG_MOVE_WORLDPORT_ACK"}, + { SMSG_MONSTER_MOVE, "SMSG_MONSTER_MOVE"}, + { SMSG_MOVE_WATER_WALK, "SMSG_MOVE_WATER_WALK"}, + { SMSG_MOVE_LAND_WALK, "SMSG_MOVE_LAND_WALK"}, + { MSG_MOVE_SET_RAW_POSITION_ACK, "MSG_MOVE_SET_RAW_POSITION_ACK"}, + { CMSG_MOVE_SET_RAW_POSITION, "CMSG_MOVE_SET_RAW_POSITION"}, + { SMSG_FORCE_RUN_SPEED_CHANGE, "SMSG_FORCE_RUN_SPEED_CHANGE"}, + { CMSG_FORCE_RUN_SPEED_CHANGE_ACK, "CMSG_FORCE_RUN_SPEED_CHANGE_ACK"}, + { SMSG_FORCE_RUN_BACK_SPEED_CHANGE, "SMSG_FORCE_RUN_BACK_SPEED_CHANGE"}, + { CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK, "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK"}, + { SMSG_FORCE_SWIM_SPEED_CHANGE, "SMSG_FORCE_SWIM_SPEED_CHANGE"}, + { CMSG_FORCE_SWIM_SPEED_CHANGE_ACK, "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK"}, + { SMSG_FORCE_MOVE_ROOT, "SMSG_FORCE_MOVE_ROOT"}, + { CMSG_FORCE_MOVE_ROOT_ACK, "CMSG_FORCE_MOVE_ROOT_ACK"}, + { SMSG_FORCE_MOVE_UNROOT, "SMSG_FORCE_MOVE_UNROOT"}, + { CMSG_FORCE_MOVE_UNROOT_ACK, "CMSG_FORCE_MOVE_UNROOT_ACK"}, + { MSG_MOVE_ROOT, "MSG_MOVE_ROOT"}, + { MSG_MOVE_UNROOT, "MSG_MOVE_UNROOT"}, + { MSG_MOVE_HEARTBEAT, "MSG_MOVE_HEARTBEAT"}, + { SMSG_MOVE_KNOCK_BACK, "SMSG_MOVE_KNOCK_BACK"}, + { CMSG_MOVE_KNOCK_BACK_ACK, "CMSG_MOVE_KNOCK_BACK_ACK"}, + { MSG_MOVE_KNOCK_BACK, "MSG_MOVE_KNOCK_BACK"}, + { SMSG_MOVE_FEATHER_FALL, "SMSG_MOVE_FEATHER_FALL"}, + { SMSG_MOVE_NORMAL_FALL, "SMSG_MOVE_NORMAL_FALL"}, + { SMSG_MOVE_SET_HOVER, "SMSG_MOVE_SET_HOVER"}, + { SMSG_MOVE_UNSET_HOVER, "SMSG_MOVE_UNSET_HOVER"}, + { CMSG_MOVE_HOVER_ACK, "CMSG_MOVE_HOVER_ACK"}, + { MSG_MOVE_HOVER, "MSG_MOVE_HOVER"}, + { CMSG_TRIGGER_CINEMATIC_CHEAT, "CMSG_TRIGGER_CINEMATIC_CHEAT"}, + { CMSG_OPENING_CINEMATIC, "CMSG_OPENING_CINEMATIC"}, + { SMSG_TRIGGER_CINEMATIC, "SMSG_TRIGGER_CINEMATIC"}, + { CMSG_NEXT_CINEMATIC_CAMERA, "CMSG_NEXT_CINEMATIC_CAMERA"}, + { CMSG_COMPLETE_CINEMATIC, "CMSG_COMPLETE_CINEMATIC"}, + { SMSG_TUTORIAL_FLAGS, "SMSG_TUTORIAL_FLAGS"}, + { CMSG_TUTORIAL_FLAG, "CMSG_TUTORIAL_FLAG"}, + { CMSG_TUTORIAL_CLEAR, "CMSG_TUTORIAL_CLEAR"}, + { CMSG_TUTORIAL_RESET, "CMSG_TUTORIAL_RESET"}, + { CMSG_STANDSTATECHANGE, "CMSG_STANDSTATECHANGE"}, + { CMSG_EMOTE, "CMSG_EMOTE"}, + { SMSG_EMOTE, "SMSG_EMOTE"}, + { CMSG_TEXT_EMOTE, "CMSG_TEXT_EMOTE"}, + { SMSG_TEXT_EMOTE, "SMSG_TEXT_EMOTE"}, + { CMSG_AUTOEQUIP_GROUND_ITEM, "CMSG_AUTOEQUIP_GROUND_ITEM"}, + { CMSG_AUTOSTORE_GROUND_ITEM, "CMSG_AUTOSTORE_GROUND_ITEM"}, + { CMSG_AUTOSTORE_LOOT_ITEM, "CMSG_AUTOSTORE_LOOT_ITEM"}, + { CMSG_STORE_LOOT_IN_SLOT, "CMSG_STORE_LOOT_IN_SLOT"}, + { CMSG_AUTOEQUIP_ITEM, "CMSG_AUTOEQUIP_ITEM"}, + { CMSG_AUTOSTORE_BAG_ITEM, "CMSG_AUTOSTORE_BAG_ITEM"}, + { CMSG_SWAP_ITEM, "CMSG_SWAP_ITEM"}, + { CMSG_SWAP_INV_ITEM, "CMSG_SWAP_INV_ITEM"}, + { CMSG_SPLIT_ITEM, "CMSG_SPLIT_ITEM"}, + { CMSG_PICKUP_ITEM, "CMSG_PICKUP_ITEM"}, + { CMSG_DROP_ITEM, "CMSG_DROP_ITEM"}, + { CMSG_DESTROYITEM, "CMSG_DESTROYITEM"}, + { SMSG_INVENTORY_CHANGE_FAILURE, "SMSG_INVENTORY_CHANGE_FAILURE"}, + { SMSG_OPEN_CONTAINER, "SMSG_OPEN_CONTAINER"}, + { CMSG_INSPECT, "CMSG_INSPECT"}, + { SMSG_INSPECT, "SMSG_INSPECT"}, + { CMSG_INITIATE_TRADE, "CMSG_INITIATE_TRADE"}, + { CMSG_BEGIN_TRADE, "CMSG_BEGIN_TRADE"}, + { CMSG_BUSY_TRADE, "CMSG_BUSY_TRADE"}, + { CMSG_IGNORE_TRADE, "CMSG_IGNORE_TRADE"}, + { CMSG_ACCEPT_TRADE, "CMSG_ACCEPT_TRADE"}, + { CMSG_UNACCEPT_TRADE, "CMSG_UNACCEPT_TRADE"}, + { CMSG_CANCEL_TRADE, "CMSG_CANCEL_TRADE"}, + { CMSG_SET_TRADE_ITEM, "CMSG_SET_TRADE_ITEM"}, + { CMSG_CLEAR_TRADE_ITEM, "CMSG_CLEAR_TRADE_ITEM"}, + { CMSG_SET_TRADE_GOLD, "CMSG_SET_TRADE_GOLD"}, + { SMSG_TRADE_STATUS, "SMSG_TRADE_STATUS"}, + { SMSG_TRADE_STATUS_EXTENDED, "SMSG_TRADE_STATUS_EXTENDED"}, + { SMSG_INITIALIZE_FACTIONS, "SMSG_INITIALIZE_FACTIONS"}, + { SMSG_SET_FACTION_VISIBLE, "SMSG_SET_FACTION_VISIBLE"}, + { SMSG_SET_FACTION_STANDING, "SMSG_SET_FACTION_STANDING"}, + { CMSG_SET_FACTION_ATWAR, "CMSG_SET_FACTION_ATWAR"}, + { CMSG_SET_FACTION_CHEAT, "CMSG_SET_FACTION_CHEAT"}, + { SMSG_SET_PROFICIENCY, "SMSG_SET_PROFICIENCY"}, + { CMSG_SET_ACTION_BUTTON, "CMSG_SET_ACTION_BUTTON"}, + { SMSG_ACTION_BUTTONS, "SMSG_ACTION_BUTTONS"}, + { SMSG_INITIAL_SPELLS, "SMSG_INITIAL_SPELLS"}, + { SMSG_LEARNED_SPELL, "SMSG_LEARNED_SPELL"}, + { SMSG_SUPERCEDED_SPELL, "SMSG_SUPERCEDED_SPELL"}, + { CMSG_NEW_SPELL_SLOT, "CMSG_NEW_SPELL_SLOT"}, + { CMSG_CAST_SPELL, "CMSG_CAST_SPELL"}, + { CMSG_CANCEL_CAST, "CMSG_CANCEL_CAST"}, + { SMSG_CAST_RESULT, "SMSG_CAST_RESULT"}, + { SMSG_SPELL_START, "SMSG_SPELL_START"}, + { SMSG_SPELL_GO, "SMSG_SPELL_GO"}, + { SMSG_SPELL_FAILURE, "SMSG_SPELL_FAILURE"}, + { SMSG_SPELL_COOLDOWN, "SMSG_SPELL_COOLDOWN"}, + { SMSG_COOLDOWN_EVENT, "SMSG_COOLDOWN_EVENT"}, + { CMSG_CANCEL_AURA, "CMSG_CANCEL_AURA"}, + { SMSG_UPDATE_AURA_DURATION, "SMSG_UPDATE_AURA_DURATION"}, + { SMSG_PET_CAST_FAILED, "SMSG_PET_CAST_FAILED"}, + { MSG_CHANNEL_START, "MSG_CHANNEL_START"}, + { MSG_CHANNEL_UPDATE, "MSG_CHANNEL_UPDATE"}, + { CMSG_CANCEL_CHANNELLING, "CMSG_CANCEL_CHANNELLING"}, + { SMSG_AI_REACTION, "SMSG_AI_REACTION"}, + { CMSG_SET_SELECTION, "CMSG_SET_SELECTION"}, + { CMSG_SET_TARGET_OBSOLETE, "CMSG_SET_TARGET_OBSOLETE"}, + { CMSG_UNUSED, "CMSG_UNUSED"}, + { CMSG_UNUSED2, "CMSG_UNUSED2"}, + { CMSG_ATTACKSWING, "CMSG_ATTACKSWING"}, + { CMSG_ATTACKSTOP, "CMSG_ATTACKSTOP"}, + { SMSG_ATTACKSTART, "SMSG_ATTACKSTART"}, + { SMSG_ATTACKSTOP, "SMSG_ATTACKSTOP"}, + { SMSG_ATTACKSWING_NOTINRANGE, "SMSG_ATTACKSWING_NOTINRANGE"}, + { SMSG_ATTACKSWING_BADFACING, "SMSG_ATTACKSWING_BADFACING"}, + { SMSG_ATTACKSWING_NOTSTANDING, "SMSG_ATTACKSWING_NOTSTANDING"}, + { SMSG_ATTACKSWING_DEADTARGET, "SMSG_ATTACKSWING_DEADTARGET"}, + { SMSG_ATTACKSWING_CANT_ATTACK, "SMSG_ATTACKSWING_CANT_ATTACK"}, + { SMSG_ATTACKERSTATEUPDATE, "SMSG_ATTACKERSTATEUPDATE"}, + { SMSG_VICTIMSTATEUPDATE_OBSOLETE, "SMSG_VICTIMSTATEUPDATE_OBSOLETE"}, + { SMSG_DAMAGE_DONE_OBSOLETE, "SMSG_DAMAGE_DONE_OBSOLETE"}, + { SMSG_DAMAGE_TAKEN_OBSOLETE, "SMSG_DAMAGE_TAKEN_OBSOLETE"}, + { SMSG_CANCEL_COMBAT, "SMSG_CANCEL_COMBAT"}, + { SMSG_PLAYER_COMBAT_XP_GAIN_OBSOLETE, "SMSG_PLAYER_COMBAT_XP_GAIN_OBSOLETE"}, + { SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, "SMSG_HEALSPELL_ON_PLAYER_OBSOLETE"}, + { SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, "SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE"}, + { CMSG_SHEATHE_OBSOLETE, "CMSG_SHEATHE_OBSOLETE"}, + { CMSG_SAVE_PLAYER, "CMSG_SAVE_PLAYER"}, + { CMSG_SETDEATHBINDPOINT, "CMSG_SETDEATHBINDPOINT"}, + { SMSG_BINDPOINTUPDATE, "SMSG_BINDPOINTUPDATE"}, + { CMSG_GETDEATHBINDZONE, "CMSG_GETDEATHBINDZONE"}, + { SMSG_BINDZONEREPLY, "SMSG_BINDZONEREPLY"}, + { SMSG_PLAYERBOUND, "SMSG_PLAYERBOUND"}, + { SMSG_DEATH_NOTIFY_OBSOLETE, "SMSG_DEATH_NOTIFY_OBSOLETE"}, + { CMSG_REPOP_REQUEST, "CMSG_REPOP_REQUEST"}, + { SMSG_RESURRECT_REQUEST, "SMSG_RESURRECT_REQUEST"}, + { CMSG_RESURRECT_RESPONSE, "CMSG_RESURRECT_RESPONSE"}, + { CMSG_LOOT, "CMSG_LOOT"}, + { CMSG_LOOT_MONEY, "CMSG_LOOT_MONEY"}, + { CMSG_LOOT_RELEASE, "CMSG_LOOT_RELEASE"}, + { SMSG_LOOT_RESPONSE, "SMSG_LOOT_RESPONSE"}, + { SMSG_LOOT_RELEASE_RESPONSE, "SMSG_LOOT_RELEASE_RESPONSE"}, + { SMSG_LOOT_REMOVED, "SMSG_LOOT_REMOVED"}, + { SMSG_LOOT_MONEY_NOTIFY, "SMSG_LOOT_MONEY_NOTIFY"}, + { SMSG_LOOT_ITEM_NOTIFY, "SMSG_LOOT_ITEM_NOTIFY"}, + { SMSG_LOOT_CLEAR_MONEY, "SMSG_LOOT_CLEAR_MONEY"}, + { SMSG_ITEM_PUSH_RESULT, "SMSG_ITEM_PUSH_RESULT"}, + { SMSG_DUEL_REQUESTED, "SMSG_DUEL_REQUESTED"}, + { SMSG_DUEL_OUTOFBOUNDS, "SMSG_DUEL_OUTOFBOUNDS"}, + { SMSG_DUEL_INBOUNDS, "SMSG_DUEL_INBOUNDS"}, + { SMSG_DUEL_COMPLETE, "SMSG_DUEL_COMPLETE"}, + { SMSG_DUEL_WINNER, "SMSG_DUEL_WINNER"}, + { CMSG_DUEL_ACCEPTED, "CMSG_DUEL_ACCEPTED"}, + { CMSG_DUEL_CANCELLED, "CMSG_DUEL_CANCELLED"}, + { SMSG_MOUNTRESULT, "SMSG_MOUNTRESULT"}, + { SMSG_DISMOUNTRESULT, "SMSG_DISMOUNTRESULT"}, + { SMSG_PUREMOUNT_CANCELLED_OBSOLETE, "SMSG_PUREMOUNT_CANCELLED_OBSOLETE"}, + { CMSG_MOUNTSPECIAL_ANIM, "CMSG_MOUNTSPECIAL_ANIM"}, + { SMSG_MOUNTSPECIAL_ANIM, "SMSG_MOUNTSPECIAL_ANIM"}, + { SMSG_PET_TAME_FAILURE, "SMSG_PET_TAME_FAILURE"}, + { CMSG_PET_SET_ACTION, "CMSG_PET_SET_ACTION"}, + { CMSG_PET_ACTION, "CMSG_PET_ACTION"}, + { CMSG_PET_ABANDON, "CMSG_PET_ABANDON"}, + { CMSG_PET_RENAME, "CMSG_PET_RENAME"}, + { SMSG_PET_NAME_INVALID, "SMSG_PET_NAME_INVALID"}, + { SMSG_PET_SPELLS, "SMSG_PET_SPELLS"}, + { SMSG_PET_MODE, "SMSG_PET_MODE"}, + { CMSG_GOSSIP_HELLO, "CMSG_GOSSIP_HELLO"}, + { CMSG_GOSSIP_SELECT_OPTION, "CMSG_GOSSIP_SELECT_OPTION"}, + { SMSG_GOSSIP_MESSAGE, "SMSG_GOSSIP_MESSAGE"}, + { SMSG_GOSSIP_COMPLETE, "SMSG_GOSSIP_COMPLETE"}, + { CMSG_NPC_TEXT_QUERY, "CMSG_NPC_TEXT_QUERY"}, + { SMSG_NPC_TEXT_UPDATE, "SMSG_NPC_TEXT_UPDATE"}, + { SMSG_NPC_WONT_TALK, "SMSG_NPC_WONT_TALK"}, + { CMSG_QUESTGIVER_STATUS_QUERY, "CMSG_QUESTGIVER_STATUS_QUERY"}, + { SMSG_QUESTGIVER_STATUS, "SMSG_QUESTGIVER_STATUS"}, + { CMSG_QUESTGIVER_HELLO, "CMSG_QUESTGIVER_HELLO"}, + { SMSG_QUESTGIVER_QUEST_LIST, "SMSG_QUESTGIVER_QUEST_LIST"}, + { CMSG_QUESTGIVER_QUERY_QUEST, "CMSG_QUESTGIVER_QUERY_QUEST"}, + { CMSG_QUESTGIVER_QUEST_AUTOLAUNCH, "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH"}, + { SMSG_QUESTGIVER_QUEST_DETAILS, "SMSG_QUESTGIVER_QUEST_DETAILS"}, + { CMSG_QUESTGIVER_ACCEPT_QUEST, "CMSG_QUESTGIVER_ACCEPT_QUEST"}, + { CMSG_QUESTGIVER_COMPLETE_QUEST, "CMSG_QUESTGIVER_COMPLETE_QUEST"}, + { SMSG_QUESTGIVER_REQUEST_ITEMS, "SMSG_QUESTGIVER_REQUEST_ITEMS"}, + { CMSG_QUESTGIVER_REQUEST_REWARD, "CMSG_QUESTGIVER_REQUEST_REWARD"}, + { SMSG_QUESTGIVER_OFFER_REWARD, "SMSG_QUESTGIVER_OFFER_REWARD"}, + { CMSG_QUESTGIVER_CHOOSE_REWARD, "CMSG_QUESTGIVER_CHOOSE_REWARD"}, + { SMSG_QUESTGIVER_QUEST_INVALID, "SMSG_QUESTGIVER_QUEST_INVALID"}, + { CMSG_QUESTGIVER_CANCEL, "CMSG_QUESTGIVER_CANCEL"}, + { SMSG_QUESTGIVER_QUEST_COMPLETE, "SMSG_QUESTGIVER_QUEST_COMPLETE"}, + { SMSG_QUESTGIVER_QUEST_FAILED, "SMSG_QUESTGIVER_QUEST_FAILED"}, + { CMSG_QUESTLOG_SWAP_QUEST, "CMSG_QUESTLOG_SWAP_QUEST"}, + { CMSG_QUESTLOG_REMOVE_QUEST, "CMSG_QUESTLOG_REMOVE_QUEST"}, + { SMSG_QUESTLOG_FULL, "SMSG_QUESTLOG_FULL"}, + { SMSG_QUESTUPDATE_FAILED, "SMSG_QUESTUPDATE_FAILED"}, + { SMSG_QUESTUPDATE_FAILEDTIMER, "SMSG_QUESTUPDATE_FAILEDTIMER"}, + { SMSG_QUESTUPDATE_COMPLETE, "SMSG_QUESTUPDATE_COMPLETE"}, + { SMSG_QUESTUPDATE_ADD_KILL, "SMSG_QUESTUPDATE_ADD_KILL"}, + { SMSG_QUESTUPDATE_ADD_ITEM, "SMSG_QUESTUPDATE_ADD_ITEM"}, + { CMSG_QUEST_CONFIRM_ACCEPT, "CMSG_QUEST_CONFIRM_ACCEPT"}, + { SMSG_QUEST_CONFIRM_ACCEPT, "SMSG_QUEST_CONFIRM_ACCEPT"}, + { CMSG_PUSHQUESTTOPARTY, "CMSG_PUSHQUESTTOPARTY"}, + { CMSG_LIST_INVENTORY, "CMSG_LIST_INVENTORY"}, + { SMSG_LIST_INVENTORY, "SMSG_LIST_INVENTORY"}, + { CMSG_SELL_ITEM, "CMSG_SELL_ITEM"}, + { SMSG_SELL_ITEM, "SMSG_SELL_ITEM"}, + { CMSG_BUY_ITEM, "CMSG_BUY_ITEM"}, + { CMSG_BUY_ITEM_IN_SLOT, "CMSG_BUY_ITEM_IN_SLOT"}, + { SMSG_BUY_ITEM, "SMSG_BUY_ITEM"}, + { SMSG_BUY_FAILED, "SMSG_BUY_FAILED"}, + { CMSG_TAXICLEARALLNODES, "CMSG_TAXICLEARALLNODES"}, + { CMSG_TAXIENABLEALLNODES, "CMSG_TAXIENABLEALLNODES"}, + { CMSG_TAXISHOWNODES, "CMSG_TAXISHOWNODES"}, + { SMSG_SHOWTAXINODES, "SMSG_SHOWTAXINODES"}, + { CMSG_TAXINODE_STATUS_QUERY, "CMSG_TAXINODE_STATUS_QUERY"}, + { SMSG_TAXINODE_STATUS, "SMSG_TAXINODE_STATUS"}, + { CMSG_TAXIQUERYAVAILABLENODES, "CMSG_TAXIQUERYAVAILABLENODES"}, + { CMSG_ACTIVATETAXI, "CMSG_ACTIVATETAXI"}, + { SMSG_ACTIVATETAXIREPLY, "SMSG_ACTIVATETAXIREPLY"}, + { CMSG_ACTIVATETAXI_FAR, "CMSG_ACTIVATETAXI_FAR"}, + { SMSG_NEW_TAXI_PATH, "SMSG_NEW_TAXI_PATH"}, + { CMSG_TRAINER_LIST, "CMSG_TRAINER_LIST"}, + { SMSG_TRAINER_LIST, "SMSG_TRAINER_LIST"}, + { CMSG_TRAINER_BUY_SPELL, "CMSG_TRAINER_BUY_SPELL"}, + { SMSG_TRAINER_BUY_SUCCEEDED, "SMSG_TRAINER_BUY_SUCCEEDED"}, + { SMSG_TRAINER_BUY_FAILED, "SMSG_TRAINER_BUY_FAILED"}, + { CMSG_BINDER_ACTIVATE, "CMSG_BINDER_ACTIVATE"}, + { SMSG_PLAYERBINDERROR, "SMSG_PLAYERBINDERROR"}, + { CMSG_BANKER_ACTIVATE, "CMSG_BANKER_ACTIVATE"}, + { SMSG_SHOW_BANK, "SMSG_SHOW_BANK"}, + { CMSG_BUY_BANK_SLOT, "CMSG_BUY_BANK_SLOT"}, + { SMSG_BUY_BANK_SLOT_RESULT, "SMSG_BUY_BANK_SLOT_RESULT"}, + { CMSG_PETITION_SHOWLIST, "CMSG_PETITION_SHOWLIST"}, + { SMSG_PETITION_SHOWLIST, "SMSG_PETITION_SHOWLIST"}, + { CMSG_PETITION_BUY, "CMSG_PETITION_BUY"}, + { CMSG_PETITION_SHOW_SIGNATURES, "CMSG_PETITION_SHOW_SIGNATURES"}, + { SMSG_PETITION_SHOW_SIGNATURES, "SMSG_PETITION_SHOW_SIGNATURES"}, + { CMSG_PETITION_SIGN, "CMSG_PETITION_SIGN"}, + { SMSG_PETITION_SIGN_RESULTS, "SMSG_PETITION_SIGN_RESULTS"}, + { MSG_PETITION_DECLINE, "MSG_PETITION_DECLINE"}, + { CMSG_OFFER_PETITION, "CMSG_OFFER_PETITION"}, + { CMSG_TURN_IN_PETITION, "CMSG_TURN_IN_PETITION"}, + { SMSG_TURN_IN_PETITION_RESULTS, "SMSG_TURN_IN_PETITION_RESULTS"}, + { CMSG_PETITION_QUERY, "CMSG_PETITION_QUERY"}, + { SMSG_PETITION_QUERY_RESPONSE, "SMSG_PETITION_QUERY_RESPONSE"}, + { SMSG_FISH_NOT_HOOKED, "SMSG_FISH_NOT_HOOKED"}, + { SMSG_FISH_ESCAPED, "SMSG_FISH_ESCAPED"}, + { CMSG_BUG, "CMSG_BUG"}, + { SMSG_NOTIFICATION, "SMSG_NOTIFICATION"}, + { CMSG_PLAYED_TIME, "CMSG_PLAYED_TIME"}, + { SMSG_PLAYED_TIME, "SMSG_PLAYED_TIME"}, + { CMSG_QUERY_TIME, "CMSG_QUERY_TIME"}, + { SMSG_QUERY_TIME_RESPONSE, "SMSG_QUERY_TIME_RESPONSE"}, + { SMSG_LOG_XPGAIN, "SMSG_LOG_XPGAIN"}, + { MSG_SPLIT_MONEY, "MSG_SPLIT_MONEY"}, + { CMSG_RECLAIM_CORPSE, "CMSG_RECLAIM_CORPSE"}, + { CMSG_WRAP_ITEM, "CMSG_WRAP_ITEM"}, + { SMSG_LEVELUP_INFO, "SMSG_LEVELUP_INFO"}, + { MSG_MINIMAP_PING, "MSG_MINIMAP_PING"}, + { SMSG_RESISTLOG, "SMSG_RESISTLOG"}, + { SMSG_ENCHANTMENTLOG, "SMSG_ENCHANTMENTLOG"}, + { CMSG_SET_SKILL_CHEAT, "CMSG_SET_SKILL_CHEAT"}, + { SMSG_START_MIRROR_TIMER, "SMSG_START_MIRROR_TIMER"}, + { SMSG_PAUSE_MIRROR_TIMER, "SMSG_PAUSE_MIRROR_TIMER"}, + { SMSG_STOP_MIRROR_TIMER, "SMSG_STOP_MIRROR_TIMER"}, + { CMSG_PING, "CMSG_PING"}, + { SMSG_PONG, "SMSG_PONG"}, + { SMSG_CLEAR_COOLDOWN, "SMSG_CLEAR_COOLDOWN"}, + { SMSG_GAMEOBJECT_PAGETEXT, "SMSG_GAMEOBJECT_PAGETEXT"}, + { CMSG_SETSHEATHED, "CMSG_SETSHEATHED"}, + { SMSG_COOLDOWN_CHEAT, "SMSG_COOLDOWN_CHEAT"}, + { SMSG_SPELL_DELAYED, "SMSG_SPELL_DELAYED"}, + { CMSG_PLAYER_MACRO_OBSOLETE, "CMSG_PLAYER_MACRO_OBSOLETE"}, + { SMSG_PLAYER_MACRO_OBSOLETE, "SMSG_PLAYER_MACRO_OBSOLETE"}, + { CMSG_GHOST, "CMSG_GHOST"}, + { CMSG_GM_INVIS, "CMSG_GM_INVIS"}, + { SMSG_INVALID_PROMOTION_CODE, "SMSG_INVALID_PROMOTION_CODE"}, + { MSG_GM_BIND_OTHER, "MSG_GM_BIND_OTHER"}, + { MSG_GM_SUMMON, "MSG_GM_SUMMON"}, + { SMSG_ITEM_TIME_UPDATE, "SMSG_ITEM_TIME_UPDATE"}, + { SMSG_ITEM_ENCHANT_TIME_UPDATE, "SMSG_ITEM_ENCHANT_TIME_UPDATE"}, + { SMSG_AUTH_CHALLENGE, "SMSG_AUTH_CHALLENGE"}, + { CMSG_AUTH_SESSION, "CMSG_AUTH_SESSION"}, + { SMSG_AUTH_RESPONSE, "SMSG_AUTH_RESPONSE"}, + { MSG_GM_SHOWLABEL, "MSG_GM_SHOWLABEL"}, + { MSG_ADD_DYNAMIC_TARGET_OBSOLETE, "MSG_ADD_DYNAMIC_TARGET_OBSOLETE"}, + { MSG_SAVE_GUILD_EMBLEM, "MSG_SAVE_GUILD_EMBLEM"}, + { MSG_TABARDVENDOR_ACTIVATE, "MSG_TABARDVENDOR_ACTIVATE"}, + { SMSG_PLAY_SPELL_VISUAL, "SMSG_PLAY_SPELL_VISUAL"}, + { CMSG_ZONEUPDATE, "CMSG_ZONEUPDATE"}, + { SMSG_PARTYKILLLOG, "SMSG_PARTYKILLLOG"}, + { SMSG_COMPRESSED_UPDATE_OBJECT, "SMSG_COMPRESSED_UPDATE_OBJECT"}, + { SMSG_OBSOLETE, "SMSG_OBSOLETE"}, + { SMSG_EXPLORATION_EXPERIENCE, "SMSG_EXPLORATION_EXPERIENCE"}, + { CMSG_GM_SET_SECURITY_GROUP, "CMSG_GM_SET_SECURITY_GROUP"}, + { CMSG_GM_NUKE, "CMSG_GM_NUKE"}, + { MSG_RANDOM_ROLL, "MSG_RANDOM_ROLL"}, + { SMSG_ENVIRONMENTALDAMAGELOG, "SMSG_ENVIRONMENTALDAMAGELOG"}, + { CMSG_RWHOIS, "CMSG_RWHOIS"}, + { SMSG_RWHOIS, "SMSG_RWHOIS"}, + { MSG_LOOKING_FOR_GROUP, "MSG_LOOKING_FOR_GROUP"}, + { CMSG_SET_LOOKING_FOR_GROUP, "CMSG_SET_LOOKING_FOR_GROUP"}, + { CMSG_UNLEARN_SPELL, "CMSG_UNLEARN_SPELL"}, + { CMSG_UNLEARN_SKILL, "CMSG_UNLEARN_SKILL"}, + { SMSG_REMOVED_SPELL, "SMSG_REMOVED_SPELL"}, + { CMSG_DECHARGE, "CMSG_DECHARGE"}, + { CMSG_GMTICKET_CREATE, "CMSG_GMTICKET_CREATE"}, + { SMSG_GMTICKET_CREATE, "SMSG_GMTICKET_CREATE"}, + { CMSG_GMTICKET_UPDATETEXT, "CMSG_GMTICKET_UPDATETEXT"}, + { SMSG_GMTICKET_UPDATETEXT, "SMSG_GMTICKET_UPDATETEXT"}, + { SMSG_ACCOUNT_DATA_MD5, "SMSG_ACCOUNT_DATA_MD5"}, + { CMSG_REQUEST_ACCOUNT_DATA, "CMSG_REQUEST_ACCOUNT_DATA"}, + { CMSG_UPDATE_ACCOUNT_DATA, "CMSG_UPDATE_ACCOUNT_DATA"}, + { SMSG_UPDATE_ACCOUNT_DATA, "SMSG_UPDATE_ACCOUNT_DATA"}, + { SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE"}, + { SMSG_POWERGAINLOG_OBSOLETE, "SMSG_POWERGAINLOG_OBSOLETE"}, + { CMSG_GM_TEACH, "CMSG_GM_TEACH"}, + { CMSG_GM_CREATE_ITEM_TARGET, "CMSG_GM_CREATE_ITEM_TARGET"}, + { CMSG_GMTICKET_GETTICKET, "CMSG_GMTICKET_GETTICKET"}, + { SMSG_GMTICKET_GETTICKET, "SMSG_GMTICKET_GETTICKET"}, + { CMSG_UNLEARN_TALENTS, "CMSG_UNLEARN_TALENTS"}, + { SMSG_GAMEOBJECT_SPAWN_ANIM, "SMSG_GAMEOBJECT_SPAWN_ANIM"}, + { SMSG_GAMEOBJECT_DESPAWN_ANIM, "SMSG_GAMEOBJECT_DESPAWN_ANIM"}, + { MSG_CORPSE_QUERY, "MSG_CORPSE_QUERY"}, + { CMSG_GMTICKET_DELETETICKET, "CMSG_GMTICKET_DELETETICKET"}, + { SMSG_GMTICKET_DELETETICKET, "SMSG_GMTICKET_DELETETICKET"}, + { SMSG_CHAT_WRONG_FACTION, "SMSG_CHAT_WRONG_FACTION"}, + { CMSG_GMTICKET_SYSTEMSTATUS, "CMSG_GMTICKET_SYSTEMSTATUS"}, + { SMSG_GMTICKET_SYSTEMSTATUS, "SMSG_GMTICKET_SYSTEMSTATUS"}, + { CMSG_SPIRIT_HEALER_ACTIVATE, "CMSG_SPIRIT_HEALER_ACTIVATE"}, + { CMSG_SET_STAT_CHEAT, "CMSG_SET_STAT_CHEAT"}, + { SMSG_SET_REST_START, "SMSG_SET_REST_START"}, + { CMSG_SKILL_BUY_STEP, "CMSG_SKILL_BUY_STEP"}, + { CMSG_SKILL_BUY_RANK, "CMSG_SKILL_BUY_RANK"}, + { CMSG_XP_CHEAT, "CMSG_XP_CHEAT"}, + { SMSG_SPIRIT_HEALER_CONFIRM, "SMSG_SPIRIT_HEALER_CONFIRM"}, + { CMSG_CHARACTER_POINT_CHEAT, "CMSG_CHARACTER_POINT_CHEAT"}, + { SMSG_GOSSIP_POI, "SMSG_GOSSIP_POI"}, + { CMSG_CHAT_IGNORED, "CMSG_CHAT_IGNORED"}, + { CMSG_GM_VISION, "CMSG_GM_VISION"}, + { CMSG_SERVER_COMMAND, "CMSG_SERVER_COMMAND"}, + { CMSG_GM_SILENCE, "CMSG_GM_SILENCE"}, + { CMSG_GM_REVEALTO, "CMSG_GM_REVEALTO"}, + { CMSG_GM_RESURRECT, "CMSG_GM_RESURRECT"}, + { CMSG_GM_SUMMONMOB, "CMSG_GM_SUMMONMOB"}, + { CMSG_GM_MOVECORPSE, "CMSG_GM_MOVECORPSE"}, + { CMSG_GM_FREEZE, "CMSG_GM_FREEZE"}, + { CMSG_GM_UBERINVIS, "CMSG_GM_UBERINVIS"}, + { CMSG_GM_REQUEST_PLAYER_INFO, "CMSG_GM_REQUEST_PLAYER_INFO"}, + { SMSG_GM_PLAYER_INFO, "SMSG_GM_PLAYER_INFO"}, + { CMSG_GUILD_RANK, "CMSG_GUILD_RANK"}, + { CMSG_GUILD_ADD_RANK, "CMSG_GUILD_ADD_RANK"}, + { CMSG_GUILD_DEL_RANK, "CMSG_GUILD_DEL_RANK"}, + { CMSG_GUILD_SET_PUBLIC_NOTE, "CMSG_GUILD_SET_PUBLIC_NOTE"}, + { CMSG_GUILD_SET_OFFICER_NOTE, "CMSG_GUILD_SET_OFFICER_NOTE"}, + { SMSG_LOGIN_VERIFY_WORLD, "SMSG_LOGIN_VERIFY_WORLD"}, + { CMSG_CLEAR_EXPLORATION, "CMSG_CLEAR_EXPLORATION"}, + { CMSG_SEND_MAIL, "CMSG_SEND_MAIL"}, + { SMSG_SEND_MAIL_RESULT, "SMSG_SEND_MAIL_RESULT"}, + { CMSG_GET_MAIL_LIST, "CMSG_GET_MAIL_LIST"}, + { SMSG_MAIL_LIST_RESULT, "SMSG_MAIL_LIST_RESULT"}, + { CMSG_BATTLEFIELD_LIST, "CMSG_BATTLEFIELD_LIST"}, + { SMSG_BATTLEFIELD_LIST, "SMSG_BATTLEFIELD_LIST"}, + { CMSG_BATTLEFIELD_JOIN, "CMSG_BATTLEFIELD_JOIN"}, + { SMSG_BATTLEFIELD_WIN, "SMSG_BATTLEFIELD_WIN"}, + { SMSG_BATTLEFIELD_LOSE, "SMSG_BATTLEFIELD_LOSE"}, + { CMSG_TAXICLEARNODE, "CMSG_TAXICLEARNODE"}, + { CMSG_TAXIENABLENODE, "CMSG_TAXIENABLENODE"}, + { CMSG_ITEM_TEXT_QUERY, "CMSG_ITEM_TEXT_QUERY"}, + { SMSG_ITEM_TEXT_QUERY_RESPONSE, "SMSG_ITEM_TEXT_QUERY_RESPONSE"}, + { CMSG_MAIL_TAKE_MONEY, "CMSG_MAIL_TAKE_MONEY"}, + { CMSG_MAIL_TAKE_ITEM, "CMSG_MAIL_TAKE_ITEM"}, + { CMSG_MAIL_MARK_AS_READ, "CMSG_MAIL_MARK_AS_READ"}, + { CMSG_MAIL_RETURN_TO_SENDER, "CMSG_MAIL_RETURN_TO_SENDER"}, + { CMSG_MAIL_DELETE, "CMSG_MAIL_DELETE"}, + { CMSG_MAIL_CREATE_TEXT_ITEM, "CMSG_MAIL_CREATE_TEXT_ITEM"}, + { SMSG_SPELLLOGMISS, "SMSG_SPELLLOGMISS"}, + { SMSG_SPELLLOGEXECUTE, "SMSG_SPELLLOGEXECUTE"}, + { SMSG_DEBUGAURAPROC, "SMSG_DEBUGAURAPROC"}, + { SMSG_PERIODICAURALOG, "SMSG_PERIODICAURALOG"}, + { SMSG_SPELLDAMAGESHIELD, "SMSG_SPELLDAMAGESHIELD"}, + { SMSG_SPELLNONMELEEDAMAGELOG, "SMSG_SPELLNONMELEEDAMAGELOG"}, + { CMSG_LEARN_TALENT, "CMSG_LEARN_TALENT"}, + { SMSG_RESURRECT_FAILED, "SMSG_RESURRECT_FAILED"}, + { CMSG_TOGGLE_PVP, "CMSG_TOGGLE_PVP"}, + { SMSG_ZONE_UNDER_ATTACK, "SMSG_ZONE_UNDER_ATTACK"}, + { MSG_AUCTION_HELLO, "MSG_AUCTION_HELLO"}, + { CMSG_AUCTION_SELL_ITEM, "CMSG_AUCTION_SELL_ITEM"}, + { CMSG_AUCTION_REMOVE_ITEM, "CMSG_AUCTION_REMOVE_ITEM"}, + { CMSG_AUCTION_LIST_ITEMS, "CMSG_AUCTION_LIST_ITEMS"}, + { CMSG_AUCTION_LIST_OWNER_ITEMS, "CMSG_AUCTION_LIST_OWNER_ITEMS"}, + { CMSG_AUCTION_PLACE_BID, "CMSG_AUCTION_PLACE_BID"}, + { SMSG_AUCTION_COMMAND_RESULT, "SMSG_AUCTION_COMMAND_RESULT"}, + { SMSG_AUCTION_LIST_RESULT, "SMSG_AUCTION_LIST_RESULT"}, + { SMSG_AUCTION_OWNER_LIST_RESULT, "SMSG_AUCTION_OWNER_LIST_RESULT"}, + { SMSG_AUCTION_BIDDER_NOTIFICATION, "SMSG_AUCTION_BIDDER_NOTIFICATION"}, + { SMSG_AUCTION_OWNER_NOTIFICATION, "SMSG_AUCTION_OWNER_NOTIFICATION"}, + { SMSG_PROCRESIST, "SMSG_PROCRESIST"}, + { SMSG_STANDSTATE_CHANGE_FAILURE, "SMSG_STANDSTATE_CHANGE_FAILURE"}, + { SMSG_DISPEL_FAILED, "SMSG_DISPEL_FAILED"}, + { SMSG_SPELLORDAMAGE_IMMUNE, "SMSG_SPELLORDAMAGE_IMMUNE"}, + { CMSG_AUCTION_LIST_BIDDER_ITEMS, "CMSG_AUCTION_LIST_BIDDER_ITEMS"}, + { SMSG_AUCTION_BIDDER_LIST_RESULT, "SMSG_AUCTION_BIDDER_LIST_RESULT"}, + { SMSG_SET_FLAT_SPELL_MODIFIER, "SMSG_SET_FLAT_SPELL_MODIFIER"}, + { SMSG_SET_PCT_SPELL_MODIFIER, "SMSG_SET_PCT_SPELL_MODIFIER"}, + { CMSG_SET_AMMO, "CMSG_SET_AMMO"}, + { SMSG_CORPSE_RECLAIM_DELAY, "SMSG_CORPSE_RECLAIM_DELAY"}, + { CMSG_SET_ACTIVE_MOVER, "CMSG_SET_ACTIVE_MOVER"}, + { CMSG_PET_CANCEL_AURA, "CMSG_PET_CANCEL_AURA"}, + { CMSG_PLAYER_AI_CHEAT, "CMSG_PLAYER_AI_CHEAT"}, + { CMSG_CANCEL_AUTO_REPEAT_SPELL, "CMSG_CANCEL_AUTO_REPEAT_SPELL"}, + { MSG_GM_ACCOUNT_ONLINE, "MSG_GM_ACCOUNT_ONLINE"}, + { MSG_LIST_STABLED_PETS, "MSG_LIST_STABLED_PETS"}, + { CMSG_STABLE_PET, "CMSG_STABLE_PET"}, + { CMSG_UNSTABLE_PET, "CMSG_UNSTABLE_PET"}, + { CMSG_BUY_STABLE_SLOT, "CMSG_BUY_STABLE_SLOT"}, + { SMSG_STABLE_RESULT, "SMSG_STABLE_RESULT"}, + { CMSG_STABLE_REVIVE_PET, "CMSG_STABLE_REVIVE_PET"}, + { CMSG_STABLE_SWAP_PET, "CMSG_STABLE_SWAP_PET"}, + { MSG_QUEST_PUSH_RESULT, "MSG_QUEST_PUSH_RESULT"}, + { SMSG_PLAY_MUSIC, "SMSG_PLAY_MUSIC"}, + { SMSG_PLAY_OBJECT_SOUND, "SMSG_PLAY_OBJECT_SOUND"}, + { CMSG_REQUEST_PET_INFO, "CMSG_REQUEST_PET_INFO"}, + { CMSG_FAR_SIGHT, "CMSG_FAR_SIGHT"}, + { SMSG_SPELLDISPELLOG, "SMSG_SPELLDISPELLOG"}, + { SMSG_DAMAGE_CALC_LOG, "SMSG_DAMAGE_CALC_LOG"}, + { CMSG_ENABLE_DAMAGE_LOG, "CMSG_ENABLE_DAMAGE_LOG"}, + { CMSG_GROUP_CHANGE_SUB_GROUP, "CMSG_GROUP_CHANGE_SUB_GROUP"}, + { CMSG_REQUEST_PARTY_MEMBER_STATS, "CMSG_REQUEST_PARTY_MEMBER_STATS"}, + { CMSG_GROUP_SWAP_SUB_GROUP, "CMSG_GROUP_SWAP_SUB_GROUP"}, + { CMSG_RESET_FACTION_CHEAT, "CMSG_RESET_FACTION_CHEAT"}, + { CMSG_AUTOSTORE_BANK_ITEM, "CMSG_AUTOSTORE_BANK_ITEM"}, + { CMSG_AUTOBANK_ITEM, "CMSG_AUTOBANK_ITEM"}, + { MSG_QUERY_NEXT_MAIL_TIME, "MSG_QUERY_NEXT_MAIL_TIME"}, + { SMSG_RECEIVED_MAIL, "SMSG_RECEIVED_MAIL"}, + { SMSG_RAID_GROUP_ONLY, "SMSG_RAID_GROUP_ONLY"}, + { CMSG_SET_DURABILITY_CHEAT, "CMSG_SET_DURABILITY_CHEAT"}, + { CMSG_SET_PVP_RANK_CHEAT, "CMSG_SET_PVP_RANK_CHEAT"}, + { CMSG_ADD_PVP_MEDAL_CHEAT, "CMSG_ADD_PVP_MEDAL_CHEAT"}, + { CMSG_DEL_PVP_MEDAL_CHEAT, "CMSG_DEL_PVP_MEDAL_CHEAT"}, + { CMSG_SET_PVP_TITLE, "CMSG_SET_PVP_TITLE"}, + { SMSG_PVP_CREDIT, "SMSG_PVP_CREDIT"}, + { SMSG_AUCTION_REMOVED_NOTIFICATION, "SMSG_AUCTION_REMOVED_NOTIFICATION"}, + { CMSG_GROUP_RAID_CONVERT, "CMSG_GROUP_RAID_CONVERT"}, + { CMSG_GROUP_ASSISTANT_LEADER, "CMSG_GROUP_ASSISTANT_LEADER"}, + { CMSG_BUYBACK_ITEM, "CMSG_BUYBACK_ITEM"}, + { SMSG_SERVER_MESSAGE, "SMSG_SERVER_MESSAGE"}, + { CMSG_MEETINGSTONE_JOIN, "CMSG_MEETINGSTONE_JOIN"}, + { CMSG_MEETINGSTONE_LEAVE, "CMSG_MEETINGSTONE_LEAVE"}, + { CMSG_MEETINGSTONE_CHEAT, "CMSG_MEETINGSTONE_CHEAT"}, + { SMSG_MEETINGSTONE_SETQUEUE, "SMSG_MEETINGSTONE_SETQUEUE"}, + { CMSG_MEETINGSTONE_INFO, "CMSG_MEETINGSTONE_INFO"}, + { SMSG_MEETINGSTONE_COMPLETE, "SMSG_MEETINGSTONE_COMPLETE"}, + { SMSG_MEETINGSTONE_IN_PROGRESS, "SMSG_MEETINGSTONE_IN_PROGRESS"}, + { SMSG_MEETINGSTONE_MEMBER_ADDED, "SMSG_MEETINGSTONE_MEMBER_ADDED"}, + { CMSG_GMTICKETSYSTEM_TOGGLE, "CMSG_GMTICKETSYSTEM_TOGGLE"}, + { CMSG_CANCEL_GROWTH_AURA, "CMSG_CANCEL_GROWTH_AURA"}, + { SMSG_CANCEL_AUTO_REPEAT, "SMSG_CANCEL_AUTO_REPEAT"}, + { SMSG_STANDSTATE_CHANGE_ACK, "SMSG_STANDSTATE_CHANGE_ACK"}, + { SMSG_LOOT_ALL_PASSED, "SMSG_LOOT_ALL_PASSED"}, + { SMSG_LOOT_ROLL_WON, "SMSG_LOOT_ROLL_WON"}, + { CMSG_LOOT_ROLL, "CMSG_LOOT_ROLL"}, + { SMSG_LOOT_START_ROLL, "SMSG_LOOT_START_ROLL"}, + { SMSG_LOOT_ROLL, "SMSG_LOOT_ROLL"}, + { CMSG_LOOT_MASTER_GIVE, "CMSG_LOOT_MASTER_GIVE"}, + { SMSG_LOOT_MASTER_LIST, "SMSG_LOOT_MASTER_LIST"}, + { SMSG_SET_FORCED_REACTIONS, "SMSG_SET_FORCED_REACTIONS"}, + { SMSG_SPELL_FAILED_OTHER, "SMSG_SPELL_FAILED_OTHER"}, + { SMSG_GAMEOBJECT_RESET_STATE, "SMSG_GAMEOBJECT_RESET_STATE"}, + { CMSG_REPAIR_ITEM, "CMSG_REPAIR_ITEM"}, + { SMSG_CHAT_PLAYER_NOT_FOUND, "SMSG_CHAT_PLAYER_NOT_FOUND"}, + { MSG_TALENT_WIPE_CONFIRM, "MSG_TALENT_WIPE_CONFIRM"}, + { SMSG_SUMMON_REQUEST, "SMSG_SUMMON_REQUEST"}, + { CMSG_SUMMON_RESPONSE, "CMSG_SUMMON_RESPONSE"}, + { MSG_MOVE_TOGGLE_GRAVITY_CHEAT, "MSG_MOVE_TOGGLE_GRAVITY_CHEAT"}, + { SMSG_MONSTER_MOVE_TRANSPORT, "SMSG_MONSTER_MOVE_TRANSPORT"}, + { SMSG_PET_BROKEN, "SMSG_PET_BROKEN"}, + { MSG_MOVE_FEATHER_FALL, "MSG_MOVE_FEATHER_FALL"}, + { MSG_MOVE_WATER_WALK, "MSG_MOVE_WATER_WALK"}, + { CMSG_SERVER_BROADCAST, "CMSG_SERVER_BROADCAST"}, + { CMSG_SELF_RES, "CMSG_SELF_RES"}, + { SMSG_FEIGN_DEATH_RESISTED, "SMSG_FEIGN_DEATH_RESISTED"}, + { CMSG_RUN_SCRIPT, "CMSG_RUN_SCRIPT"}, + { SMSG_SCRIPT_MESSAGE, "SMSG_SCRIPT_MESSAGE"}, + { SMSG_DUEL_COUNTDOWN, "SMSG_DUEL_COUNTDOWN"}, + { SMSG_AREA_TRIGGER_MESSAGE, "SMSG_AREA_TRIGGER_MESSAGE"}, + { CMSG_TOGGLE_HELM, "CMSG_TOGGLE_HELM"}, + { CMSG_TOGGLE_CLOAK, "CMSG_TOGGLE_CLOAK"}, + { SMSG_MEETINGSTONE_JOINFAILED, "SMSG_MEETINGSTONE_JOINFAILED"}, + { SMSG_PLAYER_SKINNED, "SMSG_PLAYER_SKINNED"}, + { SMSG_DURABILITY_DAMAGE_DEATH, "SMSG_DURABILITY_DAMAGE_DEATH"}, + { CMSG_SET_EXPLORATION, "CMSG_SET_EXPLORATION"}, + { CMSG_SET_ACTIONBAR_TOGGLES, "CMSG_SET_ACTIONBAR_TOGGLES"}, + { UMSG_DELETE_GUILD_CHARTER, "UMSG_DELETE_GUILD_CHARTER"}, + { MSG_PETITION_RENAME, "MSG_PETITION_RENAME"}, + { SMSG_INIT_WORLD_STATES, "SMSG_INIT_WORLD_STATES"}, + { SMSG_UPDATE_WORLD_STATE, "SMSG_UPDATE_WORLD_STATE"}, + { CMSG_ITEM_NAME_QUERY, "CMSG_ITEM_NAME_QUERY"}, + { SMSG_ITEM_NAME_QUERY_RESPONSE, "SMSG_ITEM_NAME_QUERY_RESPONSE"}, + { SMSG_PET_ACTION_FEEDBACK, "SMSG_PET_ACTION_FEEDBACK"}, + { CMSG_CHAR_RENAME, "CMSG_CHAR_RENAME"}, + { SMSG_CHAR_RENAME, "SMSG_CHAR_RENAME"}, + { CMSG_MOVE_SPLINE_DONE, "CMSG_MOVE_SPLINE_DONE"}, + { CMSG_MOVE_FALL_RESET, "CMSG_MOVE_FALL_RESET"}, + { SMSG_INSTANCE_SAVE_CREATED, "SMSG_INSTANCE_SAVE_CREATED"}, + { SMSG_RAID_INSTANCE_INFO, "SMSG_RAID_INSTANCE_INFO"}, + { CMSG_REQUEST_RAID_INFO, "CMSG_REQUEST_RAID_INFO"}, + { CMSG_MOVE_TIME_SKIPPED, "CMSG_MOVE_TIME_SKIPPED"}, + { CMSG_MOVE_FEATHER_FALL_ACK, "CMSG_MOVE_FEATHER_FALL_ACK"}, + { CMSG_MOVE_WATER_WALK_ACK, "CMSG_MOVE_WATER_WALK_ACK"}, + { CMSG_MOVE_NOT_ACTIVE_MOVER, "CMSG_MOVE_NOT_ACTIVE_MOVER"}, + { SMSG_PLAY_SOUND, "SMSG_PLAY_SOUND"}, + { CMSG_BATTLEFIELD_STATUS, "CMSG_BATTLEFIELD_STATUS"}, + { SMSG_BATTLEFIELD_STATUS, "SMSG_BATTLEFIELD_STATUS"}, + { CMSG_BATTLEFIELD_PORT, "CMSG_BATTLEFIELD_PORT"}, + { MSG_INSPECT_HONOR_STATS, "MSG_INSPECT_HONOR_STATS"}, + { CMSG_BATTLEMASTER_HELLO, "CMSG_BATTLEMASTER_HELLO"}, + { CMSG_MOVE_START_SWIM_CHEAT, "CMSG_MOVE_START_SWIM_CHEAT"}, + { CMSG_MOVE_STOP_SWIM_CHEAT, "CMSG_MOVE_STOP_SWIM_CHEAT"}, + { SMSG_FORCE_WALK_SPEED_CHANGE, "SMSG_FORCE_WALK_SPEED_CHANGE"}, + { CMSG_FORCE_WALK_SPEED_CHANGE_ACK, "CMSG_FORCE_WALK_SPEED_CHANGE_ACK"}, + { SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE"}, + { CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK, "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK"}, + { SMSG_FORCE_TURN_RATE_CHANGE, "SMSG_FORCE_TURN_RATE_CHANGE"}, + { CMSG_FORCE_TURN_RATE_CHANGE_ACK, "CMSG_FORCE_TURN_RATE_CHANGE_ACK"}, + { MSG_PVP_LOG_DATA, "MSG_PVP_LOG_DATA"}, + { CMSG_LEAVE_BATTLEFIELD, "CMSG_LEAVE_BATTLEFIELD"}, + { CMSG_AREA_SPIRIT_HEALER_QUERY, "CMSG_AREA_SPIRIT_HEALER_QUERY"}, + { CMSG_AREA_SPIRIT_HEALER_QUEUE, "CMSG_AREA_SPIRIT_HEALER_QUEUE"}, + { SMSG_AREA_SPIRIT_HEALER_TIME, "SMSG_AREA_SPIRIT_HEALER_TIME"}, + { CMSG_GM_UNTEACH, "CMSG_GM_UNTEACH"}, + { SMSG_HARDWARE_SURVEY_REQUEST, "SMSG_HARDWARE_SURVEY_REQUEST"}, + { CMSG_HARDWARE_SURVEY_RESULTS, "CMSG_HARDWARE_SURVEY_RESULTS"}, + { SMSG_WARDEN_DATA, "SMSG_WARDEN_DATA"}, + { CMSG_WARDEN_DATA, "CMSG_WARDEN_DATA"}, + { SMSG_GROUP_JOINED_BATTLEGROUND, "SMSG_GROUP_JOINED_BATTLEGROUND"}, + { MSG_BATTLEGROUND_PLAYER_POSITIONS, "MSG_BATTLEGROUND_PLAYER_POSITIONS"}, + { CMSG_PET_STOP_ATTACK, "CMSG_PET_STOP_ATTACK"}, + { SMSG_BINDER_CONFIRM, "SMSG_BINDER_CONFIRM"}, + { SMSG_BATTLEGROUND_PLAYER_JOINED, "SMSG_BATTLEGROUND_PLAYER_JOINED"}, + { SMSG_BATTLEGROUND_PLAYER_LEFT, "SMSG_BATTLEGROUND_PLAYER_LEFT"}, + { CMSG_BATTLEMASTER_JOIN, "CMSG_BATTLEMASTER_JOIN"}, + { SMSG_ADDON_INFO, "SMSG_ADDON_INFO"}, + { CMSG_PET_UNLEARN, "CMSG_PET_UNLEARN"}, + { SMSG_PET_UNLEARN_CONFIRM, "SMSG_PET_UNLEARN_CONFIRM"}, + { SMSG_PARTY_MEMBER_STATS_FULL, "SMSG_PARTY_MEMBER_STATS_FULL"}, + { CMSG_PET_SPELL_AUTOCAST, "CMSG_PET_SPELL_AUTOCAST"}, + { SMSG_WEATHER, "SMSG_WEATHER"}, + { SMSG_PLAY_TIME_WARNING, "SMSG_PLAY_TIME_WARNING"}, + { SMSG_MINIGAME_SETUP, "SMSG_MINIGAME_SETUP"}, + { SMSG_MINIGAME_STATE, "SMSG_MINIGAME_STATE"}, + { CMSG_MINIGAME_MOVE, "CMSG_MINIGAME_MOVE"}, + { SMSG_MINIGAME_MOVE_FAILED, "SMSG_MINIGAME_MOVE_FAILED"}, + { CMSG_GUILD_CHANGEINFO, "CMSG_GUILD_CHANGEINFO"}, + { SMSG_OUTDOORPVP_NOTIFY, "SMSG_OUTDOORPVP_NOTIFY"}, // unofficial - first appeared in 1.12 + { 0, 0 } +}; + +char *className[]={"ERROR","Warrior","Paladin","Hunter","Rogue","Priest","FUTURE_1","Shaman","Mage","Warlock","FUTURE_2","Druid"}; +char *raceName[]={"ERROR","Human","Orc","Dwarf","Nightelf","Undead","Tauren","Gnome","Troll"}; + +NameTableEntry langNames[] = { + { LANG_GLOBAL, "Universal"}, + { LANG_UNIVERSAL, "Universal"}, + { LANG_ORCISH, "Orcish"}, + { LANG_DARNASSIAN, "Darnassian"}, + { LANG_TAURAHE, "Taurahe"}, + { LANG_DWARVISH, "Dwarvish"}, + { LANG_COMMON, "Common"}, + { LANG_DEMONIC, "Demonic"}, + { LANG_TITAN, "Titan"}, + { LANG_THELASSIAN, "Thelassian"}, + { LANG_DRACONIC, "Draconic"}, + { LANG_KALIMAG, "Kalimag"}, + { LANG_GNOMISH, "Gnomish"}, + { LANG_TROLL, "Troll"}, + { LANG_GUTTERSPEAK, "Gutterspeak"}, + {0,0} +}; + diff --git a/src/Client/World/Opcodes.h b/src/Client/World/Opcodes.h new file mode 100644 index 0000000..f641252 --- /dev/null +++ b/src/Client/World/Opcodes.h @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 _OPCODES_H +#define _OPCODES_H + +enum OpCodes +{ + MSG_NULL_ACTION = 0, + CMSG_BOOTME = 1, + CMSG_DBLOOKUP = 2, + SMSG_DBLOOKUP = 3, + CMSG_QUERY_OBJECT_POSITION = 4, + SMSG_QUERY_OBJECT_POSITION = 5, + CMSG_QUERY_OBJECT_ROTATION = 6, + SMSG_QUERY_OBJECT_ROTATION = 7, + CMSG_WORLD_TELEPORT = 8, + CMSG_TELEPORT_TO_UNIT = 9, + CMSG_ZONE_MAP = 10, + SMSG_ZONE_MAP = 11, + CMSG_DEBUG_CHANGECELLZONE = 12, + CMSG_EMBLAZON_TABARD_OBSOLETE = 13, + CMSG_UNEMBLAZON_TABARD_OBSOLETE = 14, + CMSG_RECHARGE = 15, + CMSG_LEARN_SPELL = 16, + CMSG_CREATEMONSTER = 17, + CMSG_DESTROYMONSTER = 18, + CMSG_CREATEITEM = 19, + CMSG_CREATEGAMEOBJECT = 20, + + //CMSG_MAKEMONSTERATTACKME = 21, //OBSOLETE + CMSG_MAKEMONSTERATTACKME_OBSOLETE = 21, + CMSG_MAKEMONSTERATTACKGUID = 22, + CMSG_ENABLEDEBUGCOMBATLOGGING_OBSOLETE = 23, + CMSG_FORCEACTION = 24, + CMSG_FORCEACTIONONOTHER = 25, + CMSG_FORCEACTIONSHOW = 26, + SMSG_FORCEACTIONSHOW = 27, + SMSG_ATTACKERSTATEUPDATEDEBUGINFO_OBSOLETE = 28, + SMSG_DEBUGINFOSPELL_OBSOLETE = 29, + SMSG_DEBUGINFOSPELLMISS_OBSOLETE = 30, + SMSG_DEBUG_PLAYER_RANGE_OBSOLETE = 31, + CMSG_UNDRESSPLAYER = 32, + CMSG_BEASTMASTER = 33, + CMSG_GODMODE = 34, + SMSG_GODMODE = 35, + CMSG_CHEAT_SETMONEY = 36, + CMSG_LEVEL_CHEAT = 37, + CMSG_PET_LEVEL_CHEAT = 38, + CMSG_LEVELUP_CHEAT_OBSOLETE = 39, + CMSG_COOLDOWN_CHEAT = 40, + CMSG_USE_SKILL_CHEAT = 41, + CMSG_FLAG_QUEST = 42, + CMSG_FLAG_QUEST_FINISH = 43, + CMSG_CLEAR_QUEST = 44, + CMSG_SEND_EVENT = 45, + CMSG_DEBUG_AISTATE = 46, + SMSG_DEBUG_AISTATE = 47, + CMSG_DISABLE_PVP_CHEAT = 48, + CMSG_ADVANCE_SPAWN_TIME = 49, + CMSG_PVP_PORT_OBSOLETE = 50, + CMSG_AUTH_SRP6_BEGIN = 51, + CMSG_AUTH_SRP6_PROOF = 52, + CMSG_AUTH_SRP6_RECODE = 53, + CMSG_CHAR_CREATE = 54, + CMSG_CHAR_ENUM = 55, + CMSG_CHAR_DELETE = 56, + SMSG_AUTH_SRP6_RESPONSE = 57, + SMSG_CHAR_CREATE = 58, + SMSG_CHAR_ENUM = 59, + SMSG_CHAR_DELETE = 60, + CMSG_PLAYER_LOGIN = 61, + SMSG_NEW_WORLD = 62, + SMSG_TRANSFER_PENDING = 63, + SMSG_TRANSFER_ABORTED = 64, + SMSG_CHARACTER_LOGIN_FAILED = 65, + SMSG_LOGIN_SETTIMESPEED = 66, + SMSG_GAMETIME_UPDATE = 67, + CMSG_GAMETIME_SET = 68, + SMSG_GAMETIME_SET = 69, + CMSG_GAMESPEED_SET = 70, + SMSG_GAMESPEED_SET = 71, + CMSG_SERVERTIME = 72, + SMSG_SERVERTIME = 73, + CMSG_PLAYER_LOGOUT = 74, + CMSG_LOGOUT_REQUEST = 75, + SMSG_LOGOUT_RESPONSE = 76, + SMSG_LOGOUT_COMPLETE = 77, + CMSG_LOGOUT_CANCEL = 78, + SMSG_LOGOUT_CANCEL_ACK = 79, + CMSG_NAME_QUERY = 80, + SMSG_NAME_QUERY_RESPONSE = 81, + CMSG_PET_NAME_QUERY = 82, + SMSG_PET_NAME_QUERY_RESPONSE = 83, + CMSG_GUILD_QUERY = 84, + SMSG_GUILD_QUERY_RESPONSE = 85, + CMSG_ITEM_QUERY_SINGLE = 86, + CMSG_ITEM_QUERY_MULTIPLE = 87, + SMSG_ITEM_QUERY_SINGLE_RESPONSE = 88, + SMSG_ITEM_QUERY_MULTIPLE_RESPONSE = 89, + CMSG_PAGE_TEXT_QUERY = 90, + SMSG_PAGE_TEXT_QUERY_RESPONSE = 91, + CMSG_QUEST_QUERY = 92, + SMSG_QUEST_QUERY_RESPONSE = 93, + CMSG_GAMEOBJECT_QUERY = 94, + SMSG_GAMEOBJECT_QUERY_RESPONSE = 95, + CMSG_CREATURE_QUERY = 96, + SMSG_CREATURE_QUERY_RESPONSE = 97, + CMSG_WHO = 98, + SMSG_WHO = 99, + CMSG_WHOIS = 100, + SMSG_WHOIS = 101, + CMSG_FRIEND_LIST = 102, + SMSG_FRIEND_LIST = 103, + SMSG_FRIEND_STATUS = 104, + CMSG_ADD_FRIEND = 105, + CMSG_DEL_FRIEND = 106, + SMSG_IGNORE_LIST = 107, + CMSG_ADD_IGNORE = 108, + CMSG_DEL_IGNORE = 109, + CMSG_GROUP_INVITE = 110, + SMSG_GROUP_INVITE = 111, + CMSG_GROUP_CANCEL = 112, + SMSG_GROUP_CANCEL = 113, + CMSG_GROUP_ACCEPT = 114, + CMSG_GROUP_DECLINE = 115, + SMSG_GROUP_DECLINE = 116, + CMSG_GROUP_UNINVITE = 117, + CMSG_GROUP_UNINVITE_GUID = 118, + SMSG_GROUP_UNINVITE = 119, + CMSG_GROUP_SET_LEADER = 120, + SMSG_GROUP_SET_LEADER = 121, + CMSG_LOOT_METHOD = 122, + CMSG_GROUP_DISBAND = 123, + SMSG_GROUP_DESTROYED = 124, + SMSG_GROUP_LIST = 125, + SMSG_PARTY_MEMBER_STATS = 126, + SMSG_PARTY_COMMAND_RESULT = 127, + UMSG_UPDATE_GROUP_MEMBERS = 128, + CMSG_GUILD_CREATE = 129, + CMSG_GUILD_INVITE = 130, + SMSG_GUILD_INVITE = 131, + CMSG_GUILD_ACCEPT = 132, + CMSG_GUILD_DECLINE = 133, + SMSG_GUILD_DECLINE = 134, + CMSG_GUILD_INFO = 135, + SMSG_GUILD_INFO = 136, + CMSG_GUILD_ROSTER = 137, + SMSG_GUILD_ROSTER = 138, + CMSG_GUILD_PROMOTE = 139, + CMSG_GUILD_DEMOTE = 140, + CMSG_GUILD_LEAVE = 141, + CMSG_GUILD_REMOVE = 142, + CMSG_GUILD_DISBAND = 143, + CMSG_GUILD_LEADER = 144, + CMSG_GUILD_MOTD = 145, + SMSG_GUILD_EVENT = 146, + SMSG_GUILD_COMMAND_RESULT = 147, + UMSG_UPDATE_GUILD = 148, + CMSG_MESSAGECHAT = 149, + SMSG_MESSAGECHAT = 150, + CMSG_JOIN_CHANNEL = 151, + CMSG_LEAVE_CHANNEL = 152, + SMSG_CHANNEL_NOTIFY = 153, + CMSG_CHANNEL_LIST = 154, + SMSG_CHANNEL_LIST = 155, + CMSG_CHANNEL_PASSWORD = 156, + CMSG_CHANNEL_SET_OWNER = 157, + CMSG_CHANNEL_OWNER = 158, + CMSG_CHANNEL_MODERATOR = 159, + CMSG_CHANNEL_UNMODERATOR = 160, + CMSG_CHANNEL_MUTE = 161, + CMSG_CHANNEL_UNMUTE = 162, + CMSG_CHANNEL_INVITE = 163, + CMSG_CHANNEL_KICK = 164, + CMSG_CHANNEL_BAN = 165, + CMSG_CHANNEL_UNBAN = 166, + CMSG_CHANNEL_ANNOUNCEMENTS = 167, + CMSG_CHANNEL_MODERATE = 168, + SMSG_UPDATE_OBJECT = 169, + SMSG_DESTROY_OBJECT = 170, + CMSG_USE_ITEM = 171, + CMSG_OPEN_ITEM = 172, + CMSG_READ_ITEM = 173, + SMSG_READ_ITEM_OK = 174, + SMSG_READ_ITEM_FAILED = 175, + SMSG_ITEM_COOLDOWN = 176, + CMSG_GAMEOBJ_USE = 177, + CMSG_GAMEOBJ_CHAIR_USE_OBSOLETE = 178, + SMSG_GAMEOBJECT_CUSTOM_ANIM = 179, + CMSG_AREATRIGGER = 180, + MSG_MOVE_START_FORWARD = 181, + MSG_MOVE_START_BACKWARD = 182, + MSG_MOVE_STOP = 183, + MSG_MOVE_START_STRAFE_LEFT = 184, + MSG_MOVE_START_STRAFE_RIGHT = 185, + MSG_MOVE_STOP_STRAFE = 186, + MSG_MOVE_JUMP = 187, + MSG_MOVE_START_TURN_LEFT = 188, + MSG_MOVE_START_TURN_RIGHT = 189, + MSG_MOVE_STOP_TURN = 190, + MSG_MOVE_START_PITCH_UP = 191, + MSG_MOVE_START_PITCH_DOWN = 192, + MSG_MOVE_STOP_PITCH = 193, + MSG_MOVE_SET_RUN_MODE = 194, + MSG_MOVE_SET_WALK_MODE = 195, + MSG_MOVE_TOGGLE_LOGGING = 196, + MSG_MOVE_TELEPORT = 197, + MSG_MOVE_TELEPORT_CHEAT = 198, + MSG_MOVE_TELEPORT_ACK = 199, + MSG_MOVE_TOGGLE_FALL_LOGGING = 200, + MSG_MOVE_FALL_LAND = 201, + MSG_MOVE_START_SWIM = 202, + MSG_MOVE_STOP_SWIM = 203, + MSG_MOVE_SET_RUN_SPEED_CHEAT = 204, + MSG_MOVE_SET_RUN_SPEED = 205, + MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT = 206, + MSG_MOVE_SET_RUN_BACK_SPEED = 207, + MSG_MOVE_SET_WALK_SPEED_CHEAT = 208, + MSG_MOVE_SET_WALK_SPEED = 209, + MSG_MOVE_SET_SWIM_SPEED_CHEAT = 210, + MSG_MOVE_SET_SWIM_SPEED = 211, + MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT = 212, + MSG_MOVE_SET_SWIM_BACK_SPEED = 213, + MSG_MOVE_SET_ALL_SPEED_CHEAT = 214, + MSG_MOVE_SET_TURN_RATE_CHEAT = 215, + MSG_MOVE_SET_TURN_RATE = 216, + MSG_MOVE_TOGGLE_COLLISION_CHEAT = 217, + MSG_MOVE_SET_FACING = 218, + MSG_MOVE_SET_PITCH = 219, + MSG_MOVE_WORLDPORT_ACK = 220, + SMSG_MONSTER_MOVE = 221, + SMSG_MOVE_WATER_WALK = 222, + SMSG_MOVE_LAND_WALK = 223, + MSG_MOVE_SET_RAW_POSITION_ACK = 224, + CMSG_MOVE_SET_RAW_POSITION = 225, + SMSG_FORCE_RUN_SPEED_CHANGE = 226, + CMSG_FORCE_RUN_SPEED_CHANGE_ACK = 227, + SMSG_FORCE_RUN_BACK_SPEED_CHANGE = 228, + CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK = 229, + SMSG_FORCE_SWIM_SPEED_CHANGE = 230, + CMSG_FORCE_SWIM_SPEED_CHANGE_ACK = 231, + SMSG_FORCE_MOVE_ROOT = 232, + CMSG_FORCE_MOVE_ROOT_ACK = 233, + SMSG_FORCE_MOVE_UNROOT = 234, + CMSG_FORCE_MOVE_UNROOT_ACK = 235, + MSG_MOVE_ROOT = 236, + MSG_MOVE_UNROOT = 237, + MSG_MOVE_HEARTBEAT = 238, + SMSG_MOVE_KNOCK_BACK = 239, + CMSG_MOVE_KNOCK_BACK_ACK = 240, + MSG_MOVE_KNOCK_BACK = 241, + SMSG_MOVE_FEATHER_FALL = 242, + SMSG_MOVE_NORMAL_FALL = 243, + SMSG_MOVE_SET_HOVER = 244, + SMSG_MOVE_UNSET_HOVER = 245, + CMSG_MOVE_HOVER_ACK = 246, + MSG_MOVE_HOVER = 247, + CMSG_TRIGGER_CINEMATIC_CHEAT = 248, + CMSG_OPENING_CINEMATIC = 249, + SMSG_TRIGGER_CINEMATIC = 250, + CMSG_NEXT_CINEMATIC_CAMERA = 251, + CMSG_COMPLETE_CINEMATIC = 252, + SMSG_TUTORIAL_FLAGS = 253, + CMSG_TUTORIAL_FLAG = 254, + CMSG_TUTORIAL_CLEAR = 255, + CMSG_TUTORIAL_RESET = 256, + CMSG_STANDSTATECHANGE = 257, + CMSG_EMOTE = 258, + SMSG_EMOTE = 259, + CMSG_TEXT_EMOTE = 260, + SMSG_TEXT_EMOTE = 261, + CMSG_AUTOEQUIP_GROUND_ITEM = 262, + CMSG_AUTOSTORE_GROUND_ITEM = 263, + CMSG_AUTOSTORE_LOOT_ITEM = 264, + CMSG_STORE_LOOT_IN_SLOT = 265, + CMSG_AUTOEQUIP_ITEM = 266, + CMSG_AUTOSTORE_BAG_ITEM = 267, + CMSG_SWAP_ITEM = 268, + CMSG_SWAP_INV_ITEM = 269, + CMSG_SPLIT_ITEM = 270, + CMSG_PICKUP_ITEM = 271, + CMSG_DROP_ITEM = 272, + CMSG_DESTROYITEM = 273, + SMSG_INVENTORY_CHANGE_FAILURE = 274, + SMSG_OPEN_CONTAINER = 275, + CMSG_INSPECT = 276, + SMSG_INSPECT = 277, + CMSG_INITIATE_TRADE = 278, + CMSG_BEGIN_TRADE = 279, + CMSG_BUSY_TRADE = 280, + CMSG_IGNORE_TRADE = 281, + CMSG_ACCEPT_TRADE = 282, + CMSG_UNACCEPT_TRADE = 283, + CMSG_CANCEL_TRADE = 284, + CMSG_SET_TRADE_ITEM = 285, + CMSG_CLEAR_TRADE_ITEM = 286, + CMSG_SET_TRADE_GOLD = 287, + SMSG_TRADE_STATUS = 288, + SMSG_TRADE_STATUS_EXTENDED = 289, + SMSG_INITIALIZE_FACTIONS = 290, + SMSG_SET_FACTION_VISIBLE = 291, + SMSG_SET_FACTION_STANDING = 292, + CMSG_SET_FACTION_ATWAR = 293, + CMSG_SET_FACTION_CHEAT = 294, + SMSG_SET_PROFICIENCY = 295, + CMSG_SET_ACTION_BUTTON = 296, + SMSG_ACTION_BUTTONS = 297, + SMSG_INITIAL_SPELLS = 298, + SMSG_LEARNED_SPELL = 299, + SMSG_SUPERCEDED_SPELL = 300, + CMSG_NEW_SPELL_SLOT = 301, + CMSG_CAST_SPELL = 302, + CMSG_CANCEL_CAST = 303, + SMSG_CAST_RESULT = 304, + SMSG_SPELL_START = 305, + SMSG_SPELL_GO = 306, + SMSG_SPELL_FAILURE = 307, + SMSG_SPELL_COOLDOWN = 308, + SMSG_COOLDOWN_EVENT = 309, + CMSG_CANCEL_AURA = 310, + SMSG_UPDATE_AURA_DURATION = 311, + SMSG_PET_CAST_FAILED = 312, + MSG_CHANNEL_START = 313, + MSG_CHANNEL_UPDATE = 314, + CMSG_CANCEL_CHANNELLING = 315, + SMSG_AI_REACTION = 316, + CMSG_SET_SELECTION = 317, + + //CMSG_SET_TARGET = 318, //OBSOLETE + CMSG_SET_TARGET_OBSOLETE = 318, + CMSG_UNUSED = 319, + CMSG_UNUSED2 = 320, + CMSG_ATTACKSWING = 321, + CMSG_ATTACKSTOP = 322, + SMSG_ATTACKSTART = 323, + SMSG_ATTACKSTOP = 324, + SMSG_ATTACKSWING_NOTINRANGE = 325, + SMSG_ATTACKSWING_BADFACING = 326, + SMSG_ATTACKSWING_NOTSTANDING = 327, + SMSG_ATTACKSWING_DEADTARGET = 328, + SMSG_ATTACKSWING_CANT_ATTACK = 329, + SMSG_ATTACKERSTATEUPDATE = 330, + SMSG_VICTIMSTATEUPDATE_OBSOLETE = 331, + SMSG_DAMAGE_DONE_OBSOLETE = 332, + SMSG_DAMAGE_TAKEN_OBSOLETE = 333, + SMSG_CANCEL_COMBAT = 334, + SMSG_PLAYER_COMBAT_XP_GAIN_OBSOLETE = 335, + SMSG_HEALSPELL_ON_PLAYER_OBSOLETE = 336, + SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE = 337, + CMSG_SHEATHE_OBSOLETE = 338, + CMSG_SAVE_PLAYER = 339, + CMSG_SETDEATHBINDPOINT = 340, + SMSG_BINDPOINTUPDATE = 341, + CMSG_GETDEATHBINDZONE = 342, + SMSG_BINDZONEREPLY = 343, + SMSG_PLAYERBOUND = 344, + SMSG_DEATH_NOTIFY_OBSOLETE = 345, + CMSG_REPOP_REQUEST = 346, + SMSG_RESURRECT_REQUEST = 347, + CMSG_RESURRECT_RESPONSE = 348, + CMSG_LOOT = 349, + CMSG_LOOT_MONEY = 350, + CMSG_LOOT_RELEASE = 351, + SMSG_LOOT_RESPONSE = 352, + SMSG_LOOT_RELEASE_RESPONSE = 353, + SMSG_LOOT_REMOVED = 354, + SMSG_LOOT_MONEY_NOTIFY = 355, + SMSG_LOOT_ITEM_NOTIFY = 356, + SMSG_LOOT_CLEAR_MONEY = 357, + SMSG_ITEM_PUSH_RESULT = 358, + SMSG_DUEL_REQUESTED = 359, + SMSG_DUEL_OUTOFBOUNDS = 360, + SMSG_DUEL_INBOUNDS = 361, + SMSG_DUEL_COMPLETE = 362, + SMSG_DUEL_WINNER = 363, + CMSG_DUEL_ACCEPTED = 364, + CMSG_DUEL_CANCELLED = 365, + SMSG_MOUNTRESULT = 366, + SMSG_DISMOUNTRESULT = 367, + SMSG_PUREMOUNT_CANCELLED_OBSOLETE = 368, + CMSG_MOUNTSPECIAL_ANIM = 369, + SMSG_MOUNTSPECIAL_ANIM = 370, + SMSG_PET_TAME_FAILURE = 371, + CMSG_PET_SET_ACTION = 372, + CMSG_PET_ACTION = 373, + CMSG_PET_ABANDON = 374, + CMSG_PET_RENAME = 375, + SMSG_PET_NAME_INVALID = 376, + SMSG_PET_SPELLS = 377, + + //CMSG_PET_CAST_SPELL_OBSOLETE = 378, //OBSOLETE + SMSG_PET_MODE = 378, + CMSG_GOSSIP_HELLO = 379, + CMSG_GOSSIP_SELECT_OPTION = 380, + SMSG_GOSSIP_MESSAGE = 381, + SMSG_GOSSIP_COMPLETE = 382, + CMSG_NPC_TEXT_QUERY = 383, + SMSG_NPC_TEXT_UPDATE = 384, + SMSG_NPC_WONT_TALK = 385, + CMSG_QUESTGIVER_STATUS_QUERY = 386, + SMSG_QUESTGIVER_STATUS = 387, + CMSG_QUESTGIVER_HELLO = 388, + SMSG_QUESTGIVER_QUEST_LIST = 389, + CMSG_QUESTGIVER_QUERY_QUEST = 390, + CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 391, + SMSG_QUESTGIVER_QUEST_DETAILS = 392, + CMSG_QUESTGIVER_ACCEPT_QUEST = 393, + CMSG_QUESTGIVER_COMPLETE_QUEST = 394, + SMSG_QUESTGIVER_REQUEST_ITEMS = 395, + CMSG_QUESTGIVER_REQUEST_REWARD = 396, + SMSG_QUESTGIVER_OFFER_REWARD = 397, + CMSG_QUESTGIVER_CHOOSE_REWARD = 398, + SMSG_QUESTGIVER_QUEST_INVALID = 399, + CMSG_QUESTGIVER_CANCEL = 400, + SMSG_QUESTGIVER_QUEST_COMPLETE = 401, + SMSG_QUESTGIVER_QUEST_FAILED = 402, + CMSG_QUESTLOG_SWAP_QUEST = 403, + CMSG_QUESTLOG_REMOVE_QUEST = 404, + SMSG_QUESTLOG_FULL = 405, + SMSG_QUESTUPDATE_FAILED = 406, + SMSG_QUESTUPDATE_FAILEDTIMER = 407, + SMSG_QUESTUPDATE_COMPLETE = 408, + SMSG_QUESTUPDATE_ADD_KILL = 409, + SMSG_QUESTUPDATE_ADD_ITEM = 410, + CMSG_QUEST_CONFIRM_ACCEPT = 411, + SMSG_QUEST_CONFIRM_ACCEPT = 412, + CMSG_PUSHQUESTTOPARTY = 413, + CMSG_LIST_INVENTORY = 414, + SMSG_LIST_INVENTORY = 415, + CMSG_SELL_ITEM = 416, + SMSG_SELL_ITEM = 417, + CMSG_BUY_ITEM = 418, + CMSG_BUY_ITEM_IN_SLOT = 419, + SMSG_BUY_ITEM = 420, + SMSG_BUY_FAILED = 421, + CMSG_TAXICLEARALLNODES = 422, + CMSG_TAXIENABLEALLNODES = 423, + CMSG_TAXISHOWNODES = 424, + SMSG_SHOWTAXINODES = 425, + CMSG_TAXINODE_STATUS_QUERY = 426, + SMSG_TAXINODE_STATUS = 427, + CMSG_TAXIQUERYAVAILABLENODES = 428, + CMSG_ACTIVATETAXI = 429, + SMSG_ACTIVATETAXIREPLY = 430, + SMSG_NEW_TAXI_PATH = 431, + CMSG_TRAINER_LIST = 432, + SMSG_TRAINER_LIST = 433, + CMSG_TRAINER_BUY_SPELL = 434, + SMSG_TRAINER_BUY_SUCCEEDED = 435, + SMSG_TRAINER_BUY_FAILED = 436, + CMSG_BINDER_ACTIVATE = 437, + SMSG_PLAYERBINDERROR = 438, + CMSG_BANKER_ACTIVATE = 439, + SMSG_SHOW_BANK = 440, + CMSG_BUY_BANK_SLOT = 441, + SMSG_BUY_BANK_SLOT_RESULT = 442, + CMSG_PETITION_SHOWLIST = 443, + SMSG_PETITION_SHOWLIST = 444, + CMSG_PETITION_BUY = 445, + CMSG_PETITION_SHOW_SIGNATURES = 446, + SMSG_PETITION_SHOW_SIGNATURES = 447, + CMSG_PETITION_SIGN = 448, + SMSG_PETITION_SIGN_RESULTS = 449, + MSG_PETITION_DECLINE = 450, + CMSG_OFFER_PETITION = 451, + CMSG_TURN_IN_PETITION = 452, + SMSG_TURN_IN_PETITION_RESULTS = 453, + CMSG_PETITION_QUERY = 454, + SMSG_PETITION_QUERY_RESPONSE = 455, + SMSG_FISH_NOT_HOOKED = 456, + SMSG_FISH_ESCAPED = 457, + CMSG_BUG = 458, + SMSG_NOTIFICATION = 459, + CMSG_PLAYED_TIME = 460, + SMSG_PLAYED_TIME = 461, + CMSG_QUERY_TIME = 462, + SMSG_QUERY_TIME_RESPONSE = 463, + SMSG_LOG_XPGAIN = 464, + MSG_SPLIT_MONEY = 465, + CMSG_RECLAIM_CORPSE = 466, + CMSG_WRAP_ITEM = 467, + SMSG_LEVELUP_INFO = 468, + MSG_MINIMAP_PING = 469, + SMSG_RESISTLOG = 470, + SMSG_ENCHANTMENTLOG = 471, + CMSG_SET_SKILL_CHEAT = 472, + SMSG_START_MIRROR_TIMER = 473, + SMSG_PAUSE_MIRROR_TIMER = 474, + SMSG_STOP_MIRROR_TIMER = 475, + CMSG_PING = 476, + SMSG_PONG = 477, + SMSG_CLEAR_COOLDOWN = 478, + SMSG_GAMEOBJECT_PAGETEXT = 479, + CMSG_SETSHEATHED = 480, + SMSG_COOLDOWN_CHEAT = 481, + SMSG_SPELL_DELAYED = 482, + CMSG_PLAYER_MACRO_OBSOLETE = 483, + SMSG_PLAYER_MACRO_OBSOLETE = 484, + CMSG_GHOST = 485, + CMSG_GM_INVIS = 486, + + //CMSG_SCREENSHOT = 487, //OBSOLETE + SMSG_INVALID_PROMOTION_CODE = 487, + MSG_GM_BIND_OTHER = 488, + MSG_GM_SUMMON = 489, + SMSG_ITEM_TIME_UPDATE = 490, + SMSG_ITEM_ENCHANT_TIME_UPDATE = 491, + SMSG_AUTH_CHALLENGE = 492, + CMSG_AUTH_SESSION = 493, + SMSG_AUTH_RESPONSE = 494, + MSG_GM_SHOWLABEL = 495, + + //MSG_ADD_DYNAMIC_TARGET = 496, //OBSOLETE + MSG_ADD_DYNAMIC_TARGET_OBSOLETE = 496, + MSG_SAVE_GUILD_EMBLEM = 497, + MSG_TABARDVENDOR_ACTIVATE = 498, + SMSG_PLAY_SPELL_VISUAL = 499, + CMSG_ZONEUPDATE = 500, + SMSG_PARTYKILLLOG = 501, + SMSG_COMPRESSED_UPDATE_OBJECT = 502, + SMSG_OBSOLETE = 503, + SMSG_EXPLORATION_EXPERIENCE = 504, + CMSG_GM_SET_SECURITY_GROUP = 505, + CMSG_GM_NUKE = 506, + MSG_RANDOM_ROLL = 507, + SMSG_ENVIRONMENTALDAMAGELOG = 508, + CMSG_RWHOIS = 509, + SMSG_RWHOIS = 510, + MSG_LOOKING_FOR_GROUP = 511, + CMSG_SET_LOOKING_FOR_GROUP = 512, + CMSG_UNLEARN_SPELL = 513, + CMSG_UNLEARN_SKILL = 514, + SMSG_REMOVED_SPELL = 515, + CMSG_DECHARGE = 516, + CMSG_GMTICKET_CREATE = 517, + SMSG_GMTICKET_CREATE = 518, + CMSG_GMTICKET_UPDATETEXT = 519, + SMSG_GMTICKET_UPDATETEXT = 520, + SMSG_ACCOUNT_DATA_MD5 = 521, + CMSG_REQUEST_ACCOUNT_DATA = 522, + CMSG_UPDATE_ACCOUNT_DATA = 523, + SMSG_UPDATE_ACCOUNT_DATA = 524, + SMSG_CLEAR_FAR_SIGHT_IMMEDIATE = 525, + SMSG_POWERGAINLOG_OBSOLETE = 526, + CMSG_GM_TEACH = 527, + CMSG_GM_CREATE_ITEM_TARGET = 528, + CMSG_GMTICKET_GETTICKET = 529, + SMSG_GMTICKET_GETTICKET = 530, + CMSG_UNLEARN_TALENTS = 531, + SMSG_GAMEOBJECT_SPAWN_ANIM = 532, + SMSG_GAMEOBJECT_DESPAWN_ANIM = 533, + MSG_CORPSE_QUERY = 534, + CMSG_GMTICKET_DELETETICKET = 535, + SMSG_GMTICKET_DELETETICKET = 536, + SMSG_CHAT_WRONG_FACTION = 537, + CMSG_GMTICKET_SYSTEMSTATUS = 538, + SMSG_GMTICKET_SYSTEMSTATUS = 539, + CMSG_SPIRIT_HEALER_ACTIVATE = 540, + CMSG_SET_STAT_CHEAT = 541, + SMSG_SET_REST_START = 542, + CMSG_SKILL_BUY_STEP = 543, + CMSG_SKILL_BUY_RANK = 544, + CMSG_XP_CHEAT = 545, + SMSG_SPIRIT_HEALER_CONFIRM = 546, + CMSG_CHARACTER_POINT_CHEAT = 547, + SMSG_GOSSIP_POI = 548, + CMSG_CHAT_IGNORED = 549, + CMSG_GM_VISION = 550, + CMSG_SERVER_COMMAND = 551, + CMSG_GM_SILENCE = 552, + CMSG_GM_REVEALTO = 553, + CMSG_GM_RESURRECT = 554, + CMSG_GM_SUMMONMOB = 555, + CMSG_GM_MOVECORPSE = 556, + CMSG_GM_FREEZE = 557, + CMSG_GM_UBERINVIS = 558, + CMSG_GM_REQUEST_PLAYER_INFO = 559, + SMSG_GM_PLAYER_INFO = 560, + CMSG_GUILD_RANK = 561, + CMSG_GUILD_ADD_RANK = 562, + CMSG_GUILD_DEL_RANK = 563, + CMSG_GUILD_SET_PUBLIC_NOTE = 564, + CMSG_GUILD_SET_OFFICER_NOTE = 565, + SMSG_LOGIN_VERIFY_WORLD = 566, + CMSG_CLEAR_EXPLORATION = 567, + CMSG_SEND_MAIL = 568, + SMSG_SEND_MAIL_RESULT = 569, + CMSG_GET_MAIL_LIST = 570, + SMSG_MAIL_LIST_RESULT = 571, + CMSG_BATTLEFIELD_LIST = 572, + SMSG_BATTLEFIELD_LIST = 573, + CMSG_BATTLEFIELD_JOIN = 574, + SMSG_BATTLEFIELD_WIN = 575, + SMSG_BATTLEFIELD_LOSE = 576, + CMSG_TAXICLEARNODE = 577, + CMSG_TAXIENABLENODE = 578, + CMSG_ITEM_TEXT_QUERY = 579, + SMSG_ITEM_TEXT_QUERY_RESPONSE = 580, + CMSG_MAIL_TAKE_MONEY = 581, + CMSG_MAIL_TAKE_ITEM = 582, + CMSG_MAIL_MARK_AS_READ = 583, + CMSG_MAIL_RETURN_TO_SENDER = 584, + CMSG_MAIL_DELETE = 585, + CMSG_MAIL_CREATE_TEXT_ITEM = 586, + SMSG_SPELLLOGMISS = 587, + SMSG_SPELLLOGEXECUTE = 588, + SMSG_DEBUGAURAPROC = 589, + SMSG_PERIODICAURALOG = 590, + SMSG_SPELLDAMAGESHIELD = 591, + SMSG_SPELLNONMELEEDAMAGELOG = 592, + CMSG_LEARN_TALENT = 593, + SMSG_RESURRECT_FAILED = 594, + + //CMSG_ENABLE_PVP = 595, //OBSOLETE + CMSG_TOGGLE_PVP = 595, + SMSG_ZONE_UNDER_ATTACK = 596, + MSG_AUCTION_HELLO = 597, + CMSG_AUCTION_SELL_ITEM = 598, + CMSG_AUCTION_REMOVE_ITEM = 599, + CMSG_AUCTION_LIST_ITEMS = 600, + CMSG_AUCTION_LIST_OWNER_ITEMS = 601, + CMSG_AUCTION_PLACE_BID = 602, + SMSG_AUCTION_COMMAND_RESULT = 603, + SMSG_AUCTION_LIST_RESULT = 604, + SMSG_AUCTION_OWNER_LIST_RESULT = 605, + SMSG_AUCTION_BIDDER_NOTIFICATION = 606, + SMSG_AUCTION_OWNER_NOTIFICATION = 607, + SMSG_PROCRESIST = 608, + SMSG_STANDSTATE_CHANGE_FAILURE = 609, + SMSG_DISPEL_FAILED = 610, + SMSG_SPELLORDAMAGE_IMMUNE = 611, + CMSG_AUCTION_LIST_BIDDER_ITEMS = 612, + SMSG_AUCTION_BIDDER_LIST_RESULT = 613, + SMSG_SET_FLAT_SPELL_MODIFIER = 614, + SMSG_SET_PCT_SPELL_MODIFIER = 615, + CMSG_SET_AMMO = 616, + SMSG_CORPSE_RECLAIM_DELAY = 617, + CMSG_SET_ACTIVE_MOVER = 618, + CMSG_PET_CANCEL_AURA = 619, + CMSG_PLAYER_AI_CHEAT = 620, + CMSG_CANCEL_AUTO_REPEAT_SPELL = 621, + MSG_GM_ACCOUNT_ONLINE = 622, + MSG_LIST_STABLED_PETS = 623, + CMSG_STABLE_PET = 624, + CMSG_UNSTABLE_PET = 625, + CMSG_BUY_STABLE_SLOT = 626, + SMSG_STABLE_RESULT = 627, + CMSG_STABLE_REVIVE_PET = 628, + CMSG_STABLE_SWAP_PET = 629, + MSG_QUEST_PUSH_RESULT = 630, + SMSG_PLAY_MUSIC = 631, + SMSG_PLAY_OBJECT_SOUND = 632, + CMSG_REQUEST_PET_INFO = 633, + CMSG_FAR_SIGHT = 634, + SMSG_SPELLDISPELLOG = 635, + SMSG_DAMAGE_CALC_LOG = 636, + CMSG_ENABLE_DAMAGE_LOG = 637, + CMSG_GROUP_CHANGE_SUB_GROUP = 638, + + //SMSG_RAID_MEMBER_STATS = 639, //OBSOLETE + CMSG_REQUEST_PARTY_MEMBER_STATS = 639, + CMSG_GROUP_SWAP_SUB_GROUP = 640, + CMSG_RESET_FACTION_CHEAT = 641, + CMSG_AUTOSTORE_BANK_ITEM = 642, + CMSG_AUTOBANK_ITEM = 643, + MSG_QUERY_NEXT_MAIL_TIME = 644, + SMSG_RECEIVED_MAIL = 645, + SMSG_RAID_GROUP_ONLY = 646, + CMSG_SET_DURABILITY_CHEAT = 647, + CMSG_SET_PVP_RANK_CHEAT = 648, + CMSG_ADD_PVP_MEDAL_CHEAT = 649, + CMSG_DEL_PVP_MEDAL_CHEAT = 650, + CMSG_SET_PVP_TITLE = 651, + SMSG_PVP_CREDIT = 652, + SMSG_AUCTION_REMOVED_NOTIFICATION = 653, + CMSG_GROUP_RAID_CONVERT = 654, + CMSG_GROUP_ASSISTANT_LEADER = 655, + CMSG_BUYBACK_ITEM = 656, + SMSG_SERVER_MESSAGE = 657, + CMSG_MEETINGSTONE_JOIN = 658, + CMSG_MEETINGSTONE_LEAVE = 659, + CMSG_MEETINGSTONE_CHEAT = 660, + SMSG_MEETINGSTONE_SETQUEUE = 661, + CMSG_MEETINGSTONE_INFO = 662, + SMSG_MEETINGSTONE_COMPLETE = 663, + SMSG_MEETINGSTONE_IN_PROGRESS = 664, + SMSG_MEETINGSTONE_MEMBER_ADDED = 665, + CMSG_GMTICKETSYSTEM_TOGGLE = 666, + CMSG_CANCEL_GROWTH_AURA = 667, + SMSG_CANCEL_AUTO_REPEAT = 668, + SMSG_STANDSTATE_CHANGE_ACK = 669, + SMSG_LOOT_ALL_PASSED = 670, + SMSG_LOOT_ROLL_WON = 671, + CMSG_LOOT_ROLL = 672, + SMSG_LOOT_START_ROLL = 673, + SMSG_LOOT_ROLL = 674, + CMSG_LOOT_MASTER_GIVE = 675, + SMSG_LOOT_MASTER_LIST = 676, + SMSG_SET_FORCED_REACTIONS = 677, + SMSG_SPELL_FAILED_OTHER = 678, + SMSG_GAMEOBJECT_RESET_STATE = 679, + CMSG_REPAIR_ITEM = 680, + SMSG_CHAT_PLAYER_NOT_FOUND = 681, + MSG_TALENT_WIPE_CONFIRM = 682, + SMSG_SUMMON_REQUEST = 683, + CMSG_SUMMON_RESPONSE = 684, + MSG_MOVE_TOGGLE_GRAVITY_CHEAT = 685, + SMSG_MONSTER_MOVE_TRANSPORT = 686, + SMSG_PET_BROKEN = 687, + MSG_MOVE_FEATHER_FALL = 688, + MSG_MOVE_WATER_WALK = 689, + CMSG_SERVER_BROADCAST = 690, + CMSG_SELF_RES = 691, + SMSG_FEIGN_DEATH_RESISTED = 692, + CMSG_RUN_SCRIPT = 693, + SMSG_SCRIPT_MESSAGE = 694, + SMSG_DUEL_COUNTDOWN = 695, + SMSG_AREA_TRIGGER_MESSAGE = 696, + CMSG_TOGGLE_HELM = 697, + CMSG_TOGGLE_CLOAK = 698, + + //SMSG_SPELL_REFLECTED = 699, //OBSOLETE + SMSG_MEETINGSTONE_JOINFAILED = 699, + SMSG_PLAYER_SKINNED = 700, + SMSG_DURABILITY_DAMAGE_DEATH = 701, + CMSG_SET_EXPLORATION = 702, + CMSG_SET_ACTIONBAR_TOGGLES = 703, + UMSG_DELETE_GUILD_CHARTER = 704, + MSG_PETITION_RENAME = 705, + SMSG_INIT_WORLD_STATES = 706, + SMSG_UPDATE_WORLD_STATE = 707, + CMSG_ITEM_NAME_QUERY = 708, + SMSG_ITEM_NAME_QUERY_RESPONSE = 709, + SMSG_PET_ACTION_FEEDBACK = 710, + CMSG_CHAR_RENAME = 711, + SMSG_CHAR_RENAME = 712, + CMSG_MOVE_SPLINE_DONE = 713, + CMSG_MOVE_FALL_RESET = 714, + SMSG_INSTANCE_SAVE_CREATED = 715, + SMSG_RAID_INSTANCE_INFO = 716, + CMSG_REQUEST_RAID_INFO = 717, + CMSG_MOVE_TIME_SKIPPED = 718, + CMSG_MOVE_FEATHER_FALL_ACK = 719, + CMSG_MOVE_WATER_WALK_ACK = 720, + CMSG_MOVE_NOT_ACTIVE_MOVER = 721, + SMSG_PLAY_SOUND = 722, + CMSG_BATTLEFIELD_STATUS = 723, + SMSG_BATTLEFIELD_STATUS = 724, + CMSG_BATTLEFIELD_PORT = 725, + MSG_INSPECT_HONOR_STATS = 726, + CMSG_BATTLEMASTER_HELLO = 727, + CMSG_MOVE_START_SWIM_CHEAT = 728, + CMSG_MOVE_STOP_SWIM_CHEAT = 729, + SMSG_FORCE_WALK_SPEED_CHANGE = 730, + CMSG_FORCE_WALK_SPEED_CHANGE_ACK = 731, + SMSG_FORCE_SWIM_BACK_SPEED_CHANGE = 732, + CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK = 733, + SMSG_FORCE_TURN_RATE_CHANGE = 734, + CMSG_FORCE_TURN_RATE_CHANGE_ACK = 735, + MSG_PVP_LOG_DATA = 736, + CMSG_LEAVE_BATTLEFIELD = 737, + CMSG_AREA_SPIRIT_HEALER_QUERY = 738, + CMSG_AREA_SPIRIT_HEALER_QUEUE = 739, + SMSG_AREA_SPIRIT_HEALER_TIME = 740, + CMSG_GM_UNTEACH = 739, + SMSG_HARDWARE_SURVEY_REQUEST = 740, + CMSG_HARDWARE_SURVEY_RESULTS = 741, + SMSG_WARDEN_DATA = 742, + CMSG_WARDEN_DATA = 743, + SMSG_GROUP_JOINED_BATTLEGROUND = 744, + MSG_BATTLEGROUND_PLAYER_POSITIONS = 745, + + //strange!! + //MSG_BINDPOINT_CONFIRM = SMSG_BINDER_CONFIRM, + + //TODO Check double check if the -2 is correct + CMSG_PET_STOP_ATTACK = 746, + SMSG_BINDER_CONFIRM = 747, + SMSG_BATTLEGROUND_PLAYER_JOINED = 748, + SMSG_BATTLEGROUND_PLAYER_LEFT = 749, + CMSG_BATTLEMASTER_JOIN = 750, + + SMSG_ADDON_INFO = 753-2, + CMSG_PET_UNLEARN = 754-2, + SMSG_PET_UNLEARN_CONFIRM = 755-2, + SMSG_PARTY_MEMBER_STATS_FULL = 756-2, + CMSG_PET_SPELL_AUTOCAST = 757-2, + SMSG_WEATHER = 758-2, + SMSG_PLAY_TIME_WARNING = 759-2, + SMSG_MINIGAME_SETUP = 760-2, + SMSG_MINIGAME_STATE = 761-2, + CMSG_MINIGAME_MOVE = 762-2, + SMSG_MINIGAME_MOVE_FAILED = 763-2, + CMSG_GUILD_CHANGEINFO = 764-2, + + CMSG_ACTIVATETAXI_FAR = 786, + //griphon related = 786 + + CMSG_FIELD_WATCHED_FACTION_INACTIVE = 791, + CMSG_FIELD_WATCHED_FACTION_SHOW_BAR = 792, + + // unofficial opcodes: + SMSG_OUTDOORPVP_NOTIFY = 0x33b, // 827 +}; + +enum FriendsResult +{ + FRIEND_DB_ERROR = 0x00, + FRIEND_LIST_FULL = 0x01, + FRIEND_ONLINE = 0x02, + FRIEND_OFFLINE = 0x03, + FRIEND_NOT_FOUND = 0x04, + FRIEND_REMOVED = 0x05, + FRIEND_ADDED_ONLINE = 0x06, + FRIEND_ADDED_OFFLINE = 0x07, + FRIEND_ALREADY = 0x08, + FRIEND_SELF = 0x09, + FRIEND_ENEMY = 0x0A, + FRIEND_IGNORE_FULL = 0x0B, + FRIEND_IGNORE_SELF = 0x0C, + FRIEND_IGNORE_NOT_FOUND = 0x0D, + FRIEND_IGNORE_ALREADY = 0x0E, + FRIEND_IGNORE_ADDED = 0x0F, + FRIEND_IGNORE_REMOVED = 0x10 +}; + +enum NPCFlags +{ + UNIT_NPC_FLAG_NONE = 0, + UNIT_NPC_FLAG_GOSSIP = 1, + UNIT_NPC_FLAG_QUESTGIVER = 2, + UNIT_NPC_FLAG_VENDOR = 4, + UNIT_NPC_FLAG_TAXIVENDOR = 8, + UNIT_NPC_FLAG_TRAINER = 16, + UNIT_NPC_FLAG_SPIRITHEALER = 32, + UNIT_NPC_FLAG_GUARD = 64, //UQ1: ??? We can use as guard flag? + UNIT_NPC_FLAG_INNKEEPER = 128, + UNIT_NPC_FLAG_BANKER = 256, + UNIT_NPC_FLAG_PETITIONER = 512, + UNIT_NPC_FLAG_TABARDVENDOR = 1024, + UNIT_NPC_FLAG_BATTLEFIELDPERSON = 2048, + UNIT_NPC_FLAG_AUCTIONEER = 4096, + UNIT_NPC_FLAG_STABLE = 8192, + UNIT_NPC_FLAG_ARMORER = 16384, +}; + +typedef struct +{ + uint64 PlayerGUID; + unsigned char Status; + + uint32 Area; + uint32 Level; + uint32 Class; +} FriendStr ; +#endif diff --git a/src/Client/World/Player.cpp b/src/Client/World/Player.cpp new file mode 100644 index 0000000..2a66027 --- /dev/null +++ b/src/Client/World/Player.cpp @@ -0,0 +1,117 @@ +#include +#include +#include "common.h" +#include "PseuWoW.h" +#include "Opcodes.h" +#include "WorldPacketHandler.h" +#include "SharedDefines.h" +#include "Player.h" +#include "NameTables.h" +#include "CMSGConstructor.h" +#include "DefScript/DefScript.h" + +bool PlayerNameCache::AddInfo(uint64 guid, std::string name){ + PlayerNameCacheItem *cacheItem=new PlayerNameCacheItem; + cacheItem->_name=name; + cacheItem->_guid=guid; + return AddInfo(cacheItem); +} + +bool PlayerNameCache::AddInfo(PlayerNameCacheItem* cacheItem){ + for(std::vector::iterator i=_cache.begin(); i!=_cache.end(); i++) + if(cacheItem->_guid==(*i)->_guid) + return false; + _cache.push_back(cacheItem); + return true; +} + +std::string PlayerNameCache::GetName(uint64 guid){ + for(std::vector::iterator i=_cache.begin(); i!=_cache.end(); i++) + if(guid==(*i)->_guid) + return (*i)->_name; + return ""; +} + +uint64 PlayerNameCache::GetGuid(std::string name){ + for(std::vector::iterator i=_cache.begin(); i!=_cache.end(); i++) + if(name==(*i)->_name) + return (*i)->_guid; + return 0; +} + +bool PlayerNameCache::SaveToFile(void){ + printf("Saving PlayerNameCache...\n"); + char *fn="./cache/playernames.cache"; + std::fstream fh; + fh.open(fn, std::ios_base::out | std::ios_base::binary); + if(!fh) + { + printf("ERROR: could not open file '%s'!\n",fn); + return false; + } + uint32 size=_cache.size(); + if(size==0) + return false; + uint8 len; + fh.write((char*)&size,sizeof(uint32)); + + for(std::vector::iterator i=_cache.begin(); i!=_cache.end(); i++) + { + fh.write( (char*)&((*i)->_guid),sizeof(uint64) ); + len=(*i)->_name.length(); + fh.write( (char*)&len,sizeof(uint8) ); + fh.write( (char*)(*i)->_name.c_str(),len ); + DEB(printf( "PlayerNameCache << " I64FMT " -> %s\n", (*i)->_guid, (*i)->_name.c_str());); + } + fh.close(); + printf("PlayerNameCache saved successfully.\n"); + return true; +} + +bool PlayerNameCache::ReadFromFile(void){ + char *fn="./cache/playernames.cache"; + printf("Loading PlayerNameCache...\n"); + bool success=true; + std::fstream fh; + fh.open(fn, std::ios_base::in | std::ios_base::binary); + if(!fh) + { + printf("ERROR: could not open file '%s'!\n",fn); + return false; + } + uint32 size; + fh.read((char*)&size,sizeof(uint32)); + std::string tmp; + uint8 len; + char *nameptr=new char[13]; + for(unsigned int i=0;i_guid),sizeof(uint64)); + fh.read((char*)&len,sizeof(uint8)); + if(len>12 || len<2){ + printf("\nERROR: PlayerNameCache data seem corrupt [namelength=%d, should be <=12}]\n",len); + printf("-> Clearing cache, creating new.\n"); + _cache.clear(); + success=false; + break; + } + fh.read(nameptr,len); + cacheItem->_name=nameptr; + AddInfo(cacheItem); + printf("\rPlayerNameCache [ %u / %u ] items loaded",i+1,size); + DEB(printf( " >> " I64FMT " -> %s\n", cacheItem->_guid, nameptr);); + } + printf("\n"); + delete nameptr; + fh.close(); + if(success) + printf("PlayerNameCache successfully loaded.\n"); + return success; +} + +uint32 PlayerNameCache::GetSize(void){ + return _cache.size(); +} diff --git a/src/Client/World/Player.h b/src/Client/World/Player.h new file mode 100644 index 0000000..b03052f --- /dev/null +++ b/src/Client/World/Player.h @@ -0,0 +1,69 @@ +#ifndef _PLAYER_H +#define _PLAYER_H + +#include + +struct PlayerNameCacheItem { + uint64 _guid; + std::string _name; +}; + +class PlayerNameCache { +public: + std::string GetName(uint64); + uint64 GetGuid(std::string); + bool AddInfo(uint64 guid, std::string name); + bool AddInfo(PlayerNameCacheItem*); + bool SaveToFile(void); + bool ReadFromFile(void); + uint32 GetSize(void); +private: + std::vector _cache; +}; + +class PlayerEnum { +public: + uint64 _guid; + std::string _name; + uint8 _race; + uint8 _class; + uint8 _gender; + uint8 _bytes1; + uint8 _bytes2; + uint8 _bytes3; + uint8 _bytes4; + uint8 _bytesx; + uint8 _level; + uint32 _zoneId; + uint32 _mapId; + float _x; + float _y; + float _z; + uint32 _guildId; + uint8 _flags; + uint32 _petInfoId; + uint32 _petLevel; + uint32 _petFamilyId; +// more to come...[items] + +private: + + +}; +/* +class PlayerCache { +public: + void Add(Player*); + void Remove(Player*); + void Remove(uint64); + uint32 GetCount(void) { return _players.size(); } + +private: + std::vector _players; + +}; +*/ + + + +#endif \ No newline at end of file diff --git a/src/Client/World/SharedDefines.h b/src/Client/World/SharedDefines.h new file mode 100644 index 0000000..4bf26cb --- /dev/null +++ b/src/Client/World/SharedDefines.h @@ -0,0 +1,991 @@ +/* + * Copyright (C) 2005,2006 MaNGOS + * + * 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 MANGOS_SHAREDDEFINES_H +#define MANGOS_SHAREDDEFINES_H + +#define GENDER_MALE 0 +#define GENDER_FEMALE 1 +#define GENDER_NONE 2 + +#define RACE_HUMAN 1 +#define RACE_ORC 2 +#define RACE_DWARF 3 +#define RACE_NIGHT_ELF 4 +#define RACE_UNDEAD 5 +#define RACE_TAUREN 6 +#define RACE_GNOME 7 +#define RACE_TROLL 8 + +#define CLASS_WARRIOR 1 +#define CLASS_PALADIN 2 +#define CLASS_HUNTER 3 +#define CLASS_ROGUE 4 +#define CLASS_PRIEST 5 +#define CLASS_UNK1 6 +#define CLASS_SHAMAN 7 +#define CLASS_MAGE 8 +#define CLASS_WARLOCK 9 +#define CLASS_UNK2 10 +#define CLASS_DRUID 11 + +enum Stats +{ + STAT_STRENGTH = 0, + STAT_AGILITY = 1, + STAT_STAMINA = 2, + STAT_INTELLECT = 3, + STAT_SPIRIT = 4 +}; + +enum Powers +{ + POWER_MANA = 0, + POWER_RAGE = 1, + POWER_FOCUS = 2, + POWER_ENERGY = 3, + POWER_HAPPINESS = 4 +}; + +enum SpellSchools +{ + SPELL_SCHOOL_NORMAL = 0, + SPELL_SCHOOL_HOLY = 1, + SPELL_SCHOOL_FIRE = 2, + SPELL_SCHOOL_NATURE = 3, + SPELL_SCHOOL_FROST = 4, + SPELL_SCHOOL_SHADOW = 5, + SPELL_SCHOOL_ARCANE = 6 +}; + +#define ITEM_QUALITY_POOR 0 //GREY +#define ITEM_QUALITY_NORMAL 1 //WHITE +#define ITEM_QUALITY_UNCOMMON 2 //GREEN +#define ITEM_QUALITY_RARE 3 //BLUE +#define ITEM_QUALITY_EPIC 4 //PURPLE +#define ITEM_QUALITY_LEGENDARY 5 //ORANGE +#define ITEM_QUALITY_ARTIFACT 6 //LIGHT YELLOW + +#define SHEATHETYPE_NONE 0 +#define SHEATHETYPE_MAINHAND 1 +#define SHEATHETYPE_OFFHAND 2 +#define SHEATHETYPE_LARGEWEAPONLEFT 3 +#define SHEATHETYPE_LARGEWEAPONRIGHT 4 +#define SHEATHETYPE_HIPWEAPONLEFT 5 +#define SHEATHETYPE_HIPWEAPONRIGHT 6 +#define SHEATHETYPE_SHIELD 7 + +#define SLOT_HEAD 0 +#define SLOT_NECK 1 +#define SLOT_SHOULDERS 2 +#define SLOT_SHIRT 3 +#define SLOT_CHEST 4 +#define SLOT_WAIST 5 +#define SLOT_LEGS 6 +#define SLOT_FEET 7 +#define SLOT_WRISTS 8 +#define SLOT_HANDS 9 +#define SLOT_FINGER1 10 +#define SLOT_FINGER2 11 +#define SLOT_TRINKET1 12 +#define SLOT_TRINKET2 13 +#define SLOT_BACK 14 +#define SLOT_MAIN_HAND 15 +#define SLOT_OFF_HAND 16 +#define SLOT_RANGED 17 +#define SLOT_TABARD 18 +#define SLOT_EMPTY 19 + +#define LANG_GLOBAL 0 +#define LANG_UNIVERSAL 0 +#define LANG_ORCISH 1 +#define LANG_DARNASSIAN 2 +#define LANG_TAURAHE 3 +#define LANG_DWARVISH 6 +#define LANG_COMMON 7 +#define LANG_DEMONIC 8 +#define LANG_TITAN 9 +#define LANG_THELASSIAN 10 +#define LANG_DRACONIC 11 +#define LANG_KALIMAG 12 +#define LANG_GNOMISH 13 +#define LANG_TROLL 14 +#define LANG_GUTTERSPEAK 33 + +// Spell Effects + +#define SPELL_EFFECT_INSTAKILL 1 +#define SPELL_EFFECT_SCHOOL_DAMAGE 2 +#define SPELL_EFFECT_DUMMY 3 +#define SPELL_EFFECT_PORTAL_TELEPORT 4 +#define SPELL_EFFECT_TELEPORT_UNITS 5 +#define SPELL_EFFECT_APPLY_AURA 6 +#define SPELL_EFFECT_ENVIRONMENTAL_DAMAGE 7 +#define SPELL_EFFECT_MANA_DRAIN 8 +#define SPELL_EFFECT_HEALTH_LEECH 9 +#define SPELL_EFFECT_HEAL 10 +#define SPELL_EFFECT_BIND 11 +#define SPELL_EFFECT_PORTAL 12 +#define SPELL_EFFECT_RITUAL_BASE 13 +#define SPELL_EFFECT_RITUAL_SPECIALIZE 14 +#define SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL 15 +#define SPELL_EFFECT_QUEST_COMPLETE 16 +#define SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL 17 +#define SPELL_EFFECT_RESURRECT 18 +#define SPELL_EFFECT_ADD_EXTRA_ATTACKS 19 +#define SPELL_EFFECT_DODGE 20 +#define SPELL_EFFECT_EVADE 21 +#define SPELL_EFFECT_PARRY 22 +#define SPELL_EFFECT_BLOCK 23 +#define SPELL_EFFECT_CREATE_ITEM 24 +#define SPELL_EFFECT_WEAPON 25 +#define SPELL_EFFECT_DEFENSE 26 +#define SPELL_EFFECT_PERSISTENT_AREA_AURA 27 +#define SPELL_EFFECT_SUMMON 28 +#define SPELL_EFFECT_LEAP 29 +#define SPELL_EFFECT_ENERGIZE 30 +#define SPELL_EFFECT_WEAPON_PERCENT_DAMAGE 31 +#define SPELL_EFFECT_TRIGGER_MISSILE 32 +#define SPELL_EFFECT_OPEN_LOCK 33 +#define SPELL_EFFECT_SUMMON_CHANGE_ITEM 34 +#define SPELL_EFFECT_APPLY_AREA_AURA 35 +#define SPELL_EFFECT_LEARN_SPELL 36 +#define SPELL_EFFECT_SPELL_DEFENSE 37 +#define SPELL_EFFECT_DISPEL 38 +#define SPELL_EFFECT_LANGUAGE 39 +#define SPELL_EFFECT_DUAL_WIELD 40 +#define SPELL_EFFECT_SUMMON_WILD 41 +#define SPELL_EFFECT_SUMMON_GUARDIAN 42 +#define SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER 43 +#define SPELL_EFFECT_SKILL_STEP 44 +#define SPELL_EFFECT_UNDEFINED_45 45 +#define SPELL_EFFECT_SPAWN 46 +#define SPELL_EFFECT_TRADE_SKILL 47 +#define SPELL_EFFECT_STEALTH 48 +#define SPELL_EFFECT_DETECT 49 +//#define SPELL_EFFECT_SUMMON_OBJECT 50 +#define SPELL_EFFECT_TRANS_DOOR 50 +#define SPELL_EFFECT_FORCE_CRITICAL_HIT 51 +#define SPELL_EFFECT_GUARANTEE_HIT 52 +#define SPELL_EFFECT_ENCHANT_ITEM 53 +#define SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY 54 +#define SPELL_EFFECT_TAMECREATURE 55 +#define SPELL_EFFECT_SUMMON_PET 56 +#define SPELL_EFFECT_LEARN_PET_SPELL 57 +#define SPELL_EFFECT_WEAPON_DAMAGE 58 +#define SPELL_EFFECT_OPEN_LOCK_ITEM 59 +#define SPELL_EFFECT_PROFICIENCY 60 +#define SPELL_EFFECT_SEND_EVENT 61 +#define SPELL_EFFECT_POWER_BURN 62 +#define SPELL_EFFECT_THREAT 63 +#define SPELL_EFFECT_TRIGGER_SPELL 64 +#define SPELL_EFFECT_HEALTH_FUNNEL 65 +#define SPELL_EFFECT_POWER_FUNNEL 66 +#define SPELL_EFFECT_HEAL_MAX_HEALTH 67 +#define SPELL_EFFECT_INTERRUPT_CAST 68 +#define SPELL_EFFECT_DISTRACT 69 +#define SPELL_EFFECT_PULL 70 +#define SPELL_EFFECT_PICKPOCKET 71 +#define SPELL_EFFECT_ADD_FARSIGHT 72 +#define SPELL_EFFECT_SUMMON_POSSESSED 73 +#define SPELL_EFFECT_SUMMON_TOTEM 74 +#define SPELL_EFFECT_HEAL_MECHANICAL 75 +#define SPELL_EFFECT_SUMMON_OBJECT_WILD 76 +#define SPELL_EFFECT_SCRIPT_EFFECT 77 +#define SPELL_EFFECT_ATTACK 78 +#define SPELL_EFFECT_SANCTUARY 79 +#define SPELL_EFFECT_ADD_COMBO_POINTS 80 +#define SPELL_EFFECT_CREATE_HOUSE 81 +#define SPELL_EFFECT_BIND_SIGHT 82 +#define SPELL_EFFECT_DUEL 83 +#define SPELL_EFFECT_STUCK 84 +#define SPELL_EFFECT_SUMMON_PLAYER 85 +#define SPELL_EFFECT_ACTIVATE_OBJECT 86 +#define SPELL_EFFECT_SUMMON_TOTEM_SLOT1 87 +#define SPELL_EFFECT_SUMMON_TOTEM_SLOT2 88 +#define SPELL_EFFECT_SUMMON_TOTEM_SLOT3 89 +#define SPELL_EFFECT_SUMMON_TOTEM_SLOT4 90 +#define SPELL_EFFECT_THREAT_ALL 91 +#define SPELL_EFFECT_ENCHANT_HELD_ITEM 92 +#define SPELL_EFFECT_SUMMON_PHANTASM 93 +#define SPELL_EFFECT_SELF_RESURRECT 94 +#define SPELL_EFFECT_SKINNING 95 +#define SPELL_EFFECT_CHARGE 96 +#define SPELL_EFFECT_SUMMON_CRITTER 97 +#define SPELL_EFFECT_KNOCK_BACK 98 +#define SPELL_EFFECT_DISENCHANT 99 +#define SPELL_EFFECT_INEBRIATE 100 +#define SPELL_EFFECT_FEED_PET 101 +#define SPELL_EFFECT_DISMISS_PET 102 +#define SPELL_EFFECT_REPUTATION 103 +#define SPELL_EFFECT_SUMMON_OBJECT_SLOT1 104 +#define SPELL_EFFECT_SUMMON_OBJECT_SLOT2 105 +#define SPELL_EFFECT_SUMMON_OBJECT_SLOT3 106 +#define SPELL_EFFECT_SUMMON_OBJECT_SLOT4 107 +#define SPELL_EFFECT_DISPEL_MECHANIC 108 +#define SPELL_EFFECT_SUMMON_DEAD_PET 109 +#define SPELL_EFFECT_DESTROY_ALL_TOTEMS 110 +#define SPELL_EFFECT_DURABILITY_DAMAGE 111 +#define SPELL_EFFECT_SUMMON_DEMON 112 +#define SPELL_EFFECT_RESURRECT_NEW 113 +#define SPELL_EFFECT_ATTACK_ME 114 +#define SPELL_EFFECT_DURABILITY_DAMAGE_PCT 115 +#define SPELL_EFFECT_SKIN_PLAYER_CORPSE 116 +#define SPELL_EFFECT_SPIRIT_HEAL 117 +#define SPELL_EFFECT_SKILL 118 +#define SPELL_EFFECT_APPLY_AURA_NEW 119 +#define SPELL_EFFECT_TELEPORT_GRAVEYARD 120 +#define SPELL_EFFECT_NORMALIZED_WEAPON_DMG 121 +#define TOTAL_SPELL_EFFECTS 122 + +#define STATE_STANDING 0 +#define STATE_SITTING 1 +#define STATE_SITTINGCHAIR 2 +#define STATE_SLEEPING 3 +#define STATE_SITTINGCHAIRLOW 4 +#define STATE_SITTINGCHAIRMEDIUM 5 +#define STATE_SITTINGCHAIRHIGH 6 +#define STATE_DEAD 7 +#define STATE_KNEEL 8 + +#define GAMEOBJECT_TYPE_DOOR 0 +#define GAMEOBJECT_TYPE_BUTTON 1 +#define GAMEOBJECT_TYPE_QUESTGIVER 2 +#define GAMEOBJECT_TYPE_CHEST 3 +#define GAMEOBJECT_TYPE_BINDER 4 +#define GAMEOBJECT_TYPE_GENERIC 5 +#define GAMEOBJECT_TYPE_TRAP 6 +#define GAMEOBJECT_TYPE_CHAIR 7 +#define GAMEOBJECT_TYPE_SPELL_FOCUS 8 +#define GAMEOBJECT_TYPE_TEXT 9 +#define GAMEOBJECT_TYPE_GOOBER 10 +#define GAMEOBJECT_TYPE_TRANSPORT 11 +#define GAMEOBJECT_TYPE_AREADAMAGE 12 +#define GAMEOBJECT_TYPE_CAMERA 13 +#define GAMEOBJECT_TYPE_MAP_OBJECT 14 +#define GAMEOBJECT_TYPE_MO_TRANSPORT 15 +#define GAMEOBJECT_TYPE_DUEL_ARBITER 16 +#define GAMEOBJECT_TYPE_FISHINGNODE 17 +#define GAMEOBJECT_TYPE_RITUAL 18 +#define GAMEOBJECT_TYPE_MAILBOX 19 +#define GAMEOBJECT_TYPE_AUCTIONHOUSE 20 +#define GAMEOBJECT_TYPE_GUARDPOST 21 +#define GAMEOBJECT_TYPE_SPELLCASTER 22 +#define GAMEOBJECT_TYPE_MEETINGSTONE 23 +#define GAMEOBJECT_TYPE_FLAGSTAND 24 +#define GAMEOBJECT_TYPE_FISHINGHOLE 25 +#define GAMEOBJECT_TYPE_FLAGDROP 26 +// Custom gametypes, can create problems at sending to client +#define GAMEOBJECT_TYPE_CUSTOM_TELEPORTER 27 + +#define TEXTEMOTE_AGREE 1 +#define TEXTEMOTE_AMAZE 2 +#define TEXTEMOTE_ANGRY 3 +#define TEXTEMOTE_APOLOGIZE 4 +#define TEXTEMOTE_APPLAUD 5 +#define TEXTEMOTE_BASHFUL 6 +#define TEXTEMOTE_BECKON 7 +#define TEXTEMOTE_BEG 8 +#define TEXTEMOTE_BITE 9 +#define TEXTEMOTE_BLEED 10 +#define TEXTEMOTE_BLINK 11 +#define TEXTEMOTE_BLUSH 12 +#define TEXTEMOTE_BONK 13 +#define TEXTEMOTE_BORED 14 +#define TEXTEMOTE_BOUNCE 15 +#define TEXTEMOTE_BRB 16 +#define TEXTEMOTE_BOW 17 +#define TEXTEMOTE_BURP 18 +#define TEXTEMOTE_BYE 19 +#define TEXTEMOTE_CACKLE 20 +#define TEXTEMOTE_CHEER 21 +#define TEXTEMOTE_CHICKEN 22 +#define TEXTEMOTE_CHUCKLE 23 +#define TEXTEMOTE_CLAP 24 +#define TEXTEMOTE_CONFUSED 25 +#define TEXTEMOTE_CONGRATULATE 26 +#define TEXTEMOTE_COUGH 27 +#define TEXTEMOTE_COWER 28 +#define TEXTEMOTE_CRACK 29 +#define TEXTEMOTE_CRINGE 30 +#define TEXTEMOTE_CRY 31 +#define TEXTEMOTE_CURIOUS 32 +#define TEXTEMOTE_CURTSEY 33 +#define TEXTEMOTE_DANCE 34 +#define TEXTEMOTE_DRINK 35 +#define TEXTEMOTE_DROOL 36 +#define TEXTEMOTE_EAT 37 +#define TEXTEMOTE_EYE 38 +#define TEXTEMOTE_FART 39 +#define TEXTEMOTE_FIDGET 40 +#define TEXTEMOTE_FLEX 41 +#define TEXTEMOTE_FROWN 42 +#define TEXTEMOTE_GASP 43 +#define TEXTEMOTE_GAZE 44 +#define TEXTEMOTE_GIGGLE 45 +#define TEXTEMOTE_GLARE 46 +#define TEXTEMOTE_GLOAT 47 +#define TEXTEMOTE_GREET 48 +#define TEXTEMOTE_GRIN 49 +#define TEXTEMOTE_GROAN 50 +#define TEXTEMOTE_GROVEL 51 +#define TEXTEMOTE_GUFFAW 52 +#define TEXTEMOTE_HAIL 53 +#define TEXTEMOTE_HAPPY 54 +#define TEXTEMOTE_HELLO 55 +#define TEXTEMOTE_HUG 56 +#define TEXTEMOTE_HUNGRY 57 +#define TEXTEMOTE_KISS 58 +#define TEXTEMOTE_KNEEL 59 +#define TEXTEMOTE_LAUGH 60 +#define TEXTEMOTE_LAYDOWN 61 +#define TEXTEMOTE_MESSAGE 62 +#define TEXTEMOTE_MOAN 63 +#define TEXTEMOTE_MOON 64 +#define TEXTEMOTE_MOURN 65 +#define TEXTEMOTE_NO 66 +#define TEXTEMOTE_NOD 67 +#define TEXTEMOTE_NOSEPICK 68 +#define TEXTEMOTE_PANIC 69 +#define TEXTEMOTE_PEER 70 +#define TEXTEMOTE_PLEAD 71 +#define TEXTEMOTE_POINT 72 +#define TEXTEMOTE_POKE 73 +#define TEXTEMOTE_PRAY 74 +#define TEXTEMOTE_ROAR 75 +#define TEXTEMOTE_ROFL 76 +#define TEXTEMOTE_RUDE 77 +#define TEXTEMOTE_SALUTE 78 +#define TEXTEMOTE_SCRATCH 79 +#define TEXTEMOTE_SEXY 80 +#define TEXTEMOTE_SHAKE 81 +#define TEXTEMOTE_SHOUT 82 +#define TEXTEMOTE_SHRUG 83 +#define TEXTEMOTE_SHY 84 +#define TEXTEMOTE_SIGH 85 +#define TEXTEMOTE_SIT 86 +#define TEXTEMOTE_SLEEP 87 +#define TEXTEMOTE_SNARL 88 +#define TEXTEMOTE_SPIT 89 +#define TEXTEMOTE_STARE 90 +#define TEXTEMOTE_SURPRISED 91 +#define TEXTEMOTE_SURRENDER 92 +#define TEXTEMOTE_TALK 93 +#define TEXTEMOTE_TALKEX 94 +#define TEXTEMOTE_TALKQ 95 +#define TEXTEMOTE_TAP 96 +#define TEXTEMOTE_THANK 97 +#define TEXTEMOTE_THREATEN 98 +#define TEXTEMOTE_TIRED 99 +#define TEXTEMOTE_VICTORY 100 +#define TEXTEMOTE_WAVE 101 +#define TEXTEMOTE_WELCOME 102 +#define TEXTEMOTE_WHINE 103 +#define TEXTEMOTE_WHISTLE 104 +#define TEXTEMOTE_WORK 105 +#define TEXTEMOTE_YAWN 106 +#define TEXTEMOTE_BOGGLE 107 +#define TEXTEMOTE_CALM 108 +#define TEXTEMOTE_COLD 109 +#define TEXTEMOTE_COMFORT 110 +#define TEXTEMOTE_CUDDLE 111 +#define TEXTEMOTE_DUCK 112 +#define TEXTEMOTE_INSULT 113 +#define TEXTEMOTE_INTRODUCE 114 +#define TEXTEMOTE_JK 115 +#define TEXTEMOTE_LICK 116 +#define TEXTEMOTE_LISTEN 117 +#define TEXTEMOTE_LOST 118 +#define TEXTEMOTE_MOCK 119 +#define TEXTEMOTE_PONDER 120 +#define TEXTEMOTE_POUNCE 121 +#define TEXTEMOTE_PRAISE 122 +#define TEXTEMOTE_PURR 123 +#define TEXTEMOTE_PUZZLE 124 +#define TEXTEMOTE_RAISE 125 +#define TEXTEMOTE_READY 126 +#define TEXTEMOTE_SHIMMY 127 +#define TEXTEMOTE_SHIVER 128 +#define TEXTEMOTE_SHOO 129 +#define TEXTEMOTE_SLAP 130 +#define TEXTEMOTE_SMIRK 131 +#define TEXTEMOTE_SNIFF 132 +#define TEXTEMOTE_SNUB 133 +#define TEXTEMOTE_SOOTHE 134 +#define TEXTEMOTE_STINK 135 +#define TEXTEMOTE_TAUNT 136 +#define TEXTEMOTE_TEASE 137 +#define TEXTEMOTE_THIRSTY 138 +#define TEXTEMOTE_VETO 139 +#define TEXTEMOTE_SNICKER 140 +#define TEXTEMOTE_STAND 141 +#define TEXTEMOTE_TICKLE 142 +#define TEXTEMOTE_VIOLIN 143 +#define TEXTEMOTE_SMILE 163 +#define TEXTEMOTE_RASP 183 +#define TEXTEMOTE_PITY 203 +#define TEXTEMOTE_GROWL 204 +#define TEXTEMOTE_BARK 205 +#define TEXTEMOTE_SCARED 223 +#define TEXTEMOTE_FLOP 224 +#define TEXTEMOTE_LOVE 225 +#define TEXTEMOTE_MOO 226 +#define TEXTEMOTE_COMMEND 243 +#define TEXTEMOTE_JOKE 329 + +#define EMOTE_ONESHOT_NONE 0 +#define EMOTE_ONESHOT_TALK 1 +#define EMOTE_ONESHOT_BOW 2 +#define EMOTE_ONESHOT_WAVE 3 +#define EMOTE_ONESHOT_CHEER 4 +#define EMOTE_ONESHOT_EXCLAMATION 5 +#define EMOTE_ONESHOT_QUESTION 6 +#define EMOTE_ONESHOT_EAT 7 +#define EMOTE_STATE_DANCE 10 +#define EMOTE_ONESHOT_LAUGH 11 +#define EMOTE_STATE_SLEEP 12 +#define EMOTE_STATE_SIT 13 +#define EMOTE_ONESHOT_RUDE 14 +#define EMOTE_ONESHOT_ROAR 15 +#define EMOTE_ONESHOT_KNEEL 16 +#define EMOTE_ONESHOT_KISS 17 +#define EMOTE_ONESHOT_CRY 18 +#define EMOTE_ONESHOT_CHICKEN 19 +#define EMOTE_ONESHOT_BEG 20 +#define EMOTE_ONESHOT_APPLAUD 21 +#define EMOTE_ONESHOT_SHOUT 22 +#define EMOTE_ONESHOT_FLEX 23 +#define EMOTE_ONESHOT_SHY 24 +#define EMOTE_ONESHOT_POINT 25 +#define EMOTE_STATE_STAND 26 +#define EMOTE_STATE_READYUNARMED 27 +#define EMOTE_STATE_WORK 28 +#define EMOTE_STATE_POINT 29 +#define EMOTE_STATE_NONE 30 +#define EMOTE_ONESHOT_WOUND 33 +#define EMOTE_ONESHOT_WOUNDCRITICAL 34 +#define EMOTE_ONESHOT_ATTACKUNARMED 35 +#define EMOTE_ONESHOT_ATTACK1H 36 +#define EMOTE_ONESHOT_ATTACK2HTIGHT 37 +#define EMOTE_ONESHOT_ATTACK2HLOOSE 38 +#define EMOTE_ONESHOT_PARRYUNARMED 39 +#define EMOTE_ONESHOT_PARRYSHIELD 43 +#define EMOTE_ONESHOT_READYUNARMED 44 +#define EMOTE_ONESHOT_READY1H 45 +#define EMOTE_ONESHOT_READYBOW 48 +#define EMOTE_ONESHOT_SPELLPRECAST 50 +#define EMOTE_ONESHOT_SPELLCAST 51 +#define EMOTE_ONESHOT_BATTLEROAR 53 +#define EMOTE_ONESHOT_SPECIALATTACK1H 54 +#define EMOTE_ONESHOT_KICK 60 +#define EMOTE_ONESHOT_ATTACKTHROWN 61 +#define EMOTE_STATE_STUN 64 +#define EMOTE_STATE_DEAD 65 +#define EMOTE_ONESHOT_SALUTE 66 +#define EMOTE_STATE_KNEEL 68 +#define EMOTE_STATE_USESTANDING 69 +#define EMOTE_ONESHOT_WAVE_NOSHEATHE 70 +#define EMOTE_ONESHOT_CHEER_NOSHEATHE 71 +#define EMOTE_ONESHOT_EAT_NOSHEATHE 92 +#define EMOTE_STATE_STUN_NOSHEATHE 93 +#define EMOTE_ONESHOT_DANCE 94 +#define EMOTE_ONESHOT_SALUTE_NOSHEATH 113 +#define EMOTE_STATE_USESTANDING_NOSHEATHE 133 +#define EMOTE_ONESHOT_LAUGH_NOSHEATHE 153 +#define EMOTE_STATE_WORK_NOSHEATHE 173 +#define EMOTE_STATE_SPELLPRECAST 193 +#define EMOTE_ONESHOT_READYRIFLE 213 +#define EMOTE_STATE_READYRIFLE 214 +#define EMOTE_STATE_WORK_NOSHEATHE_MINING 233 +#define EMOTE_STATE_WORK_NOSHEATHE_CHOPWOOD 234 +#define EMOTE_zzOLDONESHOT_LIFTOFF 253 +#define EMOTE_ONESHOT_LIFTOFF 254 +#define EMOTE_ONESHOT_YES 273 +#define EMOTE_ONESHOT_NO 274 +#define EMOTE_ONESHOT_TRAIN 275 +#define EMOTE_ONESHOT_LAND 293 +#define EMOTE_STATE_READY1H 333 +#define EMOTE_STATE_AT_EASE 313 +#define EMOTE_STATE_SPELLKNEELSTART 353 +#define EMOTE_STATE_SUBMERGED 373 +#define EMOTE_ONESHOT_SUBMERGE 374 + +#define ANIM_STAND 0x0 +#define ANIM_DEATH 0x1 +#define ANIM_SPELL 0x2 +#define ANIM_STOP 0x3 +#define ANIM_WALK 0x4 +#define ANIM_RUN 0x5 +#define ANIM_DEAD 0x6 +#define ANIM_RISE 0x7 +#define ANIM_STANDWOUND 0x8 +#define ANIM_COMBATWOUND 0x9 +#define ANIM_COMBATCRITICAL 0xA +#define ANIM_SHUFFLE_LEFT 0xB +#define ANIM_SHUFFLE_RIGHT 0xC +#define ANIM_WALK_BACKWARDS 0xD +#define ANIM_STUN 0xE +#define ANIM_HANDS_CLOSED 0xF +#define ANIM_ATTACKUNARMED 0x10 +#define ANIM_ATTACK1H 0x11 +#define ANIM_ATTACK2HTIGHT 0x12 +#define ANIM_ATTACK2HLOOSE 0x13 +#define ANIM_PARRYUNARMED 0x14 +#define ANIM_PARRY1H 0x15 +#define ANIM_PARRY2HTIGHT 0x16 +#define ANIM_PARRY2HLOOSE 0x17 +#define ANIM_PARRYSHIELD 0x18 +#define ANIM_READYUNARMED 0x19 +#define ANIM_READY1H 0x1A +#define ANIM_READY2HTIGHT 0x1B +#define ANIM_READY2HLOOSE 0x1C +#define ANIM_READYBOW 0x1D +#define ANIM_DODGE 0x1E +#define ANIM_SPELLPRECAST 0x1F +#define ANIM_SPELLCAST 0x20 +#define ANIM_SPELLCASTAREA 0x21 +#define ANIM_NPCWELCOME 0x22 +#define ANIM_NPCGOODBYE 0x23 +#define ANIM_BLOCK 0x24 +#define ANIM_JUMPSTART 0x25 +#define ANIM_JUMP 0x26 +#define ANIM_JUMPEND 0x27 +#define ANIM_FALL 0x28 +#define ANIM_SWIMIDLE 0x29 +#define ANIM_SWIM 0x2A +#define ANIM_SWIM_LEFT 0x2B +#define ANIM_SWIM_RIGHT 0x2C +#define ANIM_SWIM_BACKWARDS 0x2D +#define ANIM_ATTACKBOW 0x2E +#define ANIM_FIREBOW 0x2F +#define ANIM_READYRIFLE 0x30 +#define ANIM_ATTACKRIFLE 0x31 +#define ANIM_LOOT 0x32 +#define ANIM_SPELL_PRECAST_DIRECTED 0x33 +#define ANIM_SPELL_PRECAST_OMNI 0x34 +#define ANIM_SPELL_CAST_DIRECTED 0x35 +#define ANIM_SPELL_CAST_OMNI 0x36 +#define ANIM_SPELL_BATTLEROAR 0x37 +#define ANIM_SPELL_READYABILITY 0x38 +#define ANIM_SPELL_SPECIAL1H 0x39 +#define ANIM_SPELL_SPECIAL2H 0x3A +#define ANIM_SPELL_SHIELDBASH 0x3B +#define ANIM_EMOTE_TALK 0x3C +#define ANIM_EMOTE_EAT 0x3D +#define ANIM_EMOTE_WORK 0x3E +#define ANIM_EMOTE_USE_STANDING 0x3F +#define ANIM_EMOTE_EXCLAMATION 0x40 +#define ANIM_EMOTE_QUESTION 0x41 +#define ANIM_EMOTE_BOW 0x42 +#define ANIM_EMOTE_WAVE 0x43 +#define ANIM_EMOTE_CHEER 0x44 +#define ANIM_EMOTE_DANCE 0x45 +#define ANIM_EMOTE_LAUGH 0x46 +#define ANIM_EMOTE_SLEEP 0x47 +#define ANIM_EMOTE_SIT_GROUND 0x48 +#define ANIM_EMOTE_RUDE 0x49 +#define ANIM_EMOTE_ROAR 0x4A +#define ANIM_EMOTE_KNEEL 0x4B +#define ANIM_EMOTE_KISS 0x4C +#define ANIM_EMOTE_CRY 0x4D +#define ANIM_EMOTE_CHICKEN 0x4E +#define ANIM_EMOTE_BEG 0x4F +#define ANIM_EMOTE_APPLAUD 0x50 +#define ANIM_EMOTE_SHOUT 0x51 +#define ANIM_EMOTE_FLEX 0x52 +#define ANIM_EMOTE_SHY 0x53 +#define ANIM_EMOTE_POINT 0x54 +#define ANIM_ATTACK1HPIERCE 0x55 +#define ANIM_ATTACK2HLOOSEPIERCE 0x56 +#define ANIM_ATTACKOFF 0x57 +#define ANIM_ATTACKOFFPIERCE 0x58 +#define ANIM_SHEATHE 0x59 +#define ANIM_HIPSHEATHE 0x5A +#define ANIM_MOUNT 0x5B +#define ANIM_RUN_LEANRIGHT 0x5C +#define ANIM_RUN_LEANLEFT 0x5D +#define ANIM_MOUNT_SPECIAL 0x5E +#define ANIM_KICK 0x5F +#define ANIM_SITDOWN 0x60 +#define ANIM_SITTING 0x61 +#define ANIM_SITUP 0x62 +#define ANIM_SLEEPDOWN 0x63 +#define ANIM_SLEEPING 0x64 +#define ANIM_SLEEPUP 0x65 +#define ANIM_SITCHAIRLOW 0x66 +#define ANIM_SITCHAIRMEDIUM 0x67 +#define ANIM_SITCHAIRHIGH 0x68 +#define ANIM_LOADBOW 0x69 +#define ANIM_LOADRIFLE 0x6A +#define ANIM_ATTACKTHROWN 0x6B +#define ANIM_READYTHROWN 0x6C +#define ANIM_HOLDBOW 0x6D +#define ANIM_HOLDRIFLE 0x6E +#define ANIM_HOLDTHROWN 0x6F +#define ANIM_LOADTHROWN 0x70 +#define ANIM_EMOTE_SALUTE 0x71 +#define ANIM_KNEELDOWN 0x72 +#define ANIM_KNEELING 0x73 +#define ANIM_KNEELUP 0x74 +#define ANIM_ATTACKUNARMEDOFF 0x75 +#define ANIM_SPECIALUNARMED 0x76 +#define ANIM_STEALTHWALK 0x77 +#define ANIM_STEALTHSTAND 0x78 +#define ANIM_KNOCKDOWN 0x79 +#define ANIM_EATING 0x7A +#define ANIM_USESTANDINGLOOP 0x7B +#define ANIM_CHANNELCASTDIRECTED 0x7C +#define ANIM_CHANNELCASTOMNI 0x7D +#define ANIM_WHIRLWIND 0x7E +#define ANIM_BIRTH 0x7F +#define ANIM_USESTANDINGSTART 0x80 +#define ANIM_USESTANDINGEND 0x81 +#define ANIM_HOWL 0x82 +#define ANIM_DROWN 0x83 +#define ANIM_DROWNED 0x84 +#define ANIM_FISHINGCAST 0x85 +#define ANIM_FISHINGLOOP 0x86 + +#define FIRST_GAMEOBJECTANIMATION 0x87 +#define ANIM_GAMEOBJ_STAND 0 +#define ANIM_GAMEOBJ_CLOSED 1 +#define ANIM_GAMEOBJ_OPEN 2 +#define ANIM_GAMEOBJ_OPENED 3 +#define ANIM_GAMEOBJ_CLOSE 4 +#define ANIM_GAMEOBJ_DESTROY 5 +#define ANIM_GAMEOBJ_DESTROYED 6 +#define ANIM_GAMEOBJ_REBUILD 7 +#define ANIM_GAMEOBJ_CUSTOM0 8 +#define ANIM_GAMEOBJ_CUSTOM1 9 +#define ANIM_GAMEOBJ_CUSTOM2 10 +#define ANIM_GAMEOBJ_CUSTOM3 11 + +#define FIRST_EFFECTANIMATION 0x93 +#define ANIM_EFFECT_STAND 0 +#define ANIM_EFFECT_HOLD 1 +#define ANIM_EFFECT_DECAY 2 + +#define FIRST_ITEMANIMATION 0x96 +#define ANIM_ITEM_STAND 0 +#define ANIM_ITEM_INFLIGHT 1 +#define ANIM_ITEM_BOWPULL 2 +#define ANIM_ITEM_BOWRELEASE 3 + +#define LOCKTYPE_PICKLOCK 1 +#define LOCKTYPE_HERBALISM 2 +#define LOCKTYPE_MINING 3 +#define LOCKTYPE_DISARM_TRAP 4 +#define LOCKTYPE_OPEN 5 +#define LOCKTYPE_TREASURE 6 +#define LOCKTYPE_CALCIFIED_ELVEN_GEMS 7 +#define LOCKTYPE_CLOSE 8 +#define LOCKTYPE_ARM_TRAP 9 +#define LOCKTYPE_QUICK_OPEN 10 +#define LOCKTYPE_QUICK_CLOSE 11 +#define LOCKTYPE_OPEN_TINKERING 12 +#define LOCKTYPE_OPEN_KNEELING 13 +#define LOCKTYPE_OPEN_ATTACKING 14 +#define LOCKTYPE_GAHZRIDIAN 15 +#define LOCKTYPE_BLASTING 16 +#define LOCKTYPE_SLOW_OPEN 17 +#define LOCKTYPE_SLOW_CLOSE 18 + +#define TRAINER_TYPE_CLASS 0 +#define TRAINER_TYPE_MOUNTS 1 +#define TRAINER_TYPE_TRADESKILLS 2 +#define TRAINER_TYPE_PETS 3 + +#define SHAPESHIFT_FORM_CAT 1 +#define SHAPESHIFT_FORM_TREE 2 +#define SHAPESHIFT_FORM_TRAVEL 3 +#define SHAPESHIFT_FORM_AQUATIC 4 +#define SHAPESHIFT_FORM_BEAR 5 +#define SHAPESHIFT_AMBIENT 6 +#define SHAPESHIFT_GHOUL 7 +#define SHAPESHIFT_FORM_DIRE_BEAR 8 +#define SHAPESHIFT_CREATURE_BEAR 14 +#define SHAPESHIFT_GHOST_WOLF 16 +#define SHAPESHIFT_BATTLE_STANCE 17 +#define SHAPESHIFT_DEFENSIVE_STANCE 18 +#define SHAPESHIFT_BERSERKER_STANCE 19 +#define SHAPESHIFT_FORM_SHADOW 28 +#define SHAPESHIFT_STEALTH 30 +#define SHAPESHIFT_MOONKIN 31 + +#define CREATURE_TYPE_BEAST 1 +#define CREATURE_TYPE_DRAGON 2 +#define CREATURE_TYPE_DEMON 3 +#define CREATURE_TYPE_ELEMENTAL 4 +#define CREATURE_TYPE_GIANT 5 +#define CREATURE_TYPE_UNDEAD 6 +#define CREATURE_TYPE_HUMANOID 7 +#define CREATURE_TYPE_CRITTER 8 +#define CREATURE_TYPE_MECHANICAL 9 +#define CREATURE_TYPE_UNKNOWN 10 + +#define CREATURE_FAMILY_WOLF 1 +#define CREATURE_FAMILY_CAT 2 +#define CREATURE_FAMILY_SPIDER 3 +#define CREATURE_FAMILY_BEAR 4 +#define CREATURE_FAMILY_BOAR 5 +#define CREATURE_FAMILY_CROCILISK 6 +#define CREATURE_FAMILY_CARRION_BIRD 7 +#define CREATURE_FAMILY_CRAB 8 +#define CREATURE_FAMILY_GORILLA 9 +#define CREATURE_FAMILY_RAPTOR 11 +#define CREATURE_FAMILY_TALLSTRIDER 12 +#define CREATURE_FAMILY_FELHUNTER 15 +#define CREATURE_FAMILY_VOIDWALKER 16 +#define CREATURE_FAMILY_SUCCUBUS 17 +#define CREATURE_FAMILY_DOOMGUARD 19 +#define CREATURE_FAMILY_SCORPID 20 +#define CREATURE_FAMILY_TURTLE 21 +#define CREATURE_FAMILY_IMP 23 +#define CREATURE_FAMILY_BAT 24 +#define CREATURE_FAMILY_HYENA 25 +#define CREATURE_FAMILY_OWL 26 +#define CREATURE_FAMILY_WIND_SERPENT 27 + +#define CREATURE_ELITE_NORMAL 0 +#define CREATURE_ELITE_ELITE 1 +#define CREATURE_ELITE_RAREELITE 2 +#define CREATURE_ELITE_WORLDBOSS 3 +#define CREATURE_ELITE_RARE 4 + +#define QUEST_TYPE_ELITE 1 +#define QUEST_TYPE_LIFE 21 +#define QUEST_TYPE_PVP 41 +#define QUEST_TYPE_RAID 62 +#define QUEST_TYPE_DUNGEON 81 + +#define QUEST_SORT_EPIC 1 +#define QUEST_SORT_WAILING_CAVERNS_OLD 21 +#define QUEST_SORT_SEASONAL 22 +#define QUEST_SORT_UNDERCITY_OLD 23 +#define QUEST_SORT_HERBALISM 24 +#define QUEST_SORT_SCARLET_MONASTERY_OLD 25 +#define QUEST_SORT_ULDAMN_OLD 41 +#define QUEST_SORT_WARLOCK 61 +#define QUEST_SORT_WARRIOR 81 +#define QUEST_SORT_SHAMAN 82 +#define QUEST_SORT_FISHING 101 +#define QUEST_SORT_BLACKSMITHING 121 +#define QUEST_SORT_PALADIN 141 +#define QUEST_SORT_MAGE 161 +#define QUEST_SORT_ROGUE 162 +#define QUEST_SORT_ALCHEMY 181 +#define QUEST_SORT_LEATHERWORKING 182 +#define QUEST_SORT_ENGINERING 201 +#define QUEST_SORT_TREASURE_MAP 221 +#define QUEST_SORT_SUNKEN_TEMPLE_OLD 241 +#define QUEST_SORT_HUNTER 261 +#define QUEST_SORT_PRIEST 262 +#define QUEST_SORT_DRUID 263 +#define QUEST_SORT_TAILORING 264 +#define QUEST_SORT_SPECIAL 284 +#define QUEST_SORT_COOKING 304 +#define QUEST_SORT_FIRST_AID 324 + +#define SKILL_FROST 6 +#define SKILL_FIRE 8 +#define SKILL_ARMS 26 +#define SKILL_COMBAT 38 +#define SKILL_SUBTLETY 39 +#define SKILL_POISONS 40 +#define SKILL_SWORDS 43 +#define SKILL_AXES 44 +#define SKILL_BOWS 45 +#define SKILL_GUNS 46 +#define SKILL_BEAST_MASTERY 50 +#define SKILL_SURVIVAL 51 +#define SKILL_MACES 54 +#define SKILL_HOLY 56 +#define SKILL_2H_SWORDS 55 +#define SKILL_SHADOW 78 +#define SKILL_DEFENSE 95 +#define SKILL_LANG_COMMON 98 +#define SKILL_RACIAL_DWARVEN 101 +#define SKILL_LANG_ORCISH 109 +#define SKILL_LANG_DWARVEN 111 +#define SKILL_LANG_DARNASSIAN 113 +#define SKILL_LANG_TAURAHE 115 +#define SKILL_DUAL_WIELD 118 +#define SKILL_RACIAL_TAUREN 124 +#define SKILL_ORC_RACIAL 125 +#define SKILL_RACIAL_NIGHT_ELF 126 +#define SKILL_FIRST_AID 129 +#define SKILL_FERAL_COMBAT 134 +#define SKILL_LANG_THALASSIAN 137 +#define SKILL_STAVES 136 +#define SKILL_LANG_DRACONIC 138 +#define SKILL_LANG_DEMON_TONGUE 139 +#define SKILL_LANG_TITAN 140 +#define SKILL_LANG_OLD_TONGUE 141 +#define SKILL_SURVIVAL2 142 +#define SKILL_RIDING_HORSE 148 +#define SKILL_RIDING_WOLF 149 +#define SKILL_RIDING_RAM 152 +#define SKILL_RIDING_TIGER 150 +#define SKILL_SWIMING 155 +#define SKILL_2H_MACES 160 +#define SKILL_UNARMED 162 +#define SKILL_MARKSMANSHIP 163 +#define SKILL_BLACKSMITHING 164 +#define SKILL_LEATHERWORKING 165 +#define SKILL_ALCHEMY 171 +#define SKILL_2H_AXES 172 +#define SKILL_DAGGERS 173 +#define SKILL_THROWN 176 +#define SKILL_HERBALISM 182 +#define SKILL_GENERIC_DND 183 +#define SKILL_RETRIBUTION 184 +#define SKILL_COOKING 185 +#define SKILL_MINING 186 +#define SKILL_PET_IMP 188 +#define SKILL_PET_FELHUNTER 189 +#define SKILL_TAILORING 197 +#define SKILL_ENGINERING 202 +#define SKILL_PET_SPIDER 203 +#define SKILL_PET_VOIDWALKER 204 +#define SKILL_PET_SUCCUBUS 205 +#define SKILL_PET_INFERNAL 206 +#define SKILL_PET_DOOMGUARD 207 +#define SKILL_PET_WOLF 208 +#define SKILL_PET_CAT 209 +#define SKILL_PET_BEAR 210 +#define SKILL_PET_BOAR 211 +#define SKILL_PET_CROCILISK 212 +#define SKILL_PET_CARRION_BIRD 213 +#define SKILL_PET_GORILLA 215 +#define SKILL_PET_CRAB 214 +#define SKILL_PET_RAPTOR 217 +#define SKILL_PET_TALLSTRIDER 218 +#define SKILL_RACIAL_UNDED 220 +#define SKILL_WEAPON_TALENTS 222 +#define SKILL_CROSSBOWS 226 +#define SKILL_SPEARS 227 +#define SKILL_WANDS 228 +#define SKILL_POLEARMS 229 +#define SKILL_ATTRIBUTE_ENCHANCEMENTS 230 +#define SKILL_SLAYER_TALENTS 231 +#define SKILL_MAGIC_TALENTS 233 +#define SKILL_DEFENSIVE_TALENTS 234 +#define SKILL_PET_SCORPID 236 +#define SKILL_ARCANE 237 +#define SKILL_OPEN_LOCK 242 +#define SKILL_PET_TURTLE 251 +#define SKILL_FURY 256 +#define SKILL_PROTECTION 257 +#define SKILL_BEAST_TRAINING 261 +#define SKILL_PROTECTION2 267 +#define SKILL_PET_TALENTS 270 +#define SKILL_PLATE_MAIL 293 +#define SKILL_ASSASSINATION 253 +#define SKILL_LANG_GNOMISH 313 +#define SKILL_LANG_TROLL 315 +#define SKILL_ENCHANTING 333 +#define SKILL_DEMONOLOGY 354 +#define SKILL_AFFLICTION 355 +#define SKILL_FISHING 356 +#define SKILL_ENHANCEMENT 373 +#define SKILL_RESTORATION 374 +#define SKILL_ELEMENTAL_COMBAT 375 +#define SKILL_SKINNING 393 +#define SKILL_LEATHER 414 +#define SKILL_CLOTH 415 +#define SKILL_MAIL 413 +#define SKILL_SHIELD 433 +#define SKILL_FIST_WEAPONS 473 +#define SKILL_TRACKING_BEAST 513 +#define SKILL_TRACKING_HUMANOID 514 +#define SKILL_TRACKING_DEMON 516 +#define SKILL_TRACKING_UNDEAD 517 +#define SKILL_TRACKING_DRAGON 518 +#define SKILL_TRACKING_ELEMENTAL 519 +#define SKILL_RIDING_RAPTOR 533 +#define SKILL_RIDING_MECHANOSTRIDER 553 +#define SKILL_RIDING_UNDEAD_HORSE 554 +#define SKILL_RESTORATION2 573 +#define SKILL_BALANCE 574 +#define SKILL_DESTRUCTION 593 +#define SKILL_HOLY2 594 +#define SKILL_DISCIPLINE 613 +#define SKILL_LOCKPICKING 633 +#define SKILL_PET_BAT 653 +#define SKILL_PET_HYENA 654 +#define SKILL_PET_OWL 655 +#define SKILL_PET_WIND_SERPENT 656 +#define SKILL_LANG_GUTTERSPEAK 673 +#define SKILL_RIDING_KODO 713 +#define SKILL_RACIAL_TROLL 733 +#define SKILL_RACIAL_GNOME 753 +#define SKILL_RACIAL_HUMAN 754 + +#define UNIT_DYNFLAG_LOOTABLE 0x0001 + +#define UNIT_DYNFLAG_TRACK_UNIT 0x0002 + +#define UNIT_DYNFLAG_OTHER_TAGGER 0x0004 + +#define UNIT_DYNFLAG_ROOTED 0x0008 + +#define UNIT_DYNFLAG_SPECIALINFO 0x0010 + +#define UNIT_DYNFLAG_DEAD 0x0020 + +#define UNIT_FLAG_NOT_ATTACKABLE 0x0002 + +#define UNIT_FLAG_ATTACKABLE 0x0008 + +#define UNIT_FLAG_NOT_ATTACKABLE_1 0x0080 + +#define UNIT_FLAG_NON_PVP_PLAYER (UNIT_FLAG_ATTACKABLE + UNIT_FLAG_NOT_ATTACKABLE_1) + +#define UNIT_FLAG_ANIMATION_FROZEN 0x0400 +#define UNIT_FLAG_WAR_PLAYER 0x1000 + +enum ChatMsg +{ + CHAT_MSG_SAY = 0x00, + CHAT_MSG_PARTY = 0x01, + CHAT_MSG_RAID = 0x02, + CHAT_MSG_GUILD = 0x03, + CHAT_MSG_OFFICER = 0x04, + CHAT_MSG_YELL = 0x05, + CHAT_MSG_WHISPER = 0x06, + CHAT_MSG_WHISPER_INFORM = 0x07, + CHAT_MSG_EMOTE = 0x08, + CHAT_MSG_TEXT_EMOTE = 0x09, + CHAT_MSG_SYSTEM = 0x0A, + CHAT_MSG_MONSTER_SAY = 0x0B, + CHAT_MSG_MONSTER_YELL = 0x0C, + CHAT_MSG_MONSTER_EMOTE = 0x0D, + CHAT_MSG_CHANNEL = 0x0E, + CHAT_MSG_CHANNEL_JOIN = 0x0F, + CHAT_MSG_CHANNEL_LEAVE = 0x10, + CHAT_MSG_CHANNEL_LIST = 0x11, + CHAT_MSG_CHANNEL_NOTICE = 0x12, + CHAT_MSG_CHANNEL_NOTICE_USER = 0x13, + CHAT_MSG_AFK = 0x14, + CHAT_MSG_DND = 0x15, + CHAT_MSG_IGNORED = 0x16, + CHAT_MSG_SKILL = 0x17, + CHAT_MSG_LOOT = 0x18, +}; + +#endif diff --git a/src/Client/World/WorldPacket.cpp b/src/Client/World/WorldPacket.cpp new file mode 100644 index 0000000..3929752 --- /dev/null +++ b/src/Client/World/WorldPacket.cpp @@ -0,0 +1,19 @@ + +#include "WorldPacket.h" + + +uint64 WorldPacket::GetPackedGuid(void) +{ + uint8 mask; + *this >> mask; + uint64 guid=0; + for(uint8 i=0;i<8;i++) + { + if(mask & (1<> ((uint8*)&guid)[i]; + } + } + return guid; +} + diff --git a/src/Client/World/WorldPacket.h b/src/Client/World/WorldPacket.h new file mode 100644 index 0000000..e52cea1 --- /dev/null +++ b/src/Client/World/WorldPacket.h @@ -0,0 +1,25 @@ +#ifndef _WORLDPACKET_H +#define _WORLDPACKET_H + +#include "SysDefs.h" +#include "Auth/ByteBuffer.h" + +class WorldPacket : public ByteBuffer +{ +public: + WorldPacket() { ByteBuffer(10); _opcode=0; } + WorldPacket(uint32 r) { reserve(r); _opcode=0; } + WorldPacket(uint16 opcode, uint32 r) { _opcode=opcode; reserve(r); } + WorldPacket(uint16 opcode) { _opcode=opcode; reserve(10); } + inline void SetOpcode(uint16 opcode) { _opcode=opcode; } + inline uint16 GetOpcode(void) { return _opcode; } + uint64 GetPackedGuid(void); + ~WorldPacket(); + +private: + uint16 _opcode; + +}; + + +#endif \ No newline at end of file diff --git a/src/Client/World/WorldPacketHandler.cpp_ b/src/Client/World/WorldPacketHandler.cpp_ new file mode 100644 index 0000000..859c171 --- /dev/null +++ b/src/Client/World/WorldPacketHandler.cpp_ @@ -0,0 +1,463 @@ +#include +#include +#include "zlib/zlib.h" +#include "common.h" +#include "PseuWoW.h" +#include "Auth/AuthCrypt.h" +#include "../shared/CircularBuffer.h" // to have the Buf data structure +#include "../shared/SDLTCPConnection.h" +#include "Auth/ByteBuffer.h" +#include "Auth/BigNumber.h" +#include "Auth/Sha1.h" +#include "Opcodes.h" +#include "WorldPacketHandler.h" +#include "SharedDefines.h" +#include "Player.h" +#include "NameTables.h" +#include "CMSGConstructor.h" +#include "DefScript/DefScript.h" + + +struct ClientPktHeader +{ + uint16 size; + uint16 cmd; + uint16 nil; +}; + +struct ServerPktHeader +{ + uint16 size; + uint16 cmd; +}; + +AuthCrypt _crypt; +BigNumber sessionkey; + +uint8 GetCompressedGuidSize(uint8 mask){ + uint8 size=0; + for(unsigned int i=0;i<8;i++){ + if(mask>>i){ + size++; + } + } + return size; +} + +uint64 DecompressGuid(uint8 *z, uint8 mask){ + uint64 guid=0; + for(uint8 i=0;i<8;i++){ + if(mask>>i){ + ((uint8*)&guid)[i]=*z; + z++; + } + } + return guid; +} + + +void SendWorldPacket(uint16 opcode, ByteBuffer *pkt){ + ClientPktHeader hdr={0,0,0}; + ByteBuffer buf; + if(pkt!=NULL)buf.append(*pkt); + hdr.cmd=opcode; + hdr.size=ntohs(buf.size()+4); + _crypt.EncryptSend((uint8*)&hdr, 6); + ByteBuffer final; + final.append((uint8*)&hdr,6); + if(buf.size()){ + final.append(buf); + } + worldCon.Send((char*)final.contents(), final.size()); +} + + +void HandleWorldPacket(ByteBuffer pkt){ + + static uint16 _last_cmd,_last_remaining; + static bool _last_pkt_wrong; + ServerPktHeader hdr; + uint16 _remaining, _cmd; + ByteBuffer wdata; + pkt >> hdr.size >> hdr.cmd; + _crypt.DecryptRecv((uint8*)&hdr, 4); + _remaining=ntohs(hdr.size)-2; + _cmd=hdr.cmd; + //DEBUG3(printf("DECRYPT: rest=%d, opcode=%d\n",_remaining,_cmd);) + if(_cmd>800){ + DEBUG3(printf("Recieved weird opcode [%u] pktsize=%u remaining=%u(corrupted header?)\n",_cmd,pkt.size(),_remaining);) + DEBUG3(pkt.hexlike();) + //if(pkt.size()==_last_remaining){ + // DEBUG3(printf("Trying to attach packet to last recieved opcode [%s], size=%u\n",LookupName(_last_cmd,g_worldOpcodeNames),_last_remaining);) + // wdata.append(pkt.contents(),_last_remaining); + // HandleOpcode(_last_cmd,wdata); // lets hope it wont crash :/ + //} else + //DEBUG1(printf("Packet rescue failed, dropping. size=%u opcode=%u\n",_remaining,_cmd);) + + return; + } + else + if(pkt.size()>4 && _remaining+4==pkt.size()){ + DEBUG3(printf("Rcvd pkt hdr is too big (%u)! Assuming {header+data}, opcode=%d [%s]\n",pkt.size(),_cmd,LookupName(_cmd,g_worldOpcodeNames));) + wdata.append(&pkt.contents()[4],4); + //wdata.hexlike(); + _last_cmd=_cmd; + _last_remaining=_remaining; + HandleOpcode(_cmd,wdata); + + } else { + if(!_remaining){ + ByteBuffer dummy; + HandleOpcode(_cmd,dummy); + } + if(_remaining){ + ByteBuffer content; + content.append(worldCon.GetDataString()); // fetch the next packet + content.resize(content.size()-1); // remove the \0 + if(content.size()<_remaining ){ // packet is smaller then expected + //content.hexlike(); + DEBUG3(printf("Packet was smaller then expected! (expected: %u, recvd: %u)\n",_remaining,content.size());) + //if(content.size()==_last_remaining){ + // DEBUG3(printf("Trying to attach packet to last recieved opcode [%s], size=%u\n",LookupName(_last_cmd,g_worldOpcodeNames),_last_remaining);) + // wdata.append(pkt.contents(),_last_remaining); + // HandleOpcode(_last_cmd,wdata); // lets hope it wont crash :/ + // //something_went_wrong=true; + //} else + // printf("Packet rescue failed, dropping. size=%u opcode=%u\n",_remaining,_cmd); + return; + } else { // packet seems ok, use the full packet that came in + //content.hexlike(); + wdata.append(content.contents(),_remaining); + _last_cmd=_cmd; + _last_remaining=_remaining; + HandleOpcode(_cmd,wdata); + } + } + } +} + +void HandleOpcode(uint16 opcode, ByteBuffer &data){ + + //DEBUG3(printf("W: opcode=0x%X | %d , datasize=%d [%s]\n",opcode,opcode,data.size(),LookupName(opcode,g_worldOpcodeNames));) + switch(opcode){ + case SMSG_AUTH_CHALLENGE:{ + std::string acc(strupr(accname)); + uint32 serverseed; + data>>serverseed; + DEBUG3(printf("W:auth: serverseed=0x%X\n",serverseed);) + Sha1Hash digest; + digest.UpdateData(acc); + uint32 unk=0; + digest.UpdateData((uint8*)&unk,sizeof(uint32)); + BigNumber clientseed; + clientseed.SetRand(8*4); + unsigned int clientseed_uint32=clientseed.AsDword(); + digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32)); + digest.UpdateData((uint8*)&serverseed,sizeof(uint32)); + digest.UpdateBigNumbers(&sessionkey,NULL); + digest.Finalize(); + ByteBuffer outpkt; + outpkt<<(uint32)clientbuild<> num; + if(num==0){ + printf("W:No chars found!\n"); + something_went_wrong=true; + return; + } + printf("W: Chars in list: %u\n",num); + for(unsigned int i=0;i> plr[i]._guid; + data >> plr[i]._name; + data >> plr[i]._race; + data >> plr[i]._class; + data >> plr[i]._gender; + data >> plr[i]._bytes1; + data >> plr[i]._bytes2; + data >> plr[i]._bytes3; + data >> plr[i]._bytes4; + data >> plr[i]._bytesx; + data >> plr[i]._level; + data >> plr[i]._zoneId; + data >> plr[i]._mapId; + data >> plr[i]._x; + data >> plr[i]._y; + data >> plr[i]._z; + data >> plr[i]._guildId; + data >> dummy8; + data >> plr[i]._flags; + data >> dummy8 >> dummy8 >> dummy8; + data >> plr[i]._petInfoId; + data >> plr[i]._petLevel; + data >> plr[i]._petFamilyId; + for(unsigned int inv=0;inv<20;inv++){ + data >> dummy32 >> dummy8; // item data are not relevant yet ( (uint32)itemID , (uint8)inventorytype ) + } + plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); + } + bool char_found=false; + uint64 login_guid; + for(unsigned int i=0;i coords: map=%u zone=%u x=%f y=%f z=%f\n", + plr[i]._mapId,plr[i]._zoneId,plr[i]._x,plr[i]._y,plr[i]._z);) + if(plr[i]._name==charname){ + char_found=true; + login_guid=plr[i]._guid; + } + + } + if(!char_found){ + printf("W: Character \"%s\" was not found on char list!\n",charname.c_str()); + something_went_wrong=true; + return; + } else { + printf("W: Entering World with Character \"%s\"...\n",charname.c_str()); + ByteBuffer pkt; + pkt << login_guid; + _myGUID=login_guid; + _targetGUID=0; + SendWorldPacket(CMSG_PLAYER_LOGIN,&pkt); + } + + + + }break; + + case SMSG_ACCOUNT_DATA_MD5: + case SMSG_SET_PROFICIENCY: + case SMSG_CAST_RESULT: + case SMSG_LOGIN_SETTIMESPEED: //those opcodes are sent on login + { + if(!inworld){ + inworld=true; + defScp.RunScriptByName("_enterworld",NULL,255); + } + // o_O + } break; + + case SMSG_MESSAGECHAT:{ + uint8 type=0; + uint32 lang=0; + uint64 target_guid=0; + uint32 msglen=0; + std::string msg,ext; + bool isCmd=false; + + data >> type >> lang; + + if (type == CHAT_MSG_CHANNEL) + data >> ext; // extract channel name + + data >> target_guid; + std::string plrname; + if(target_guid){ + plrname=plrNameCache.GetName(target_guid); + if(plrname.empty()) + { + QueryPlayerName(target_guid); + plrname="Unknown Entity"; + } + } + defScp.variables.Set("@lastmsg_name",defScp.variables.Get("@thismsg_name")); + defScp.variables.Set("@lastmsg",defScp.variables.Get("@lastmsg")); + defScp.variables.Set("@thismsg_name",plrname); + defScp.variables.Set("@thismsg",toString(target_guid)); + + + if(type == CHAT_MSG_SAY || type == CHAT_MSG_YELL || type == CHAT_MSG_PARTY) + data >> target_guid; + + data >> msglen >> msg; + if (type == CHAT_MSG_SYSTEM){ + printf("W:SYSMSG: \"%s\"\n",msg.c_str()); + } else if (type==CHAT_MSG_WHISPER ){ + printf("W:WHISP: %s [%s]: %s\n",plrname.c_str(),LookupName(lang,langNames),msg.c_str()); + } else { + printf("W:CHAT: %s [%s]: %s\n",plrname.c_str(),LookupName(lang,langNames),msg.c_str()); + } + + if(target_guid!=_myGUID && msg.length()>1 && msg.at(0)=='-') + isCmd=true; + + // some fun code :P + if(type==CHAT_MSG_SAY && target_guid!=_myGUID && !isCmd) + { + if(msg=="lol") + SendChatMessage(CHAT_MSG_SAY,lang,"say \"lol\" if you have nothing else to say... lol xD",""); + else if(msg.length()>4 && msg.find("you?")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,std::string(ver).append(" -- i am a bot, made by False.Genesis, my master."),""); + else if(msg=="hi") + SendChatMessage(CHAT_MSG_SAY,lang,"Hi, wadup?",""); + else if(msg.length()<12 && msg.find("wtf")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,"Yeah, WTF is a good way to say you dont understand anything... :P",""); + else if(msg.length()<15 && (msg.find("omg")!=std::string::npos || msg.find("omfg")!=std::string::npos) ) + SendChatMessage(CHAT_MSG_SAY,lang,"OMG a bot logged in, you don't believe it :O",""); + else if(msg.find("from")!=std::string::npos || msg.find("download")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,"you can dl me from http://my.opera.com/PseuWoW",""); + else if(msg.find("Genesis")!=std::string::npos || msg.find("genesis")!=std::string::npos) + SendChatMessage(CHAT_MSG_YELL,lang,"False.Genesis, they are calling you!! Come here, master xD",""); + } + + if(isCmd){ + defScp.variables.Set("@lastcmd_name",defScp.variables.Get("@thiscmd_name")); + defScp.variables.Set("@lastcmd",defScp.variables.Get("@lastcmd")); + defScp.variables.Set("@thiscmd_name",plrname); + defScp.variables.Set("@thiscmd",toString(target_guid)); + std::string lin=msg.substr(1,msg.length()-1); + uint8 perm=atoi(playerPermissions.Get(plrname).c_str()); + try{ + if(!defScp.RunSingleLine(lin,perm)) + defScp.RunScriptByName("_nopermission",NULL,255); + } catch (...) { + SendChatMessage(CHAT_MSG_SAY,0,"Exception while trying to execute: [ "+lin+" ]",""); + } + + } + if(type==CHAT_MSG_WHISPER && !isCmd){ + defScp.variables.Set("@lastwhisper_name",defScp.variables.Get("@thiswhisper_name")); + defScp.variables.Set("@lastwhisper",defScp.variables.Get("@thiswhisper")); + defScp.variables.Set("@lastwhisper_lang",defScp.variables.Get("@thiswhisper_lang")); + defScp.variables.Set("@thiswhisper_name",plrname); + defScp.variables.Set("@thiswhisper",toString(target_guid)); + defScp.variables.Set("@thiswhisper_lang",toString((uint64)lang)); + defScp.RunScriptByName("_onwhisper",NULL,255); + } + + + + } break; + + case SMSG_MONSTER_MOVE:{ + // register moving mobs, etc + } break; + + case SMSG_STOP_MIRROR_TIMER:{ + // mangos spams u with that if you are dead (bug) + } break; + + case SMSG_NAME_QUERY_RESPONSE:{ + uint64 pguid; + std::string pname; + data >> pguid >> pname; + if(pname.length()>12 || pname.length()<2) + break; // playernames maxlen=12 + // rest of the packet is not interesting for now + if(plrNameCache.AddInfo(pguid,pname)) + { + printf("CACHE: Assigned new player name: '%s'",pname.c_str()); + SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.",""); + DEBUG2(printf(" to guid "I64FMTD,pguid);); + printf("\n"); + } + + } break; + + case MSG_MOVE_SET_FACING: + case MSG_MOVE_START_FORWARD: + case MSG_MOVE_START_BACKWARD: + case MSG_MOVE_STOP: + case MSG_MOVE_START_STRAFE_LEFT: + case MSG_MOVE_START_STRAFE_RIGHT: + case MSG_MOVE_STOP_STRAFE: + case MSG_MOVE_JUMP: + case MSG_MOVE_START_TURN_LEFT: + case MSG_MOVE_START_TURN_RIGHT: + case MSG_MOVE_STOP_TURN: + case MSG_MOVE_START_SWIM: + case MSG_MOVE_STOP_SWIM: + case MSG_MOVE_HEARTBEAT: + case MSG_MOVE_FALL_LAND: + { + uint32 flags, time; + float x, y, z, o; + uint64 guid; + uint8 mask,guidlen,*zguid; + std::string plrname; + data >> mask; + guidlen=GetCompressedGuidSize(mask); + zguid=new uint8[guidlen]; + data.read(zguid,guidlen); + guid=DecompressGuid(zguid,mask); + delete zguid; + data >> flags >> time >> x >> y >> z >> o; + if(guid){ + plrname=plrNameCache.GetName(guid); + if(plrname.empty()) + { + QueryPlayerName(guid); + plrname="Unknown Entity"; + } + } + // for follow: + if(_followGUID==guid){ + ByteBuffer bb; + bb << time << flags << x << y << z << o; + SendWorldPacket(opcode,&bb); + } + // more to come + } break; + + case SMSG_PONG:{ + uint32 pong; + data >> pong; + printf("Recieved Ping reply: %u ms latency, including %u ms fetch delay.\n",clock()-pong,idleSleepTime); + } break; + + case SMSG_TRADE_STATUS:{ + data.hexlike(); + uint8 unk; + data >> unk; + if(unk==1){ + SendChatMessage(CHAT_MSG_SAY,0,"It has no sense trying to trade with me, that feature is not yet implemented!",""); + SendWorldPacket(CMSG_CANCEL_TRADE,NULL); + } + } + + case SMSG_GROUP_INVITE:{ + data.hexlike(); + SendWorldPacket(CMSG_GROUP_DECLINE,NULL); + } + + + //... + + default: { + DEBUG1(printf("Recieved unknown opcode=%u [%s] pktlen=%u\n",opcode,LookupName(opcode,g_worldOpcodeNames),data.size());); + } break; + + } + +} \ No newline at end of file diff --git a/src/Client/World/WorldPacketHandler.h_ b/src/Client/World/WorldPacketHandler.h_ new file mode 100644 index 0000000..daeb150 --- /dev/null +++ b/src/Client/World/WorldPacketHandler.h_ @@ -0,0 +1,10 @@ +#ifndef _WORLDPACKETHANDLER_H +#define _WORLDPACKETHANDLER_H + +#include +#include "Auth/ByteBuffer.h" +void HandleWorldPacket(ByteBuffer); +void HandleOpcode(uint16,ByteBuffer&); +void SendWorldPacket(uint16, ByteBuffer*); + +#endif \ No newline at end of file diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp new file mode 100644 index 0000000..0a92c46 --- /dev/null +++ b/src/Client/World/WorldSession.cpp @@ -0,0 +1,457 @@ +#include "common.h" + +#include "Auth/Sha1.h" +#include "Auth/BigNumber.h" +#include "Auth/AuthCrypt.h" +#include "Opcodes.h" +#include "WorldPacket.h" +#include "WorldSocket.h" +#include "WorldSession.h" +#include "NameTables.h" + + +struct ClientPktHeader +{ + uint16 size; + uint16 cmd; + uint16 nil; +}; + +struct ServerPktHeader +{ + uint16 size; + uint16 cmd; +}; + + +WorldSession::WorldSession(PseuInstance *in) +{ + _instance = in; + _valid=_authed=_logged=false; + _socket=new WorldSocket(_sh,this); + _sh.Add(_socket); + _targetGUID=0; // no target + _followGUID=0; // dont follow anything + plrNameCache.ReadFromFile(); // load names/guids of known players + //... +} + +WorldSession::~WorldSession() +{ + delete _socket; +} + +void WorldSession::AddToDataQueue(uint8 *data, uint32 len) +{ + for (uint32 i=0;iSendBuf((char*)final.contents(),final.size()); +} + +void WorldSession::Update(void) +{ + WorldPacket packet; + OpcodeHandler *table = _GetOpcodeHandlerTable(); + while(pktQueue.size()>5) + { + packet = BuildWorldPacket(); + + for (uint16 i = 0; table[i].handler != NULL; i++) + if (table[i].opcode == packet.GetOpcode()) + (this->*table[i].handler)(packet); + + packet.clear(); + } + // do more stuff here +} + +WorldPacket WorldSession::BuildWorldPacket(void) +{ + ServerPktHeader hdr; + WorldPacket wp; + uint16 _remaining; + for (uint8 i=0;iGetScripts()->RunScriptByName("_enterworld",NULL,255); + } +} + + + +/////////////////////////////////////////////////////////////// +// Opcode Handlers +/////////////////////////////////////////////////////////////// + +void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket) +{ + std::string acc = stringToUpper(GetInstance()->GetConf()->accname); + uint32 serverseed; + recvPacket >> serverseed; + //DEBUG3(printf("W:auth: serverseed=0x%X\n",serverseed);) + Sha1Hash digest; + digest.UpdateData(acc); + uint32 unk=0; + digest.UpdateData((uint8*)&unk,sizeof(uint32)); + BigNumber clientseed; + clientseed.SetRand(8*4); + uint32 clientseed_uint32=clientseed.AsDword(); + digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32)); + digest.UpdateData((uint8*)&serverseed,sizeof(uint32)); + digest.UpdateBigNumbers(&(GetInstance()->GetSessionKey()),NULL); + digest.Finalize(); + WorldPacket auth; + auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<> num; + if(num==0){ + printf("W:No chars found!\n"); + GetInstance()->Stop(); + return; + } + printf("W: Chars in list: %u\n",num); + for(unsigned int i=0;i> plr[i]._guid; + recvPacket >> plr[i]._name; + recvPacket >> plr[i]._race; + recvPacket >> plr[i]._class; + recvPacket >> plr[i]._gender; + recvPacket >> plr[i]._bytes1; + recvPacket >> plr[i]._bytes2; + recvPacket >> plr[i]._bytes3; + recvPacket >> plr[i]._bytes4; + recvPacket >> plr[i]._bytesx; + recvPacket >> plr[i]._level; + recvPacket >> plr[i]._zoneId; + recvPacket >> plr[i]._mapId; + recvPacket >> plr[i]._x; + recvPacket >> plr[i]._y; + recvPacket >> plr[i]._z; + recvPacket >> plr[i]._guildId; + recvPacket >> dummy8; + recvPacket >> plr[i]._flags; + recvPacket >> dummy8 >> dummy8 >> dummy8; + recvPacket >> plr[i]._petInfoId; + recvPacket >> plr[i]._petLevel; + recvPacket >> plr[i]._petFamilyId; + for(unsigned int inv=0;inv<20;inv++){ + recvPacket >> dummy32 >> dummy8; // item data are not relevant yet ( (uint32)itemID , (uint8)inventorytype ) + } + plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); + } + bool char_found=false; + for(unsigned int i=0;i coords: map=%u zone=%u x=%f y=%f z=%f\n", + // plr[i]._mapId,plr[i]._zoneId,plr[i]._x,plr[i]._y,plr[i]._z);) + if(plr[i]._name==GetInstance()->GetConf()->charname){ + char_found=true; + _myGUID=plr[i]._guid; + } + + } + if(!char_found){ + printf("W: Character \"%s\" was not found on char list!\n",GetInstance()->GetConf()->charname.c_str()); + GetInstance()->Stop(); + return; + } else { + printf("W: Entering World with Character \"%s\"...\n",GetInstance()->GetConf()->charname.c_str()); + WorldPacket pkt; + pkt.SetOpcode(CMSG_PLAYER_LOGIN); + pkt << _myGUID; + _targetGUID=0; + _followGUID=0; + SendWorldPacket(pkt); + } +} + + +void WorldSession::_HandleSetProficiencyOpcode(WorldPacket& recvPacket) +{ + OnEnterWorld(); +} + +void WorldSession::_HandleAccountDataMD5Opcode(WorldPacket& recvPacket) +{ + OnEnterWorld(); +} + +void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) +{ + uint8 type=0; + uint32 lang=0; + uint64 target_guid=0; + uint32 msglen=0; + std::string msg,ext; + bool isCmd=false; + + recvPacket >> type >> lang; + + if (type == CHAT_MSG_CHANNEL) + recvPacket >> ext; // extract channel name + + recvPacket >> target_guid; + std::string plrname; + if(target_guid){ + plrname=plrNameCache.GetName(target_guid); + if(plrname.empty()) + { + SendQueryPlayerName(target_guid); + plrname="Unknown Entity"; + } + } + /*defScp.variables.Set("@lastmsg_name",defScp.variables.Get("@thismsg_name")); + defScp.variables.Set("@lastmsg",defScp.variables.Get("@lastmsg")); + defScp.variables.Set("@thismsg_name",plrname); + defScp.variables.Set("@thismsg",toString(target_guid));*/ + + + if(type == CHAT_MSG_SAY || type == CHAT_MSG_YELL || type == CHAT_MSG_PARTY) + recvPacket >> target_guid; + + recvPacket >> msglen >> msg; + if (type == CHAT_MSG_SYSTEM){ + printf("W:SYSMSG: \"%s\"\n",msg.c_str()); + } else if (type==CHAT_MSG_WHISPER ){ + printf("W:WHISP: %s [%s]: %s\n",plrname.c_str(),LookupName(lang,langNames),msg.c_str()); + } else { + printf("W:CHAT: %s [%s]: %s\n",plrname.c_str(),LookupName(lang,langNames),msg.c_str()); + } + + if(target_guid!=_myGUID && msg.length()>1 && msg.at(0)=='-') + isCmd=true; + + // some fun code :P + if(type==CHAT_MSG_SAY && target_guid!=_myGUID && !isCmd) + { + /*if(msg=="lol") + SendChatMessage(CHAT_MSG_SAY,lang,"say \"lol\" if you have nothing else to say... lol xD",""); + else if(msg.length()>4 && msg.find("you?")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,std::string(ver).append(" -- i am a bot, made by False.Genesis, my master."),""); + else if(msg=="hi") + SendChatMessage(CHAT_MSG_SAY,lang,"Hi, wadup?",""); + else if(msg.length()<12 && msg.find("wtf")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,"Yeah, WTF is a good way to say you dont understand anything... :P",""); + else if(msg.length()<15 && (msg.find("omg")!=std::string::npos || msg.find("omfg")!=std::string::npos) ) + SendChatMessage(CHAT_MSG_SAY,lang,"OMG a bot logged in, you don't believe it :O",""); + else if(msg.find("from")!=std::string::npos || msg.find("download")!=std::string::npos) + SendChatMessage(CHAT_MSG_SAY,lang,"you can dl me from http://my.opera.com/PseuWoW",""); + else if(msg.find("Genesis")!=std::string::npos || msg.find("genesis")!=std::string::npos) + SendChatMessage(CHAT_MSG_YELL,lang,"False.Genesis, they are calling you!! Come here, master xD","");*/ + } + + if(isCmd) + { + /*defScp.variables.Set("@lastcmd_name",defScp.variables.Get("@thiscmd_name")); + defScp.variables.Set("@lastcmd",defScp.variables.Get("@lastcmd")); + defScp.variables.Set("@thiscmd_name",plrname); + defScp.variables.Set("@thiscmd",toString(target_guid)); + std::string lin=msg.substr(1,msg.length()-1); + uint8 perm=atoi(playerPermissions.Get(plrname).c_str()); + try{ + if(!defScp.RunSingleLine(lin,perm)) + defScp.RunScriptByName("_nopermission",NULL,255); + } catch (...) { + SendChatMessage(CHAT_MSG_SAY,0,"Exception while trying to execute: [ "+lin+" ]",""); + }*/ + + } + if(type==CHAT_MSG_WHISPER && !isCmd) + { + /*defScp.variables.Set("@lastwhisper_name",defScp.variables.Get("@thiswhisper_name")); + defScp.variables.Set("@lastwhisper",defScp.variables.Get("@thiswhisper")); + defScp.variables.Set("@lastwhisper_lang",defScp.variables.Get("@thiswhisper_lang")); + defScp.variables.Set("@thiswhisper_name",plrname); + defScp.variables.Set("@thiswhisper",toString(target_guid)); + defScp.variables.Set("@thiswhisper_lang",toString((uint64)lang)); + defScp.RunScriptByName("_onwhisper",NULL,255);*/ + } +} +void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket) +{ + uint64 pguid; + std::string pname; + recvPacket >> pguid >> pname; + if(pname.length()>12 || pname.length()<2) + return; // playernames maxlen=12, minlen=2 + // rest of the packet is not interesting for now + if(plrNameCache.AddInfo(pguid,pname)) + { + printf("CACHE: Assigned new player name: '%s'",pname.c_str()); + SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.",""); + //DEBUG2(printf(" to guid "I64FMTD,pguid);); + printf("\n"); + } +} + +void WorldSession::_HandlePongOpcode(WorldPacket& recvPacket) +{ + uint32 pong; + recvPacket >> pong; + printf("Recieved Ping reply: %u ms latency.\n",clock()-pong); +} +void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket) +{ + recvPacket.hexlike(); + uint8 unk; + recvPacket >> unk; + if(unk==1) + { + SendChatMessage(CHAT_MSG_SAY,0,"It has no sense trying to trade with me, that feature is not yet implemented!",""); + WorldPacket pkt; + pkt.SetOpcode(CMSG_CANCEL_TRADE); + SendWorldPacket(pkt); + } +} + +void WorldSession::_HandleGroupInviteOpcode(WorldPacket& recvPacket) +{ + recvPacket.hexlike(); + WorldPacket pkt; + pkt.SetOpcode(CMSG_GROUP_DECLINE); + SendWorldPacket(pkt); +} + +void WorldSession::_HandleMovementOpcode(WorldPacket& recvPacket) +{ + uint32 flags, time; + float x, y, z, o; + uint64 guid; + std::string plrname; + guid = recvPacket.GetPackedGuid(); + recvPacket >> flags >> time >> x >> y >> z >> o; + if(guid){ + plrname=plrNameCache.GetName(guid); + if(plrname.empty()) + { + SendQueryPlayerName(guid); + plrname="Unknown Entity"; + } + } + // for follow: + //if(_followGUID==guid){ + // ByteBuffer bb; + // bb << time << flags << x << y << z << o; + // SendWorldPacket(opcode,&bb); + //} + // more to come +} \ No newline at end of file diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h new file mode 100644 index 0000000..6d2ca1b --- /dev/null +++ b/src/Client/World/WorldSession.h @@ -0,0 +1,83 @@ +#ifndef _WORLDSESSION_H +#define _WORLDSESSION_H + +#include +#include "PseuWoW.h" +#include "Network/SocketHandler.h" +#include "common.h" +#include "Player.h" +#include "../Auth/AuthCrypt.h" +#include "SharedDefines.h" + +class WorldSocket; +class WorldPacket; + +struct OpcodeHandler +{ + uint16 opcode; + void (WorldSession::*handler)(WorldPacket& recvPacket); +}; + + +class WorldSession +{ +public: + WorldSession(PseuInstance *i); + ~WorldSession(); + void Init(void); + + PseuInstance *GetInstance(void) { return _instance; } + + OpcodeHandler *_GetOpcodeHandlerTable(void) const; + + void AddToDataQueue(uint8*, uint32); + void Connect(std::string addr,uint16 port); + WorldPacket BuildWorldPacket(void); + void Update(void); + void SendWorldPacket(WorldPacket&); + + void SetTarget(uint64 guid); + uint64 GetTarget(void) { return _targetGUID; } + void SetFollowTarget(uint64 guid); + uint64 GetFollowTarget(void) { return _followGUID; } + uint64 GetGuid(void) { return _myGUID; } + + + // CMSGConstructor + void SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to); + void SendQueryPlayerName(uint64 guid); + void SendPing(uint32); + void SendEmote(uint32); + + PlayerNameCache plrNameCache; + +private: + + // Helpers + void OnEnterWorld(void); + + // Opcode Handlers + void _HandleAuthChallengeOpcode(WorldPacket& recvPacket); + void _HandleAuthResponseOpcode(WorldPacket& recvPacket); + void _HandleCharEnumOpcode(WorldPacket& recvPacket); + void _HandleSetProficiencyOpcode(WorldPacket& recvPacket); + void _HandleAccountDataMD5Opcode(WorldPacket& recvPacket); + void _HandleMessageChatOpcode(WorldPacket& recvPacket); + void _HandleNameQueryResponseOpcode(WorldPacket& recvPacket); + void _HandleMovementOpcode(WorldPacket& recvPacket); + void _HandlePongOpcode(WorldPacket& recvPacket); + void _HandleTradeStatusOpcode(WorldPacket& recvPacket); + void _HandleGroupInviteOpcode(WorldPacket& recvPacket); + + + PseuInstance *_instance; + AuthCrypt _crypt; + WorldSocket *_socket; + std::deque pktQueue; + bool _valid,_authed,_logged; // world status + SocketHandler _sh; // handles the WorldSocket + uint64 _targetGUID,_followGUID,_myGUID; + +}; + +#endif \ No newline at end of file diff --git a/src/Client/World/WorldSocket.cpp b/src/Client/World/WorldSocket.cpp new file mode 100644 index 0000000..705e46f --- /dev/null +++ b/src/Client/World/WorldSocket.cpp @@ -0,0 +1,20 @@ + +#include "WorldPacket.h" +#include "WorldSession.h" +#include "WorldSocket.h" + +void WorldSocket::OnConnect() +{ + printf("Connected to world server.\r\n"); +} + +void WorldSocket::OnRead() +{ + TcpSocket::OnRead(); + if(!ibuf.GetLength()) + return; + uint8 *buf=new uint8[ibuf.GetLength()]; + ibuf.Read((char*)buf,ibuf.GetLength()); + GetSession()->AddToDataQueue(buf,ibuf.GetLength()); + delete buf; // UNSURE: delete or delete[] +} diff --git a/src/Client/World/WorldSocket.h b/src/Client/World/WorldSocket.h new file mode 100644 index 0000000..87c5a41 --- /dev/null +++ b/src/Client/World/WorldSocket.h @@ -0,0 +1,23 @@ +#ifndef _WORLDSOCKET_H +#define _WORLDSOCKET_H + +#include "Network/ResolvSocket.h" +#include "SysDefs.h" + +class WorldSession; + +class WorldSocket : public TcpSocket +{ +public: + WorldSocket(SocketHandler &h, WorldSession *s); + WorldSession *GetSession(void) { return _session; } + + void OnRead(); + void OnConnect(); + +private: + WorldSession *_session; + +}; + +#endif \ No newline at end of file diff --git a/src/Client/basics.h_ b/src/Client/basics.h_ new file mode 100644 index 0000000..de71b4d --- /dev/null +++ b/src/Client/basics.h_ @@ -0,0 +1,36 @@ +// --- Defines --- +//... + +// --- Includes --- +#include +#include +#include +#include +#include +#include + +//#include + +#include "../shared/OurDefs.h" +#include "../shared/common.h" +#include "../shared/DebugStuff.h" + +// --- platform stuff --- +#if COMPILER == COMPILER_MICROSOFT + #define I64FMT "%016I64X" + #define I64FMTD "%I64u" + #define SI64FMTD "%I64d" + #define snprintf _snprintf + #define atoll __atoi64 + #define vsnprintf _vsnprintf + #define strdup _strdup +#else + #define stricmp strcasecmp + #define strnicmp strncasecmp + #define I64FMT "%016llX" + #define I64FMTD "%llu" + #define SI64FMTD "%lld" +#endif + + + diff --git a/src/Client/controller.h_ b/src/Client/controller.h_ new file mode 100644 index 0000000..f8b5ec7 --- /dev/null +++ b/src/Client/controller.h_ @@ -0,0 +1,16 @@ +#ifndef CONTROLLER_H +#define CONTROLLER_H + +void c_send(char,char*); +int c_closeconnection(void*); +int c_recieve(void*); +int c_cmdhandler(void*); +int c_create_listener(void*); +void c_quit(void); +void c_init(void); + +extern unsigned int c_port; +extern bool allowcontroller; +extern char *c_password; + +#endif \ No newline at end of file diff --git a/src/Client/doc/Ludmilla_1.8.0_LogonCodes.h.txt b/src/Client/doc/Ludmilla_1.8.0_LogonCodes.h.txt new file mode 100644 index 0000000..80dd28c --- /dev/null +++ b/src/Client/doc/Ludmilla_1.8.0_LogonCodes.h.txt @@ -0,0 +1,61 @@ +//****************************************************************************** +// Here are all codes used in Logon Server. +//============================================================================== +#ifndef _LOGONCODES_H +#define _LOGONCODES_H +//============================================================================== +//#include "OurDefs.h" +//============================================================================== +// wow's codes: +enum EClientCommand +// dumped from wow.exe 1.8.0 +// 0x007F86A8: table of +// +// switch: 005999A7 cmp byte ptr [ecx],dl +{ + CMD_AUTH_LOGON_CHALLENGE = 0x00, // client + CMD_AUTH_LOGON_PROOF = 0x01, // client + CMD_AUTH_RECONNECT_CHALLENGE = 0x02, // client + CMD_AUTH_RECONNECT_PROOF = 0x03, // client + CMD_REALM_LIST = 0x10, // client + CMD_XFER_INITIATE = 0x30, // client? from server + CMD_XFER_DATA = 0x31, // client? from server + CMD_XFER_ACCEPT = 0x32, // not official name, from client + CMD_XFER_RESUME = 0x33, // not official name, from client + CMD_XFER_CANCEL = 0x34, // not official name, from client + + // unknown: + CMD_GRUNT_AUTH_CHALLENGE = 0x00, // server + CMD_GRUNT_AUTH_VERIFY = 0x02, // server + CMD_GRUNT_CONN_PING = 0x10, // server + CMD_GRUNT_CONN_PONG = 0x11, // server + CMD_GRUNT_HELLO = 0x20, // server + CMD_GRUNT_PROVESESSION = 0x21, // server + CMD_GRUNT_KICK = 0x24, // server +}; +//------------------------------------------------------------------------------ +enum ELoginErrorCode + // dumped from wow.exe 1.8.0 + // 00591E9D mov eax,dword ptr [ebp+8] + // eax - code, name in stack after exiting from current funk +{ + // LOGIN_STATE_FAILED: + + LOGIN_FAILED = 1, // 2, B, C, D // "Unable to connect" + LOGIN_BANNED = 3, // "This World of Warcraft account has been closed and is no longer in service -- Please check the registered email address of this account for further information."; -- This is the error message players get when trying to log in with a banned account. + LOGIN_UNKNOWN_ACCOUNT = 4, // 5 // "The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password and account, see www.worldofwarcraft.com for more information."; + LOGIN_ALREADYONLINE = 6, // "This account is already logged into World of Warcraft. Please check the spelling and try again."; + LOGIN_NOTIME = 7, // "You have used up your prepaid time for this account. Please purchase more to continue playing"; + LOGIN_DBBUSY = 8, // "Could not log in to World of Warcraft at this time. Please try again later."; + LOGIN_BADVERSION = 9, // "Unable to validate game version. This may be caused by file corruption or the interference of another program. Please visit www.blizzard.com/support/wow/ for more information and possible solutions to this issue."; + LOGIN_PARENTALCONTROL = 0xF, // "17"="LOGIN_PARENTALCONTROL" // "Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at http://www.worldofwarcraft.com."; + + // LOGIN_STATE_AUTHENTICATED: + LOGIN_OK = 0, // E + + // LOGIN_STATE_DOWNLOADFILE, LOGIN_OK + LOGIN_DOWNLOADFILE = 0xA, // not official name +}; +//============================================================================== +#endif // _LOGONCODES_H +//****************************************************************************** diff --git a/src/Client/doc/Ludmilla_1.8.0_LogonPackets.h.txt b/src/Client/doc/Ludmilla_1.8.0_LogonPackets.h.txt new file mode 100644 index 0000000..15033e1 --- /dev/null +++ b/src/Client/doc/Ludmilla_1.8.0_LogonPackets.h.txt @@ -0,0 +1,193 @@ +//****************************************************************************** +// Here are all packets to and from Logon Server. +//============================================================================== +#ifndef _LOGONPACKETS_H +#define _LOGONPACKETS_H +//============================================================================== +#include "../Shared/OurDefs.h" +#include +//============================================================================== +#pragma pack(push, 1) +//============================================================================== +// Challenge: +struct SClientLogonChallenge +{ + uint8 cmd; // OP code = CMD_AUTH_LOGON_CHALLENGE + uint8 error0x02; // 0x02 + uint16 size; // size of the rest of packet, without this part + uint8 gamename[4]; // "WoW" + uint8 version[2]; // 0x01 08 00 -> (1.8.0) + uint16 build; // 0x7F12 -> 4735 + uint8 platform[3]; // 68x\0 -> "x86" + uint8 os[3]; // niW\0 -> "Win" + uint8 localization[4];// BGne -> 'enGB' + uint32 timezone_bias; // 0x78 00 00 00 + uint8 ip[4]; // client ip: 0x7F 00 00 01 + uint8 acclen; // length of account name (without zero-char) + uint8 *acc; // upcased account name (without zero-char) +}; +struct SClientLogonChallenge_Header // just for usability +{ + uint8 cmd; // OP code = CMD_AUTH_LOGON_CHALLENGE + uint8 error; // 0x02 + uint16 size; // size of the rest of packet, without this part +}; +struct SClientReconnectChallenge // == SClientChallenge +{ + uint8 cmd; // OP code = 02 = CMD_AUTH_RECONNECT_CHALLENGE + uint8 error; // 0x02 + uint16 size; // size of the rest of packet, without this part + uint8 gamename[4]; // "WoW" + uint8 version[2]; // 0x01 08 00 -> (1.8.0) + uint16 build; // 0x7F12 -> 4735 + uint8 platform[4]; // 68x\0 -> "x86" + uint8 os[4]; // niW\0 -> "Win" + uint8 country[4]; // BGne -> 'enGB' + uint32 timezone_bias; // 0x78 00 00 00 + uint8 ip[4]; // client ip: 0x7F 00 00 01 + uint8 acclen; // length of account name (without zero-char) + uint8 *acc; // upcased account name (without zero-char) +}; +struct SServerLogonChallenge_Err +{ + uint8 cmd; // 0x00 -> OPcode = CMD_AUTH_LOGON_CHALLENGE ? CMD_GRUNT_AUTH_CHALLENGE + uint8 error; // one of SServerChallenge_ErrorCodes codes +}; +struct SServerLogonChallenge_Ok + // Variables: + // X := SHA1( salt || SHA1(upper(acc:pass)) ) + // b[20] := random server's secret + // K := 3 + // salt[32] := random + // N := 89 4B 64 5E - 89 E1 53 5B - BD AD 5B 8B - 29 06 50 53 + // 08 01 B1 8E - BF BF 5E 8F - AB 3C 82 87 - 2A 3E 9B B7 + // g[1] := 7 + // + // Calculations: + // Verifier := g^(~x) mod ~N + // B := ~( K*V + g^(~b) mod ~N ) +{ + uint8 cmd; // 0x00 -> OPcode = CMD_AUTH_LOGON_CHALLENGE ? CMD_GRUNT_AUTH_CHALLENGE + uint8 error; // 0 -> ok = LOGIN_OK + uint8 unk1; // 0x00 + + uint8 B[32]; // calculated by server + + uint8 g_len; // 0x01 + uint8 g[1]; // 0x07 (const) + + uint8 N_len; // 0x20 + uint8 N[32]; // const + + uint8 salt[32]; // random + uint8 unk2[16]; //1: BA 79 D4 8D - BF FC BF AD - 8C B4 EC B3 - 75 C5 96 05 + //2: 0F EB C2 82 - 28 C2 BC E4 - A6 31 30 C7 - 9F 6D 72 76 +}; +//------------------------------------------------------------------------------ +// Proof: +struct SClientLogonProof +{ + uint8 cmd; // 0x01 -> OPcode = CMD_AUTH_LOGON_PROOF + uint8 A[32]; // calculated by client + uint8 M1[20]; // + uint8 crc_hash[20]; // + uint8 number_of_keys; // 0x00 +}; +struct SClientReconnectProof // == SClientProof +{ + uint8 cmd; // 0x01 -> OPcode = CMD_AUTH_RECONNECT_PROOF + uint8 A[32]; // calculated by client + uint8 M1[20]; // + uint8 crc_hash[20]; // + uint8 number_of_keys; // 0x00 +}; +struct SServerLogonProof_Err + // Variables: + // U := SHA1(A || B) + // + // Calculations: + // S := ~( ( (V^(~U))*(~A) ) ^ (~b) mod ~N ) + // hS0 := SHA1 ( S[0] || S[2] || ... || S[20] ) + // hS1 := SHA1 ( S[1] || S[3] || ... || S[19] ) + // SS := hS0[0] || hS1[0] || hS0[1] || ... || hS1[10] + // M1 := SHA1( (SHA1(N) xor SHA1(G)) || SHA1(upper(acc)) || salt || A || B || SS ) +{ + uint8 cmd; // 0x01 -> OPcode = CMD_AUTH_LOGON_PROOF + uint8 error; // 0x04 -> password is incorrect = LOGIN_UNKNOWN_ACCOUNT +}; +struct SServerLogonProof_Ok + // M2 := SHA1(A || M1 || SS) +{ + uint8 cmd; // 0x01 -> OPcode = CMD_AUTH_LOGON_PROOF + uint8 error; // 0x00 -> ok + uint8 M2[20]; // calculated by server + uint32 unk; // 0x00 00 00 00 +}; +//------------------------------------------------------------------------------ +// Realm: +struct SClientRealmList +{ + uint8 cmd; // OP code = CMD_REALM_LIST + uint32 unknown; // 0x00 00 00 00 +}; +struct SServerRealmList // for info only - variable size +{ + uint8 cmd; // OP code = CMD_REALM_LIST + uint16 size; // size of the rest of packet, without this part + uint32 unknown; // 0x00 00 00 00 + uint8 count; // quantity of realms + struct SRealmInfo + { + uint32 icon; // icon near realm + uint8 color; // color of record + char *name; // Text zero terminated name of Realm + char *addr_port; // Text zero terminated address of Realm ("ip:port") + float population; // 1.6 -> population value. lower == lower population and vice versa + uint8 chars_here; // number of characters on this server + uint8 timezone; // timezone + uint8 unknown; // + } * realms; + uint8 unknown1; // 0x2A unknown + uint8 unknown2; // 0x00 unknown +}; +struct SServerRealmList_Header +{ + uint8 cmd; // OP code = CMD_REALM_LIST + uint16 size; // size of the rest of packet, without this part +}; +//------------------------------------------------------------------------------ +// Xref: +struct SServerXferInitiate +{ + uint8 cmd; // 0x30 -> OPcode = CMD_XFER_INITIATE + uint8 typelen; // 0x05 -> sizeof(Patch) + uint8 typestr[5]; // 'Patch' + uint32 size; // 0x34 C4 0D 00 = 902,196 byte (180->181 enGB) + uint32 unk; // 0x0 always + uint8 md5[MD5_DIGEST_LENGTH]; // md5 checksum of file +}; +struct SServerXferData +{ + uint8 cmd; // 0x31 -> OPcode = CMD_XFER_DATA + uint16 blocksize; // 0xDC 05 -> 1500 (max block) + uint8 buf[1500]; // block +}; +struct SClientXferAccept +{ + uint8 cmd; // 0x32 -> OPcode = CMD_XFER_ACCEPT +}; +struct SClientXferResume +{ + uint8 cmd; // 0x33 -> OPcode = CMD_XFER_RESUME + uint32 start; // will continue at + uint32 unknown; // +}; +struct SClientXferCancel +{ + uint8 cmd; // 0x34 -> OPcode = CMD_XFER_CANCEL +}; +//============================================================================== +#pragma pack(pop) +//============================================================================== +#endif // _LOGONPACKETS_H +//****************************************************************************** diff --git a/src/Client/doc/RS Connection.html b/src/Client/doc/RS Connection.html new file mode 100644 index 0000000..8e8beff --- /dev/null +++ b/src/Client/doc/RS Connection.html @@ -0,0 +1,257 @@ + + +Notes by Biasha:
+Structure (fields, size) and sequence of the packets is valid for 1.8.0
+Algorithm is not checked for 1.8.0 yet
+Original URL: http://www.shockerz.net/wowresource/forum/index.php?showtopic=42
+SRP algorithm: RFC2945
+Information about SRP6: http://srp.stanford.edu/doc.html
+
+
+
+ + [quote=Zam,Feb 11 2005, 09:26 PM] +
[Version 1.03] +
+
Ok, this only covers the first handshacking packets. :-) I haven't had time to disect any other packets. +
+
[size=18]If you are having problems; please verify your math with my math; there is a reason I supply the output to every function. This will allow you to see if there is typo's or any problem on either side. +
+
Please note that some libraries may have bugs with Big Numbers; hense the reason I used openssl, as it has been used by crypto products for years. :) +
+
[/size]
+
Changes: +
V1.00 - Initial Release +
V1.01 - Removal of the Second phase and adding where I forgot to up that B (Public) is reveresed before it is stored for use later. +
V1.02 - Added Temp variables results to S calc +
- Fixed the missing UPPERCASE in M1 calculation (Username) +
- Fixed colors. :o +
- Added some more notes. +
V1.03 - Update Warning, and added a couple more intermediate numbers in the M1 Calcs. +
+
+
I have been informed that only the first 4 packets are needed and then the client should ask for the realm list +
+
This is for version 1.1.1. I do not know if anything changed srp wise in 1.2.1; but I will be confirming and diferences between 111 and 121 once I have some spare time. According to several people; srp has NOT changed between 1.1.1 and 1.2.1 +
+
Kudo's to those who have shared there knowledge. Those who have selfishly held onto most or all of their hard work so as not to advance the community; well just disappear -- you are selfish losers and the community would be better off without you... +
------------------------------------------------------------- +
+
Packets as shared by sYkez on this topic (http://www.blizzhackers.com/viewtopic.php?t=21457) +
+
Kudo's to Amso for publically sharing his attempts at decoding srp; he actually was the one to inspire me to do this. +
Notes: +
Reverse means reverse the String. DO NOT USE strrev -- +
Treat this string as an array of numbers. 0 is a valid number; strrev will stop reversing when it incounters an NULL(0) character. My reverse routine is passed the length that it needs to reverse. In fact all of these variables are strored in a simple structure {char *data; int len;} and I pass this structure around. +
uppercase means upper case all letters in string. +
All values are in hex. +
& means concatanate the string valuse. "HI" & "THERE" = "HITHERE" +
Common Q & A: +
Yes, Username and Password are Uppercased. +
Yes, there are reversed string used in certain snippits of code. Don't ask my why; I don't know why Bliz deviated from the standard -- but it works. I assume the reason why is endian-ness of the machines. There server might be a main-frame... +
I am using an UNMODIFIED openssl (latest version) library. +
And I am using the wrapper functions in the t_math.c file that comes from the srp demo page. They just make the names of the functions much more readable. :-) +
+
Each Calculation assumes the byte order is in the initial stored state. So N=894B... +
When I reverse it in a routine N is only reversed for that Routine. When you get to the next routine, N is again equal to 894B... Some routines work with a reversed version of the calculation and some don't. Exception to this rule is B, it is reveresed before it is stored for use in later calculations. +
Lets Go at it: +
+
The Client Connects and sends the Client_Challenge packet. (Pretty self explanitory) +
+
struct { +
uint8 opcode; // 0x00 +
uint8 error; // 0x02 +
uint16 size; // 0x0023 (size of the rest of packet) +
char gameid[4]; //gameid[4]=0; // 'WoW' +
uint8 version1; // 0x00 +
uint8 version2; // 0x12 build version(0.12.0) +
uint8 version3; // 0x00 +
uint16 build; // 3988 +
char platform[4]; // platform[4]=0; // 'x86' +
char os[4]; // os[4]=0; // 'Win' +
char language[4]; // language[4]=0; // 'enUS' +
uint32 timezone_bias; // -419 +
uint32 ip; // client ip +
uint8 acclen; // length of account name +
char *AccountName; +
} Client_Challenge; +
+
The Server Generates the Following Packet: +
+
struct { +
uint8 opcode; // 0x00 +
uint8 error; //no error +
uint8 ukn1; +
char B[32]; +
uint8 g_length; //1 +
char g; +
+
uint8 n_len; // 32; //N_len +
char N[32]; +
char salt[32]; +
char unk3[16]; +
} Server_Challenge; +
+
Ok, N is is hard coded in hex as: +
894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7 +
G Length = 1 +
G = 7 +
K = 3 +
salt = randomly generated 32 characters. +
Server also internally generates a random generated "b" 20 characters +
+
We are going to assume some values to make it easier to duplicate: +
Username = "TEST" +
Password = "TEST" +
salt = 33f140d46cb66e631fdbbbc9f029ad8898e05ee533876118185e56dde843674f +
b = 8692E3A6BA48B5B1004CEF76825127B7EB7D1AEF +
+
Ok, Now for the calculations: +
+
To Generate x: +
Temp = "Username" (Supplied in the client challenge) & ":" & "Password" (Supplied to whatever user registration script). +
TempHash = SHA1(uppercase(Temp)) +
x = sha1(Salt & TempHash) +
+
Your x should equal: 1b70dd2ad03c1ed140223f8f8741c00ec3a4ce73 +
+
To Generate v (Verifier): +
N = Reverse(N) // 32 Characters +
x = Reverse(x) // 20 Characters +
v = g ^ x mod (N) +
// Exact call I Use: BN_mod_exp_mont(v, g, x, N, ctx, NULL); +
Your v Should equal: 996ec7b349d5827043ecd0e6efba3daea5590f944d0184fee1b83ff4f59ecfa8 +
+
+
To Generate B (public B, not private B): +
/* B = kv + g^b mod n */ +
b = Reverse(b) +
N = Reverse(N) +
+
Temp1 = K * v +
Temp2 = g ^ b mod (N) +
Temp3 = Temp1 + Temp2 +
B = Temp3 mod (N) +
B = Reverse(B) // Store this one PERMANATLY Reversed!!! +
+
// code I use is: +
//------------------------------ +
BigIntegerMul(B, k, v, NULL); +
BigIntegerModExp(k, g, b, N, NULL, NULL); +
BigIntegerAdd(k, k, B); +
BigIntegerMod(B, k, N, NULL); +
//------------------------------ +
Your B should equal: 645d1f78973073701e12bc98aa38ea99b4bc435c32e8447c73ab077ae4d75964 +
+
+
Stuff B, g, N, and Salt in the packet and send it. +
+
The client will respond with the following: +
struct { +
uint8 opcode; // 0x01 +
uint8 A[32]; +
uint8 M1[20]; +
uint8 crc_hash[20]; +
uint8 number_of_keys; +
} Client_Proof; +
+
Were going to assume A came over as follows: +
232fb1b88529643d95b8dce78f2750c75b2df37acba873eb31073839eda0738d +
And M1 came over as: +
eeb4adca80f4de02f9a9fe8d000d682e3ddfad6f +
+
A is generated by the client by its secret (a). You will never know what the secret (a) is, so you don't need to worry about how to calc A. (See SRP demo page if you really need to generate an A because you are working on a client program. +
+
M1 however is quite important, this will be used to detect if the user is authenticly loging on. +
+
crc_hash, appears to be unimportant in 1.1.1 (Anybody have any info?) +
number_of_keys = 0 +
+
Server will respond with: +
struct { +
uint8 opcode; // 0x01 +
uint8 error; // 0;//error +
uint8 M2[20]; //M2 +
uint8 ukn1; // 0; +
uint8 ukn2; // 0; +
uint8 ukn3; // 0; +
uint8 ukn4; // 0; +
} Server_Proof; +
+
To Generate M1 & M2, we need to generate some other values: +
Generate U: +
U = SHA1(A & B) +
Your U should equal: 2f4969ac9f387fd672236f9491a516777cdde1c1 +
+
+
Generate S: // S=(Av^u) ^ b (mod N) +
U = Reverse(U) +
N = Reverse(N) +
A = Reverse(A) +
b = Reverse(b) // Private b +
+
Temp1 = v ^ U mod (n) // Result: 84DC9E9F96AE7A2D9B05CD264A75EB5671EA02FD067B243848543E2713C8D91 +
+
Temp2 = Temp1 * A // Result: 496985FE28C394E7B8FB881105E4CD02F7DF4F378736332BC2F4733ABDEF0903F5BE9084C42B32E3615DF28B069A9D275A8A31DE7FBFD0DA76870B2B285F9D3 +
+
S = Temp2 ^ b mod (n) +
+
Code I use: +
//------------------------------ +
prod = BigIntegerFromInt(0); +
BigIntegerModExp(prod, v, U, N, NULL, NULL); +
S = BigIntegerFromInt(0); +
BigIntegerMul(prod, prod, A, NULL); +
BigIntegerModExp(S, prod, b, N, NULL, NULL); +
BigIntegerToBytes(S, Buffer, 20); +
//------------------------------ +
+
Your S should equal: 7666dc8a226dd0e3de093dddf6bc2b7929df2936a8cf15a972de4042766380ba +
+
+
Next we Take S and Split it into Two Hashes. Even / Odd +
+
S = reverse(S) // Yup we revsere the prior result. +
Then We take only Odd digits +
So S1 Should equal: +
ba63..[other hex digits]..8a66 +
And S2 Should Equal: +
8076..[other hex digits]..dc76 +
+
Then We Hash Each One: +
S1_Hash = SHA(S1) // Should Equal: 02f448b61a6e79d8b714387c0d2f22cc83f2877f +
S2_Hash = SHA(S2) // Should Equal: 61eb916a82b72864ea54dbfd3dc0ce4679c07814 +
+
And then we Re-combine them into S_Hash interleaving them togetner. +
SS_Hash = S1_Hash[0] & S2_Hash[0] & S1_Hash[1] & S2_Hash[1].... +
// SS_Hash should equal: 0261f4eb4891b66a1a826eb77928d864b7ea145438db7cfd0d3d2fc022cecc468379f2c087787f14 +
+
+
+
Ok, now lets calculate M1: You need to Calc M1 to verify it matches the M1 supplied by the client. This VERIFIES the username, password is correct. +
+
N_Hash = SHA1(N) // Nothing is Reversed in this routine +
G_Hash = SHA1(G) +
+
User_Hash = SHA1(uppercase(Username)) +
// User Hash = 984816fd329622876e14907634264e6f332e9fb3 +
// XOr them +
for(i=0;i<20;i++) NG_Hash = N_Hash[i] ^ G_Hash[i]; +
// NG_Hash = 1C76CF5659F68836A628404C431C1855E84D555B +
+
Temp = NG_Hash & User_Hash & Salt & A & B & SS_Hash +
// As you might Guess Temp is a really long string. :) +
+
M1 = SHA1(Temp) // Should = eeb4adca80f4de02f9a9fe8d000d682e3ddfad6f +
+
To Calculate M2: +
+
Temp = A & M1 & SS_Hash +
M2 = SHA1(Temp) // Should equal: 3a92ed0b783597be95654d6c66442046f9d389ae +
+
Now you stuff the server packets M2 with the above M2, and unknowns are all Zero. +
+
The client should request the realmlist packets at this time. You are logged IN!!! :-D +
P.S. I would also like to see the Header Encryption Documented. I've seen some people have decoded it but they are being quite selfish with the knowledge, which sets everyone back. I mean how many development hours does it set everyone back attempting to re-inventing srp6? It has taken me a huge number of hours to get to this point... :o +
[/quote] + diff --git a/src/Client/main.cpp b/src/Client/main.cpp new file mode 100644 index 0000000..0aec6f4 --- /dev/null +++ b/src/Client/main.cpp @@ -0,0 +1,61 @@ +#include "../shared/common.h" +#include "main.h" +#include "PseuWoW.h" + +#ifndef SIGQUIT +#define SIGQUIT 3 +#endif + +void _HookSignals(void) +{ + signal(SIGINT, _OnSignal); + signal(SIGQUIT, _OnSignal); + signal(SIGTERM, _OnSignal); + signal(SIGABRT, _OnSignal); + #ifdef _WIN32 + signal(SIGBREAK, _OnSignal); + #endif +} + +void _OnSignal(int s) +{ + switch (s) + { + case SIGINT: + case SIGQUIT: + case SIGTERM: + case SIGABRT: + quitproc(); + break; + #ifdef _WIN32 + case SIGBREAK: + exit(0); + break; + #endif + } + signal(s, _OnSignal); +} + +void quitproc(void){ + exit(0); +} + + +int main(int argc, char* argv[]) { + try + { + _HookSignals(); + ZThread::Thread t(new PseuInstanceRunnable); + t.setPriority((ZThread::Priority)2); + //... + t.wait(); + //... + return 0; + } + catch (...) + { + printf("ERROR: Unhandled exception in main thread!\n"); + raise(SIGABRT); + return 1; + } +} \ No newline at end of file diff --git a/src/Client/main.h b/src/Client/main.h new file mode 100644 index 0000000..e10d3eb --- /dev/null +++ b/src/Client/main.h @@ -0,0 +1,11 @@ +#ifndef _MAIN_H +#define _MAIN_H + +void _HookSignals(void); +void _OnSignal(int); +void quitproc(void); +int main(int,char**); + +// TODO: ZTHread additional includes machen, dass #include <...> möglich ist + +#endif \ No newline at end of file diff --git a/src/Client/resource.h b/src/Client/resource.h new file mode 100644 index 0000000..1ce16a6 --- /dev/null +++ b/src/Client/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Script1.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/Client/resource1.h b/src/Client/resource1.h new file mode 100644 index 0000000..98b2673 --- /dev/null +++ b/src/Client/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PseuWoW.rc +// +#define IDI_ICON1 103 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/Controller.vcproj b/src/Controller.vcproj new file mode 100644 index 0000000..5b07583 --- /dev/null +++ b/src/Controller.vcproj @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Controller/Controller.cpp b/src/Controller/Controller.cpp new file mode 100644 index 0000000..4035e64 --- /dev/null +++ b/src/Controller/Controller.cpp @@ -0,0 +1,319 @@ +// PseuWoW_Controller.cpp : Defines the entry point for the console application. +// + +#include +#include +#include + +#include +#include +#include + +#include "../shared/controllercodes.h" + +#define gets(c) Gets(c) + +#define MAXLEN 1024 + +bool DEBUG=true; + +char *ver="PseuWoW Controlling Unit Build 1"; +int error=0,port=10024; +SDL_Thread *connect_thread,*recieve_thread,*cmdhandler_thread,*quitproc_thread,*input_thread; +char *hostname="localhost"; +bool ready=false,connected=false,authenticated=false,nopassword=true,quit=false,waitforinput; +TCPsocket tcpsock; +char *incomingtext; +unsigned char incomingcmd; +char *password,*outgoingtext; +char *remotever; + +/////////// predeclare functions ///////////////////////// +int connect(void *p); +void closeconnection(bool); +void quitproc(void); +int tquitproc(void *p); + + +////////////////////////////////////////// + +void Gets(char *z,int m) { + int ch; + int counter=0; + while((ch=getchar()) != '\n') { + z[counter++]=ch; + if(counter >= m)break; + if(quit){printf("Q: returning from input.");return;} + } + z[counter] = '\0'; /* Terminieren */ +} + +char *triml(char *data,int count){ + data=data+count; + return data; +} + +bool readconf(void){ + +// read the shit, then set nopassword=false :) +return 0; //error +} + +void send(char code, char* sm_message="()"){ + if(quit)return; + if(tcpsock==NULL){printf("ERROR: Tried to send data over a cloed socket!\n"); return;} + int sm_result; + char *packet=(char*)malloc(1024); + sprintf(packet,"%c%s",code,sm_message); + int len = strlen(packet) + 1; // add one for the terminating NULL + sm_result = SDLNet_TCP_Send(tcpsock,packet,len); + if( sm_result < len ) { + printf( "SDLNet_TCP_Send: %s\n", SDLNet_GetError() ); + } + else{ + //printf("out: %i, %s\n",code,sm_message); + } + free(packet); +} + +int recieve(void *p) { + int result; + char msg[MAXLEN]; + while(connected) { + //printf("recieve: Waiting for incoming data...\n"); + result = SDLNet_TCP_Recv(tcpsock,msg,MAXLEN); + if(result <= 0) { + // TCP Connection is broken. (because of error or closure) + //closeconnection(false); + + quitproc_thread=SDL_CreateThread(tquitproc,NULL); + } else { + msg[result] = 0; + + incomingcmd=msg[0]; + incomingtext=triml(msg,1); + //printf("in: %i, %s\n",incomingcmd,incomingtext); + + + } + } + if(DEBUG)printf("Reciever lost the connection, thread exited.\n"); + +return 0; +} + +int connect(void *p){ + if(quit)return 0; + IPaddress ip; + while(SDLNet_ResolveHost(&ip,hostname,port)==-1)SDL_Delay(100); + printf("Waiting for connection...\n"); + while(tcpsock==NULL){ + tcpsock=SDLNet_TCP_Open(&ip); + //SDL_Delay(100); + } + connected=true; + if(DEBUG)printf("Connection established.\n"); + recieve_thread=SDL_CreateThread(recieve,NULL); + send(_REQUESTCONNECTION,ver); + if(DEBUG)printf("Thread exited: Connector\n"); + return 0; +} + + +void closeconnection(bool reconnect){ + if(DEBUG)printf("Closing connections. Reconnect=%i\n",reconnect); + SDL_KillThread(recieve_thread); + SDLNet_TCP_Close(tcpsock); + tcpsock=NULL; + connected=false; + authenticated=false; + if(reconnect){ + connect_thread=SDL_CreateThread(connect,NULL); + if(DEBUG)printf("Thread restarted: Connector\n"); + } + // more to come +} + +int tquitproc(void *p){ + exit(0); + return 0; +} + +void quitproc(void){ + static bool quitted; + if(quitted) return; + quitted=true; + printf("Quitting...\n"); + quit=true; + SDL_KillThread(input_thread); + + if(DEBUG)printf("Closing Connection\n"); + closeconnection(false); + + + printf("End.\n"); + + //SDL_Delay(100); + exit(0); +} + +void forceclose(void){ +//if(connected) disconnect(); +quitproc(); +} + + + +int cmdhandler(void *p){ + while(true){ + if (incomingcmd!=_NODATA){ + switch(incomingcmd){ + //case _SENDTEXT:printf("%s\n",incomingtext);break; //bugged somehow + case _PASSWORDOK:{printf("%s has accepted the connection.\n",remotever);authenticated=true;}break; + case _PASSWORDWRONG:{printf("%s has rejected the connection, exiting...\n",remotever);SDL_Delay(2000);quitproc();}break; + //case _DISCONNECT:{printf("Got disconnected from the remote side!\n");closeconnection(false);}break; // no longer needed + case _REQUESTPASSWORD: + strcpy(remotever,incomingtext); + printf("%s requests a password.\n",remotever); + if (nopassword){ + printf("Enter Password, max. 32 chars: "); + Gets(password,32); + } + send(_SENDPASSWORD,password); + printf("Password sent, waiting for answer...\n"); + break; + case _RECIEVEDANDREADY:{printf("%s\n",incomingtext);ready=true;}break; + case _RECIEVEDBUTUNKNOWN:{printf("The opcode was not recognized by the remote side.\n");ready=true;}break; + case _UNKNOWNCOMMAND:{printf("Unknown command.\n");ready=true;}break; + case _BADCOMMAND:{printf("Bad command: %s\n",incomingtext);ready=true;}break; + default:{printf("Recieved unknown opcode!\n");}break; + } + incomingcmd=_NODATA; + } + SDL_Delay(1); + } +return 0; +} + + +bool initproc(void){ +printf("%s\n",ver); +if(DEBUG)printf("Allocating buffer memory...\n"); + +incomingtext=(char*)malloc(1024); +outgoingtext=(char*)malloc(1024); +password=(char*)malloc(32); +remotever=(char*)malloc(128); +// more malloc... + +printf("Reading Config file... "); +if (readconf()) printf("done.\n"); else { + printf("error!\n"); + //printf("Enter Password, max. 32 chars: "); + //scanf("%s",&password); +} + +if(DEBUG)printf("Initializing SDL...\n"); +if(SDL_Init(0)==-1) { + printf("SDL_Init: %s\n", SDL_GetError()); + return false; + } + +if(DEBUG)printf("Initializing SDL_Net...\n"); +if(SDLNet_Init()==-1) { + printf("SDLNet_Init: %s\n", SDLNet_GetError()); + return false; +} +if(DEBUG)printf("Starting threads...\n"); + +connect_thread=SDL_CreateThread(connect,NULL); +if(DEBUG)printf("Thread started: Connector\n"); +cmdhandler_thread=SDL_CreateThread(cmdhandler,NULL); +if(DEBUG)printf("Thread started: CmdHandler\n"); + +return 1; +} + +/* +int waitfortimeout(void *p){ + int timeout; + for (timeout=10000;timeout>0||!ready;timeout--){ + SDL_Delay(1); + if(timeout%1000==0) printf("."); + } + if(!ready) closeconnection(); // still not ready? disconnect! + +return 0; +} +*/ + +void showhelp(void){ +printf("commands - displays a list of commands the remote side supports\n"); +printf("ver - show version\n"); + + + +} + +bool IsLocalCommand(char *txt){ +if(strcmp(outgoingtext,"help")==0){showhelp();return true;} +if(strcmp(outgoingtext,"ver")==0){printf("%s\n",ver);return true;} +if(strcmp(outgoingtext,"quit")==0||strcmp(outgoingtext,"exit")==0){quitproc();return true;} +if(strcmp(outgoingtext,"?")==0){showhelp();return true;} +return false; +} + + +int main(int argc, char* argv[]) +{ + atexit(forceclose); + +///! printf("%c",(char)_SAYHELLO); + if (!initproc()){ + printf("Initialisation failed!\n"); + return 1; + } else { + // more init...? + printf("Initialisation finished.\n"); + while(!(authenticated&&connected)){ + + + + SDL_Delay(1); + } + send(_RECIEVEDANDREADY); + printf("Authentication ok, opening console. You can enter commands now.\n"); + printf("Type \"help\" for a short introduction\n"); + while(true){ + while(authenticated){ + SDL_Delay(1); + + if(ready){ + printf("> "); + while(true){ + /*if(!waitforinput){ + SDL_CreateThread(tinput,NULL); + SDL_Delay(10); + while(waitforinput)SDL_Delay(1); + }*/ + + Gets(outgoingtext,MAXLEN); + if(strlen(outgoingtext)<=0)printf("Maybe you want to enter something...?!\n> ");else break; + SDL_Delay(1); + } + if (!IsLocalCommand(outgoingtext)){send(_SENDCOMMAND,outgoingtext);ready=false;} + + + //SDL_CreateThread(waitfortimeout,NULL); + } + + } + SDL_Delay(1); + + + } + } + + return 0; +} + diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj new file mode 100644 index 0000000..6ad919e --- /dev/null +++ b/src/PseuWoW.vcproj @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dep/include/zlib/crc32.h b/src/dep/include/zlib/crc32.h new file mode 100644 index 0000000..8053b61 --- /dev/null +++ b/src/dep/include/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/src/dep/include/zlib/deflate.h b/src/dep/include/zlib/deflate.h new file mode 100644 index 0000000..05a5ab3 --- /dev/null +++ b/src/dep/include/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/src/dep/include/zlib/inffast.h b/src/dep/include/zlib/inffast.h new file mode 100644 index 0000000..1e88d2d --- /dev/null +++ b/src/dep/include/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/src/dep/include/zlib/inffixed.h b/src/dep/include/zlib/inffixed.h new file mode 100644 index 0000000..75ed4b5 --- /dev/null +++ b/src/dep/include/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/src/dep/include/zlib/inflate.h b/src/dep/include/zlib/inflate.h new file mode 100644 index 0000000..07bd3e7 --- /dev/null +++ b/src/dep/include/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/src/dep/include/zlib/inftrees.h b/src/dep/include/zlib/inftrees.h new file mode 100644 index 0000000..b1104c8 --- /dev/null +++ b/src/dep/include/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/src/dep/include/zlib/trees.h b/src/dep/include/zlib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/src/dep/include/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/src/dep/include/zlib/zconf.h b/src/dep/include/zlib/zconf.h new file mode 100644 index 0000000..03a9431 --- /dev/null +++ b/src/dep/include/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 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 deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# 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 inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# 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 zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# 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_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#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 + /* 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 /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* 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 */ diff --git a/src/dep/include/zlib/zlib.h b/src/dep/include/zlib/zlib.h new file mode 100644 index 0000000..0228179 --- /dev/null +++ b/src/dep/include/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/src/dep/include/zlib/zutil.h b/src/dep/include/zlib/zutil.h new file mode 100644 index 0000000..b7d5eff --- /dev/null +++ b/src/dep/include/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/src/dep/include/zthread/AtomicCount.h b/src/dep/include/zthread/AtomicCount.h new file mode 100644 index 0000000..ea042a7 --- /dev/null +++ b/src/dep/include/zthread/AtomicCount.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNT_H__ +#define __ZTATOMICCOUNT_H__ + +#include + +#include "zthread/Config.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + /** + * @class AtomicCount + * @author Eric Crahen + * @date <2003-07-16T09:41:55-0400> + * @version 2.3.0 + * + * This class provides an interface to a small integer whose value can be + * incremented or decremented atomically. It's designed to be as simple and + * lightweight as possible so that it can be used cheaply to create reference + * counts. + */ + class ZTHREAD_API AtomicCount : public NonCopyable { + + void* _value; + + public: + + //! Create a new AtomicCount, initialized to a value of 1 + AtomicCount(); + + //! Destroy a new AtomicCount + ~AtomicCount(); + + //! Postfix decrement and return the current value + size_t operator--(int); + + //! Postfix increment and return the current value + size_t operator++(int); + + //! Prefix decrement and return the current value + size_t operator--(); + + //! Prefix increment and return the current value + size_t operator++(); + + + }; /* AtomicCount */ + + +} // namespace ZThread + +#endif // __ZTATOMICCOUNT_H__ diff --git a/src/dep/include/zthread/Barrier.h b/src/dep/include/zthread/Barrier.h new file mode 100644 index 0000000..6aaafa9 --- /dev/null +++ b/src/dep/include/zthread/Barrier.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTBARRIER_H__ +#define __ZTBARRIER_H__ + +#include "zthread/Condition.h" +#include "zthread/Guard.h" +#include "zthread/Waitable.h" +#include "zthread/Runnable.h" + +namespace ZThread { + + /** + * @class Barrier + * @author Eric Crahen + * @date <2003-07-16T09:54:01-0400> + * @version 2.2.1 + * + * A Barrier is a Waitable object that serves as synchronization points for + * a set of threads. A Barrier is constructed for a fixed number (N) of threads. + * Threads attempting to wait() on a Barrier ( 1 - N) will block until the Nth + * thread arrives. The Nth thread will awaken all the the others. + * + * An optional Runnable command may be associated with the Barrier. This will be run() + * when the Nth thread arrives and Barrier is not broken. + * + * Error Checking + * + * A Barrier uses an all-or-nothing. All threads involved must successfully + * meet at Barrier. If any one of those threads leaves before all the threads + * have (as the result of an error or exception) then all threads present at + * the Barrier will throw BrokenBarrier_Exception. + * + * A broken Barrier will cause all threads attempting to wait() on it to + * throw a BrokenBarrier_Exception. + * + * A Barrier will remain 'broken', until it is manually reset(). + */ + template + class Barrier : public Waitable, private NonCopyable { + + //! Broken flag + bool _broken; + //! Task flag + bool _haveTask; + //! Thread count + unsigned int _count; + //! Wait generation + unsigned int _generation; + //! Serialize access + LockType _lock; + //! Signaled when all thread arrive + Condition _arrived; + //! Command to run when all the thread arrive + Task _task; + + public: + + //! Create a Barrier + Barrier() + : _broken(false), _haveTask(false), _count(Count), _generation(0), _arrived(_lock), _task(0) { } + + /** + * Create a Barrier that executes the given task when all threads arrive + * without error + * + * @param task Task to associate with this Barrier + */ + Barrier(const Task& task) + : _broken(false), _haveTask(true), _count(Count), _generation(0), _arrived(_lock), + _task(task) { } + + //! Destroy this Barrier + virtual ~Barrier() {} + + /** + * Enter barrier and wait for the other threads to arrive. This can block for an indefinite + * amount of time. + * + * @exception BrokenBarrier_Exception thrown when any thread has left a wait on this + * Barrier as a result of an error. + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending a wait + * for one thread and breaking the barrier for all threads + * + * @see Waitable::wait() + * + * @post If no exception was thrown, all threads have successfully arrived + * @post If an exception was thrown, the barrier is broken + */ + virtual void wait() { + + Guard g(_lock); + + if(_broken) + throw BrokenBarrier_Exception(); + + // Break the barrier if an arriving thread is interrupted + if(Thread::interrupted()) { + + // Release the other waiter, propagate the exception + _arrived.broadcast(); + _broken = true; + + throw Interrupted_Exception(); + + } + + if(--_count == 0) { + + // Wake the other threads if this was the last + // arriving thread + _arrived.broadcast(); + + // Try to run the associated task, if it throws then + // break the barrier and propagate the exception + try { + + if(_task) + _task->run(); + + _generation++; + + } catch(Synchronization_Exception&) { + + _broken = true; + throw; + + } catch(...) { assert(0); } + + } else { + + int myGeneration = _generation; + + try { + + // Wait for the other threads to arrive + _arrived.wait(); + + } catch(Interrupted_Exception&) { + + // Its possible for a thread to be interrupted before the + // last thread arrives. If the interrupted thread hasn't + // resumed, then just propagate the interruption + + if(myGeneration != _generation) + Thread().interrupt(); + + else _broken = true; + + } catch(Synchronization_Exception&) { + + // Break the barrier and propagate the exception + _broken = true; + throw; + + } + + // If the thread woke because it was notified by the thread + // that broke the barrier, throw. + if(_broken) + throw BrokenBarrier_Exception(); + + } + + } + + /** + * Enter barrier and wait for the other threads to arrive. This can block up to the + * amount of time specified with the timeout parameter. The barrier will not break + * if a thread leaves this function due to a timeout. + * + * @param timeout maximum amount of time, in milliseconds, to wait before + * + * @return + * - true if the set of tasks being wait for complete before + * timeout milliseconds elapse. + * - false otherwise. + * + * @exception BrokenBarrier_Exception thrown when any thread has left a wait on this + * Barrier as a result of an error. + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending a wait + * for one thread and breaking the barrier for all threads + * + * @see Waitable::wait(unsigned long timeout) + * + * @post If no exception was thrown, all threads have successfully arrived + * @post If an exception was thrown, the barrier is broken + */ + virtual bool wait(unsigned long timeout) { + + Guard g(_lock); + + if(_broken) + throw BrokenBarrier_Exception(); + + // Break the barrier if an arriving thread is interrupted + if(Thread::interrupted()) { + + // Release the other waiter, propagate the exception + _arrived.broadcast(); + _broken = true; + + throw Interrupted_Exception(); + + } + + + if(--_count == 0) { + + // Wake the other threads if this was the last + // arriving thread + _arrived.broadcast(); + + // Try to run the associated task, if it throws then + // break the barrier and propagate the exception + try { + + if(_task) + _task->run(); + + _generation++; + + } catch(Synchronization_Exception&) { + + _broken = true; + throw; + + } catch(...) { assert(0); } + + } else { + + int myGeneration = _generation; + + try { + + // Wait for the other threads to arrive + if(!_arrived.wait(timeout)) + _broken = true; + + } catch(Interrupted_Exception&) { + + // Its possible for a thread to be interrupted before the + // last thread arrives. If the interrupted thread hasn't + // resumed, then just propagate the interruption + + if(myGeneration != _generation) + Thread().interrupt(); + + else _broken = true; + + } catch(Synchronization_Exception&) { + + // Break the barrier and propagate the exception + _broken = true; + throw; + + } + + // If the thread woke because it was notified by the thread + // that broke the barrier, throw. + if(_broken) + throw BrokenBarrier_Exception(); + + } + + return true; + + } + + /** + * Break the Barrier ending the wait for any threads that were waiting on + * the barrier. + * + * @post the Barrier is broken, all waiting threads will throw the + * BrokenBarrier_Exception + */ + void shatter() { + + Guard g(_lock); + + _broken = true; + _arrived.broadcast(); + + } + + /** + * Reset the Barrier. + * + * @post the Barrier is no longer Broken and can be used again. + */ + void reset() { + + Guard g(_lock); + + _broken = false; + _generation++; + _count = Count; + + } + + }; + + +} // namespace ZThread + +#endif // __ZTBARRIER_H__ diff --git a/src/dep/include/zthread/BiasedReadWriteLock.h b/src/dep/include/zthread/BiasedReadWriteLock.h new file mode 100644 index 0000000..b1de742 --- /dev/null +++ b/src/dep/include/zthread/BiasedReadWriteLock.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTBIASEDREADWRITELOCK_H__ +#define __ZTBIASEDREADWRITELOCK_H__ + +#include "zthread/ReadWriteLock.h" +#include "zthread/Condition.h" +#include "zthread/Guard.h" +#include "zthread/FastMutex.h" + +namespace ZThread { + + /** + * @class BiasedReadWriteLock + * + * @author Eric Crahen + * @date <2003-07-16T10:22:34-0400> + * @version 2.2.7 + * + * A BiasedReadWriteLock has a bias toward writers. It will prefer read-write access over + * read-only access when many threads are contending for access to either Lockable this + * ReadWriteLock provides. + * + * @see ReadWriteLock + */ + class BiasedReadWriteLock : public ReadWriteLock { + + FastMutex _lock; + Condition _condRead; + Condition _condWrite; + + volatile int _activeWriters; + volatile int _activeReaders; + + volatile int _waitingReaders; + volatile int _waitingWriters; + + //! @class ReadLock + class ReadLock : public Lockable { + + BiasedReadWriteLock& _rwlock; + + public: + + ReadLock(BiasedReadWriteLock& rwlock) : _rwlock(rwlock) {} + + virtual ~ReadLock() {} + + virtual void acquire() { + _rwlock.beforeRead(); + } + + virtual bool tryAcquire(unsigned long timeout) { + return _rwlock.beforeReadAttempt(timeout); + } + + virtual void release() { + _rwlock.afterRead(); + } + + }; + + //! @class WriteLock + class WriteLock : public Lockable { + + BiasedReadWriteLock& _rwlock; + + public: + + WriteLock(BiasedReadWriteLock& rwlock) : _rwlock(rwlock) {} + + virtual ~WriteLock() {} + + + virtual void acquire() { + _rwlock.beforeWrite(); + } + + virtual bool tryAcquire(unsigned long timeout) { + return _rwlock.beforeWriteAttempt(timeout); + } + + virtual void release() { + _rwlock.afterWrite(); + } + + }; + + friend class ReadLock; + friend class WriteLock; + + ReadLock _rlock; + WriteLock _wlock; + + public: + + /** + * Create a BiasedReadWriteLock + * + * @exception Initialization_Exception thrown if resources could not be + * allocated for this object. + */ + BiasedReadWriteLock() : _condRead(_lock), _condWrite(_lock), _rlock(*this), _wlock(*this) { + + _activeWriters = 0; + _activeReaders = 0; + + _waitingReaders = 0; + _waitingWriters = 0; + + } + + //! Destroy this ReadWriteLock + virtual ~BiasedReadWriteLock() {} + + /** + * @see ReadWriteLock::getReadLock() + */ + virtual Lockable& getReadLock() { return _rlock; } + + /** + * @see ReadWriteLock::getWriteLock() + */ + virtual Lockable& getWriteLock() { return _wlock; } + + + protected: + + void beforeRead() { + + Guard guard(_lock); + + ++_waitingReaders; + + while(!allowReader()) { + + try { + + // wait + _condRead.wait(); + + } catch(...) { + + --_waitingReaders; + throw; + + } + + } + + --_waitingReaders; + ++_activeReaders; + + } + + bool beforeReadAttempt(unsigned long timeout) { + + Guard guard(_lock); + bool result = false; + + ++_waitingReaders; + + while(!allowReader()) { + + try { + + result = _condRead.wait(timeout); + + } catch(...) { + + --_waitingReaders; + throw; + + } + + } + + --_waitingReaders; + ++_activeReaders; + + return result; + } + + + void afterRead() { + + bool wakeReader = false; + bool wakeWriter = false; + + { + + Guard guard(_lock); + + --_activeReaders; + + wakeReader = (_waitingReaders > 0); + wakeWriter = (_waitingWriters > 0); + + } + + if(wakeWriter) + _condWrite.signal(); + + else if(wakeReader) + _condRead.signal(); + + } + + void beforeWrite() { + + Guard guard(_lock); + + ++_waitingWriters; + + while(!allowWriter()) { + + try { + + _condWrite.wait(); + + } catch(...) { + + --_waitingWriters; + throw; + + } + + } + + --_waitingWriters; + ++_activeWriters; + + } + + bool beforeWriteAttempt(unsigned long timeout) { + + Guard guard(_lock); + bool result = false; + + ++_waitingWriters; + + while(!allowWriter()) { + + try { + + result = _condWrite.wait(timeout); + + } catch(...) { + + --_waitingWriters; + throw; + } + + } + + --_waitingWriters; + ++_activeWriters; + + return result; + + } + + void afterWrite() { + + bool wakeReader = false; + bool wakeWriter = false; + + { + + Guard guard(_lock); + + --_activeWriters; + + wakeReader = (_waitingReaders > 0); + wakeWriter = (_waitingWriters > 0); + + } + + if(wakeWriter) + _condWrite.signal(); + + else if(wakeReader) + _condRead.signal(); + + } + + bool allowReader() { + return (_activeWriters == 0); + } + + bool allowWriter() { + return (_activeWriters == 0 && _activeReaders == 0); + } + + }; + +}; // __ZTBIASEDREADWRITELOCK_H__ + +#endif diff --git a/src/dep/include/zthread/BlockingQueue.h b/src/dep/include/zthread/BlockingQueue.h new file mode 100644 index 0000000..e384893 --- /dev/null +++ b/src/dep/include/zthread/BlockingQueue.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTBLOCKINGQUEUE_H__ +#define __ZTBLOCKINGQUEUE_H__ + +#include "zthread/Guard.h" +#include "zthread/Condition.h" +#include "zthread/Queue.h" + +#include + +namespace ZThread { + + /** + * @class BlockingQueue + * @author Eric Crahen + * @date <2003-07-16T12:01:43-0400> + * @version 2.3.0 + * + * Like a LockedQueue, a BlockingQueue is a Queue implementation that provides + * serialized access to the items added to it. It differs by causing threads + * accessing the next() methods to block until a value becomes available. + */ + template > + class BlockingQueue : public Queue, public Lockable { + + //! Serialize access + LockType _lock; + + //! Signaled when empty + Condition _notEmpty; + + //! Storage backing the queue + StorageType _queue; + + //! Cancellation flag + volatile bool _canceled; + + public: + + //! Create a new BlockingQueue + BlockingQueue() : _notEmpty(_lock), _canceled(false) {} + + //! Destroy this BlockingQueue + virtual ~BlockingQueue() { } + + /** + * @see Queue::add(const T& item) + */ + virtual void add(const T& item) { + + Guard g(_lock); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + + _notEmpty.signal(); + + } + + /** + * @see Queue::add(const T& item, unsigned long timeout) + */ + virtual bool add(T item, unsigned long timeout) { + + try { + + Guard g(_lock, timeout); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + + _notEmpty.signal(); + + } catch(Timeout_Exception&) { return false; } + + return true; + + } + + /** + * Get a value from this Queue. The calling thread may block indefinitely. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before a value becomes available. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + * + * @see Queue::next() + */ + virtual T next() { + + Guard g(_lock); + + while(_queue.size() == 0 && !_canceled) + _notEmpty.wait(); + + if( _queue.size() == 0 ) + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + return item; + + } + + + /** + * Get a value from this Queue. The calling thread may block indefinitely. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Timeout_Exception thrown if the timeout expires before a value + * can be retrieved. + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before a value becomes available. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + * + * @see Queue::next(unsigned long timeout) + */ + virtual T next(unsigned long timeout) { + + Guard g(_lock, timeout); + + while(_queue.size() == 0 && !_canceled) { + if(!_notEmpty.wait(timeout)) + throw Timeout_Exception(); + } + + if(_queue.size() == 0 ) + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + return item; + + } + + + /** + * @see Queue::cancel() + * + * @post If threads are blocked on one of the next() functions then + * they will be awakened with a Cancellation_Exception. + */ + virtual void cancel() { + + Guard g(_lock); + + _notEmpty.broadcast(); + _canceled = true; + + } + + /** + * @see Queue::isCanceled() + */ + virtual bool isCanceled() { + + // Faster check since the queue will not become un-canceled + if(_canceled) + return true; + + Guard g(_lock); + + return _canceled; + + } + + /** + * @see Queue::size() + */ + virtual size_t size() { + + Guard g(_lock); + return _queue.size(); + + } + + /** + * @see Queue::size(unsigned long timeout) + */ + virtual size_t size(unsigned long timeout) { + + Guard g(_lock, timeout); + return _queue.size(); + + } + + public: + + virtual void acquire() { + _lock.acquire(); + } + + virtual bool tryAcquire(unsigned long timeout) { + return _lock.tryAcquire(timeout); + } + + virtual void release() { + _lock.release(); + } + + }; /* BlockingQueue */ + +} // namespace ZThread + +#endif // __ZTBLOCKINGQUEUE_H__ diff --git a/src/dep/include/zthread/BoundedQueue.h b/src/dep/include/zthread/BoundedQueue.h new file mode 100644 index 0000000..31b1b91 --- /dev/null +++ b/src/dep/include/zthread/BoundedQueue.h @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTBOUNDEDQUEUE_H__ +#define __ZTBOUNDEDQUEUE_H__ + +#include "zthread/Condition.h" +#include "zthread/Guard.h" +#include "zthread/Queue.h" + +#include + +namespace ZThread { + + /** + * @class BoundedQueue + * + * @author Eric Crahen + * @date <2003-07-16T13:54:04-0400> + * @version 2.3.0 + * + * A BoundedQueue provides serialized access to a set of values. It differs from other + * Queues by adding a maximum capacity, giving it the following properties: + * + * - Threads calling the empty() methods will be blocked until the BoundedQueue becomes empty. + * - Threads calling the next() methods will be blocked until the BoundedQueue has a value to + * return. + * - Threads calling the add() methods will be blocked until the number of values in the + * Queue drops below the maximum capacity. + * + * @see Queue + */ + template > + class BoundedQueue : public Queue, public Lockable { + + //! Maximum capacity for the Queue + size_t _capacity; + + //! Serialize access + LockType _lock; + + //! Signaled if not full + Condition _notFull; + + //! Signaled if not empty + Condition _notEmpty; + + //! Signaled if empty + Condition _isEmpty; + + //! Storage backing the queue + StorageType _queue; + + //! Cancellation flag + volatile bool _canceled; + + public: + + /** + * Create a BoundedQueue with the given capacity. + * + * @param capacity maximum number of values to allow in the Queue at + * at any time + */ + BoundedQueue(size_t capacity) + : _notFull(_lock), _notEmpty(_lock), _isEmpty(_lock), + _capacity(capacity), _canceled(false) {} + + //! Destroy this Queue + virtual ~BoundedQueue() { } + + /** + * Get the maximum capacity of this Queue. + * + * @return size_t maximum capacity + */ + size_t capacity() { + return _capacity; + } + + /** + * Add a value to this Queue. + * + * If the number of values in the queue matches the value returned by capacity() + * then the calling thread will be blocked until at least one value is removed from + * the Queue. + * + * @param item value to be added to the Queue + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to add a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If no exception is thrown, a copy of item will have been added to the Queue. + * + * @see Queue::add(const T& item) + */ + virtual void add(const T& item) { + + Guard g(_lock); + + // Wait for the capacity of the Queue to drop + while ((_queue.size() == _capacity) && !_canceled) + _notFull.wait(); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + _notEmpty.signal(); // Wake any waiters + + + } + + /** + * Add a value to this Queue. + * + * If the number of values in the queue matches the value returned by capacity() + * then the calling thread will be blocked until at least one value is removed from + * the Queue. + * + * @param item value to be added to the Queue + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if a copy of item can be added before timeout + * milliseconds elapse. + * - false otherwise. + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to add a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If no exception is thrown, a copy of item will have been added to the Queue. + * + * @see Queue::add(const T& item, unsigned long timeout) + */ + virtual bool add(const T& item, unsigned long timeout) { + + try { + + Guard g(_lock, timeout); + + // Wait for the capacity of the Queue to drop + while ((_queue.size() == _capacity) && !_canceled) + if(!_notFull.wait(timeout)) + return false; + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + _notEmpty.signal(); // Wake any waiters + + } catch(Timeout_Exception&) { return false; } + + return true; + + } + + /** + * Retrieve and remove a value from this Queue. + * + * If invoked when there are no values present to return then the calling thread + * will be blocked until a value arrives in the Queue. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to retrieve a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next() { + + Guard g(_lock); + + while ( _queue.size() == 0 && !_canceled) + _notEmpty.wait(); + + if( _queue.size() == 0) // Queue canceled + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + _notFull.signal(); // Wake any thread trying to add + + if(_queue.size() == 0) // Wake empty waiters + _isEmpty.broadcast(); + + return item; + + } + + /** + * Retrieve and remove a value from this Queue. + * + * If invoked when there are no values present to return then the calling thread + * will be blocked until a value arrives in the Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Timeout_Exception thrown if the timeout expires before a value + * can be retrieved. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next(unsigned long timeout) { + + Guard g(_lock, timeout); + + // Wait for items to be added + while (_queue.size() == 0 && !_canceled) { + if(!_notEmpty.wait(timeout)) + throw Timeout_Exception(); + } + + if(_queue.size() == 0) // Queue canceled + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + _notFull.signal(); // Wake add() waiters + + if(_queue.size() == 0) // Wake empty() waiters + _isEmpty.broadcast(); + + return item; + + } + + /** + * Cancel this queue. + * + * @post Any threads blocked by an add() function will throw a Cancellation_Exception. + * @post Any threads blocked by a next() function will throw a Cancellation_Exception. + * + * @see Queue::cancel() + */ + virtual void cancel() { + + Guard g(_lock); + + _canceled = true; + _notEmpty.broadcast(); // Wake next() waiters + + } + + /** + * @see Queue::isCanceled() + */ + virtual bool isCanceled() { + + // Faster check since the Queue will not become un-canceled + if(_canceled) + return true; + + Guard g(_lock); + + return _canceled; + + } + + /** + * @see Queue::size() + */ + virtual size_t size() { + + Guard g(_lock); + return _queue.size(); + + } + + /** + * @see Queue::size(unsigned long timeout) + */ + virtual size_t size(unsigned long timeout) { + + Guard g(_lock, timeout); + return _queue.size(); + + } + + /** + * Test whether any values are available in this Queue. + * + * The calling thread is blocked until there are no values present + * in the Queue. + * + * @return + * - true if there are no values available. + * - false if there are values available. + * + * @see Queue::empty() + */ + virtual bool empty() { + + Guard g(_lock); + + while(_queue.size() > 0) // Wait for an empty signal + _isEmpty.wait(); + + return true; + + + } + + + /** + * Test whether any values are available in this Queue. + * + * The calling thread is blocked until there are no values present + * in the Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if there are no values available. + * - false if there are values available. + * + * @exception Timeout_Exception thrown if timeout milliseconds + * expire before a value becomes available + * + * @see Queue::empty() + */ + virtual bool empty(unsigned long timeout) { + + Guard g(_lock, timeout); + + while(_queue.size() > 0) // Wait for an empty signal + _isEmpty.wait(timeout); + + return true; + + } + + public: + + virtual void acquire() { + _lock.acquire(); + } + + virtual bool tryAcquire(unsigned long timeout) { + return _lock.tryAcquire(timeout); + } + + virtual void release() { + _lock.release(); + } + + }; /* BoundedQueue */ + +} // namespace ZThread + +#endif // __ZTBOUNDEDQUEUE_H__ diff --git a/src/dep/include/zthread/Cancelable.h b/src/dep/include/zthread/Cancelable.h new file mode 100644 index 0000000..9151ec8 --- /dev/null +++ b/src/dep/include/zthread/Cancelable.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCANCELABLE_H__ +#define __ZTCANCELABLE_H__ + +#include "zthread/Exceptions.h" + +namespace ZThread { + + /** + * @class Cancelable + * + * @author Eric Crahen + * @date <2003-07-16T09:28:46-0400> + * @version 2.3.0 + * + * The Cancelable interface defines a common method of adding general disable-and-exit + * semantics to some object. By cancel()ing a Cancelable object, a request is + * made to disable that object. + * + * Disabling + * + * A cancel()ed object may not necessarily abort it work immediately. Often, it much more + * elegant for a cancel()ed object to complete handling whatever responsibilities have + * been assigned to it, but it will not take on any new responsibility. + * + * Exiting + * + * A cancel()ed should complete its responsibilities as soon as possible. + * Canceling is not only a request to stop taking on new responsibility, and to + * complete its current responsibility. Its also a request to complete dealing with its + * current responsibilities, quickly when possible. + */ + class Cancelable { + public: + + //! Destroy a Cancelable object. + virtual ~Cancelable() {} + + /** + * Canceling a Cancelable object makes a request to disable that object. + * This entails refusing to take on any new responsibility, and completing + * its current responsibilities quickly. + * + * Canceling an object more than once has no effect. + * + * @post The Cancelable object will have permanently transitioned to a + * disabled state; it will now refuse to accept new responsibility. + */ + virtual void cancel() = 0; + + /** + * Determine if a Cancelable object has been canceled. + * + * @return + * - true if cancel() was called prior to this function. + * - false otherwise. + */ + virtual bool isCanceled() = 0; + + }; /* Cancelable */ + + +} // namespace ZThread + +#endif // __ZTCANCELABLE_H__ diff --git a/src/dep/include/zthread/ClassLockable.h b/src/dep/include/zthread/ClassLockable.h new file mode 100644 index 0000000..a10fb49 --- /dev/null +++ b/src/dep/include/zthread/ClassLockable.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCLASSLOCKABLE_H__ +#define __ZTCLASSLOCKABLE_H__ + +#include "zthread/CountedPtr.h" +#include "zthread/Mutex.h" + +namespace ZThread { + + /** + * @class ClassLockable + * + * @author Eric Crahen + * @date <2003-07-16T23:37:38-0400> + * @version 2.3.0 + * + * + */ + template + class ClassLockable : public Lockable { + + static CountedPtr _instance; + CountedPtr _lock; + + public: + + //! Create a ClassLockable + ClassLockable() + : _lock(_instance) {} + + //! acquire() the ClassLockable + virtual void acquire() { + _lock->acquire(); + } + + //! tryAcquire() the ClassLockable + virtual bool tryAcquire(unsigned long timeout) { + return _lock->tryAcquire(timeout); + } + + //! release() the ClassLockable + virtual void release() { + _lock->release(); + } + + }; + + template + CountedPtr ClassLockable::_instance(new LockType); + +} // namespace ZThread + +#endif // __ZTCLASSLOCKABLE_H__ diff --git a/src/dep/include/zthread/ConcurrentExecutor.h b/src/dep/include/zthread/ConcurrentExecutor.h new file mode 100644 index 0000000..199fe30 --- /dev/null +++ b/src/dep/include/zthread/ConcurrentExecutor.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCONCURRENTEXECUTOR_H__ +#define __ZTCONCURRENTEXECUTOR_H__ + +#include "zthread/PoolExecutor.h" + +namespace ZThread { + + /** + * @class ConcurrentExecutor + * + * @author Eric Crahen + * @date <2003-07-16T22:36:11-0400> + * @version 2.3.0 + * + * A ConcurrentExecutor spawns a single thread to service a series of Tasks. + * + * @see PoolExecutor. + */ + class ConcurrentExecutor : public Executor { + + PoolExecutor _executor; + + public: + + //! Create a ConcurrentExecutor + ConcurrentExecutor(); + + /** + * Interrupting a ConcurrentExecutor will cause the thread running the tasks to be + * be interrupted once during the execution of each task that has been submitted + * at the time this function is called. + * + * Tasks that are submitted after this function is called will + * not be interrupt()ed; unless this function is invoked again(). + * + * @code + * + * void aFunction() { + * + * ConcurrentExecutor executor; + * + * // Submit p Tasks + * for(size_t n = 0; n < p; n++) + * executor.execute(new aRunnable); + * + * // Tasks [m, p) may be interrupted, where m is the first task that has + * // not completed at the time the interrupt() is invoked. + * executor.interrupt(); + * + * // Submit (q - p) Tasks + * for(size_t n = p; n < q; n++) + * executor.execute(new Chore); + * + * // Tasks [p, q) are not interrupted + * + * } + * + * @endcode + */ + virtual void interrupt(); + + /** + * Submit a Task to this Executor. This will not block the current thread + * for very long. The task will be enqueued internally and eventually run + * in the context of the single thread driving all the Tasks submitted to this + * Executor. + * + * @exception Cancellation_Exception thrown if this Executor has been canceled. + * The Task being submitted will not be executed by this Executor. + * + * @exception Synchronization_Exception thrown only in the event of an error + * in the implementation of the library. + * + * @see Executor::execute(const Task&) + */ + virtual void execute(const Task&); + + /** + * @see Cancelable::cancel() + */ + virtual void cancel(); + + /** + * @see Cancelable::isCanceled() + */ + virtual bool isCanceled(); + + /** + * @see PoolExecutor::wait() + */ + virtual void wait(); + + /** + * @see PoolExecutor::wait(unsigned long timeout) + */ + virtual bool wait(unsigned long timeout); + + }; /* ConcurrentExecutor */ + +} // namespace ZThread + +#endif // __ZTCONCURRENTEXECUTOR_H__ diff --git a/src/dep/include/zthread/Condition.h b/src/dep/include/zthread/Condition.h new file mode 100644 index 0000000..eba9361 --- /dev/null +++ b/src/dep/include/zthread/Condition.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCONDITION_H__ +#define __ZTCONDITION_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" +#include "zthread/Waitable.h" + +namespace ZThread { + + class FifoConditionImpl; + + /** + * @class Condition + * @author Eric Crahen + * @date <2003-07-16T14:38:59-0400> + * @version 2.2.1 + * + * A Condition is a Waitable object used to block a thread until a particular + * condition is met. A Condition object is always used in conjunction with Lockable + * object. This object should be a FastMutex, Mutex, PriorityMutex or PriorityInheritanceMutex. + * + * Condition objects are reminiscent of POSIX condition variables in several ways but + * are slightly different. + * + * A Condition is not subject to spurious wakeup. + * + * Like all Waitable objects, Conditions are sensitive to Thread::interupt() which can + * be used to prematurely end a wait(). + * + * @see Thread::interupt() + * + * Before a wait() is performed on a Condition, the associated Lockable object should + * have been acquire()ed. When the wait() begins, that Lockable object is release()d + * (wait() will atomically begin the wait and unlock the Lockable). + * + * A thread blocked by wait() will remain so until an exception occurs, or until + * the thread awakened by a signal() or broadcast(). When the thread resumes execution, + * the associated Lockable is acquire()d before wait() returns. + * + * Scheduling + * + * Threads blocked on a Condition are resumed in FIFO order. + */ + class ZTHREAD_API Condition : public Waitable, private NonCopyable { + + FifoConditionImpl* _impl; + + public: + + /** + * Create a Condition associated with the given Lockable object. + * + * @param l Lockable object to associate with this Condition object. + */ + Condition(Lockable& l); + + //! Destroy Condition object + virtual ~Condition(); + + /** + * Wake one thread waiting on this Condition. + * + * The associated Lockable need not have been acquire when this function is + * invoked. + * + * @post a waiting thread, if any exists, will be awakened. + */ + void signal(); + + /** + * Wake all threads wait()ing on this Condition. + * + * The associated Lockable need not have been acquire when this function is + * invoked. + * + * @post all wait()ing threads, if any exist, will be awakened. + */ + void broadcast(); + + /** + * Wait for this Condition, blocking the calling thread until a signal or broadcast + * is received. + * + * This operation atomically releases the associated Lockable and blocks the calling thread. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @pre The thread calling this method must have first acquired the associated + * Lockable object. + * + * @post A thread that has resumed execution without exception (because of a signal(), + * broadcast() or exception) will have acquire()d the associated Lockable object + * before returning from a wait(). + * + * @see Waitable::wait() + */ + virtual void wait(); + + /** + * Wait for this Condition, blocking the calling thread until a signal or broadcast + * is received. + * + * This operation atomically releases the associated Lockable and blocks the calling thread. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * + * @return + * - true if the Condition receives a signal or broadcast before + * timeout milliseconds elapse. + * - false otherwise. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @pre The thread calling this method must have first acquired the associated + * Lockable object. + * + * @post A thread that has resumed execution without exception (because of a signal(), + * broadcast() or exception) will have acquire()d the associated Lockable object + * before returning from a wait(). + * + * @see Waitable::wait(unsigned long timeout) + */ + virtual bool wait(unsigned long timeout); + + + }; + +} // namespace ZThread + +#endif // __ZTCONDITION_H__ diff --git a/src/dep/include/zthread/Config.h b/src/dep/include/zthread/Config.h new file mode 100644 index 0000000..21e08bf --- /dev/null +++ b/src/dep/include/zthread/Config.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCONFIG_H__ +#define __ZTCONFIG_H__ + +// ===================================================================================== +// The following section describes the symbols the configure program will define. +// If you are not using configure (autoconf), then you make want to set these by +// uncommenting them here, or whatever other means you'd like. +// ===================================================================================== + +// (configure) +// Uncomment to disable actually changing the operating systems real thread priority +// #define ZTHREAD_DISABLE_PRIORITY 1 + +// (configure) +// Uncomment to disable compiling the interrupt() hook mechanisms. +// #define ZTHREAD_DISABLE_INTERRUPT 1 + +// (configure) +// Uncomment to select a Win32 ThreadOps implementation that uses _beginthreadex() +// otherwise, CreateThread() will be used for a Windows compilation +// #define HAVE_BEGINTHREADEX 1 + +// (configure) +// Uncomment to select a pthreads based implementation +// #define ZT_POSIX 1 + +// (configure) +// Uncomment to select a Windows based implementation that uses features not +// supported by windows 98 and 95 +// #define ZT_WIN32 1 + +// (configure) +// Uncomment to select a Windows based implementation that does not use features not +// supported by windows 98 and 95, but may not be compatible with 64 bit or alpha systems +// #define ZT_WIN9X 1 + +// (configure) +// Uncomment to select a MacOS based implementation +// #define ZT_MACOS 1 + +// (configure) +// Uncomment to prefer vanilla implementations of primatives when possible +// #define ZT_VANILLA 1 + +// ===================================================================================== +// The following section can be customized to select the implementation that is compiled +// Eventually, the configure program will be updated to define these symbols as well. +// ===================================================================================== + +// Uncomment to select very simple spinlock based implementations +// #define ZTHREAD_USE_SPIN_LOCKS 1 + +// Uncomment to select the vannila dual mutex implementation of FastRecursiveLock +// #define ZTHREAD_DUAL_LOCKS 1 + +// Uncomment to select a POSIX implementation of FastRecursiveLock that does not +// spin, but instead sleeps on a condition variable. +// #define ZTHREAD_CONDITION_LOCKS 1 + +// Uncomment if you want to eliminate inlined code used as a part of some template classes +// #define ZTHREAD_NOINLINE + +// Uncomment if you want to compile a DLL version of the library. (Win32) +// #define ZTHREAD_EXPORTS 1 + +// Uncomment if you want to compile a client using the DLL version of the library. (Win32) +// #define ZTHREAD_IMPORTS 1 + +// =================================================================================== +// The following section will attempt to guess the best configuration for your system +// =================================================================================== + +// Select an implementation by checking out the environment, first looking for +// compilers, then by looking for other definitions that could be present + +#if !defined(ZT_POSIX) && !defined(ZT_WIN9X) && !defined(ZT_WIN32) && !defined(ZT_MACOS) + +// Check for well known compilers +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__BCPLUSPLUS__) || defined(__MINGW32__) + +# define ZT_WIN32 + +#elif defined(__CYGWIN__) + +# define ZT_POSIX + +// Check for well known platforms +#elif defined(__linux__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__hpux) || \ + defined(__sgi) || \ + defined(__sun) + +# define ZT_POSIX + +// Check for definitions from well known headers +#elif defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE) + +# define ZT_POSIX + +#elif defined(WIN32_LEAN_AND_MEAN) + +# define ZT_WIN32 + +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + +# define ZT_MACOS + +#else +# error "Could not select implementation, define ZT_WIN9X, ZT_WIN32, ZT_POSIX or ZT_MACOS" +#endif + +#endif + +// Once an implementation has been selected, configure the API decorator +// for shared libraries if its needed. + +#if defined(ZTHREAD_SHARED) // Compatibility w/ past releases + +# define ZTHREAD_IMPORTS + +#elif defined(ZTHREAD_STATIC) + +# undef ZTHREAD_EXPORTS +# undef ZTHREAD_IMPORTS + +#endif + +// Windows users will get a static build by default, unless they +// define either ZTHREAD_IMPORTS or ZTHREAD_EXPORTS. Client code +// of a dll version of this library should define the first flag; +// To build the dll version of this library, define the second. + +#if defined(ZTHREAD_IMPORTS) && defined(ZTHREAD_EXPORTS) +# error "Import and export declarations are not valid" +#else + +# if defined(ZTHREAD_IMPORTS) +# define ZTHREAD_API __declspec(dllimport) +# elif defined(ZTHREAD_EXPORTS) +# define ZTHREAD_API __declspec(dllexport) +# else +# define ZTHREAD_API +# endif + +#endif + +// Once the API decorator is configured, create a macro for +// explicit template instantiation (whose need can hopefully +// be removed from the library) + +#if defined(ZTHREAD_EXPORTS) +# define EXPLICIT_TEMPLATE(X) template class __declspec( dllexport ) X; +#elif defined(ZTHREAD_IMPORTS) +# define EXPLICIT_TEMPLATE(X) template class __declspec( dllimport ) X; +#else +# define EXPLICIT_TEMPLATE(X) +#endif + +// Give libc a hint, should be defined by the user - but people tend +// to forget. + +#if !defined(REENTRANT) +# define REENTRANT +#endif + +#if !defined(_REENTRANT) +# define _REENTRANT +#endif + +#if defined(_MSC_VER) +# pragma warning(disable:4275) +# pragma warning(disable:4290) +# pragma warning(disable:4786) +# pragma warning(disable:4251) +# pragma warning(disable:4355) +#endif + +// Ensure that only one implementation is selected +#if \ +(defined(ZT_POSIX) && defined(ZT_WIN32)) \ + || (defined(ZT_POSIX) && defined(ZT_WIN9X)) \ + || (defined(ZT_WIN32) && defined(ZT_WIN9X)) + +# error "Only one implementation should be selected!" + +#endif + +#if defined(ZTHREAD_NOINLINE) +# define ZTHREAD_INLINE +#else +# define ZTHREAD_INLINE inline +#endif + +#endif // __ZTCONFIG_H__ + diff --git a/src/dep/include/zthread/CountedPtr.h b/src/dep/include/zthread/CountedPtr.h new file mode 100644 index 0000000..a4dcc6e --- /dev/null +++ b/src/dep/include/zthread/CountedPtr.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCOUNTEDPTR_H__ +#define __ZTCOUNTEDPTR_H__ + +#include +#include + +#include "zthread/AtomicCount.h" + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4786) // warning: long template symbol name +# pragma warning(push) +# pragma warning(disable:4284) // warning: odd return type for operator-> +#endif + +namespace ZThread { + + /** + * @class CountedPtr + * + * @author Eric Crahen + * @date <2003-07-29T06:43:48-0400> + * @version 2.3.0 + * + */ + template + class CountedPtr { + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + template friend class CountedPtr; +#endif +#endif + + CountT* _count; + T* _instance; + + public: + + CountedPtr() : _count(0), _instance(0) { } + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + explicit CountedPtr(T* raw) : _count(new CountT()), _instance(raw) { + (*_count)++; + } + +#endif +#endif + + template + explicit CountedPtr(U* raw) : _count(new CountT()), _instance(raw) { + (*_count)++; + } + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + CountedPtr(const CountedPtr& ptr) : _count(ptr._count), _instance(ptr._instance) { + + if(_count) + (*_count)++; + + } + +#endif +#endif + + template + CountedPtr(const CountedPtr& ptr) : _count(ptr._count), _instance(ptr._instance) { + + if(_count) + (*_count)++; + + } + + ~CountedPtr() { + + if(_count && --(*_count) == 0) { + + if(_instance) + delete _instance; + + delete _count; + + } + + } + + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + const CountedPtr& operator=(const CountedPtr& ptr) { + + typedef CountedPtr ThisT; + + ThisT(ptr).swap(*this); + return *this; + + } + +#endif +#endif + + template + const CountedPtr& operator=(const CountedPtr& ptr) { + + typedef CountedPtr ThisT; + + ThisT(ptr).swap(*this); + return *this; + + } + + void reset() { + + typedef CountedPtr ThisT; + ThisT().swap(*this); + + } + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + void swap(CountedPtr& ptr) { + + std::swap(_count, ptr._count); + std::swap(_instance, ptr._instance); + + } + +#endif +#endif + + template + void swap(CountedPtr& ptr) { + + std::swap(_count, ptr._count); + std::swap(_instance, ptr._instance); + + } + + // Convience operators + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + bool less(const CountedPtr& ptr) const { + return _instance < ptr._instance; + } + +#endif +#endif + + template + bool less(const CountedPtr& ptr) const { + return _instance < ptr._instance; + } + + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + bool equal(const CountedPtr& ptr) const { + return _count == ptr._count; + } + +#endif +#endif + + template + bool equal(const CountedPtr& ptr) const { + return _count == ptr._count; + } + + + friend inline bool operator==(const CountedPtr& lhs, const CountedPtr& rhs) { + return lhs.equal(rhs); + } + + friend inline bool operator<(const CountedPtr& lhs, const CountedPtr& rhs) { + return lhs.less(rhs); + } + + + T& operator*() { + assert(_instance != 0); + return *_instance; + } + + T* operator->() { + assert(_instance != 0); + return _instance; + } + + const T* operator->() const { + assert(_instance != 0); + return _instance; + } + + bool operator!() const { + return _instance == 0; + } + + operator bool() const { + return _instance != 0; + } + + }; /* CountedPtr */ + + template + inline bool operator<(CountedPtr const &lhs, CountedPtr const &rhs) { + return lhs.less(rhs); + } + + template + inline bool operator==(CountedPtr const &lhs, CountedPtr const &rhs) { + return lhs.equal(rhs.get); + } + + template + inline bool operator!=(CountedPtr const &lhs, CountedPtr const &rhs) { + return !(lhs.equal(rhs.get)); + } + + template + inline void swap(CountedPtr const &lhs, CountedPtr const &rhs) { + lhs.swap(rhs); + } + +#if !defined(__MWERKS__) +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + template + inline bool operator<(CountedPtr const &lhs, CountedPtr const &rhs) { + return lhs.less(rhs); + } + + template + inline bool operator==(CountedPtr const &lhs, CountedPtr const &rhs) { + return lhs.equal(rhs.get); + } + + template + inline bool operator!=(CountedPtr const &lhs, CountedPtr const &rhs) { + return !(lhs.equal(rhs.get)); + } + + template + inline void swap(CountedPtr const &lhs, CountedPtr const &rhs) { + lhs.swap(rhs); + } + +#endif +#endif + +} // namespace ZThread + +#ifdef _MSC_VER +# pragma warning(pop) +# pragma warning(pop) +#endif + + +#endif // __ZTCOUNTEDPTR_H__ diff --git a/src/dep/include/zthread/CountingSemaphore.h b/src/dep/include/zthread/CountingSemaphore.h new file mode 100644 index 0000000..f580a65 --- /dev/null +++ b/src/dep/include/zthread/CountingSemaphore.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCOUNTINGSEMAPHORE_H__ +#define __ZTCOUNTINGSEMAPHORE_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class FifoSemaphoreImpl; + + /** + * @class CountingSemaphore + * @author Eric Crahen + * @date <2003-07-16T15:26:18-0400> + * @version 2.2.1 + * + * A CountingSemaphore is an owner-less Lockable object. + * + * It differs from a normal Semaphore in that there is no upper bound on the count + * and it will not throw an exception because a maximum value has been exceeded. + * + * @see Semaphore + * + * Threads blocked on a CountingSemaphore are resumed in FIFO order. + */ + class ZTHREAD_API CountingSemaphore : public Lockable, private NonCopyable { + + FifoSemaphoreImpl* _impl; + + public: + + /** + * Create a new CountingSemaphore. + * + * @param count - initial count + */ + CountingSemaphore(int initialCount = 0); + + //! Destroy the CountingSemaphore + virtual ~CountingSemaphore(); + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see acquire() + */ + void wait(); + + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see tryAcquire(unsigned long timeout) + */ + bool tryWait(unsigned long timeout); + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see release() + */ + void post(); + + + /** + * Get the current count of the semaphore. + * + * This value may change immediately after this function returns to the calling thread. + * + * @return int count + */ + virtual int count(); + + /** + * Decrement the count, blocking that calling thread if the count becomes 0 or + * less than 0. The calling thread will remain blocked until the count is + * raised above 0, an exception is thrown or the given amount of time expires. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * + * @return + * - true if the Semaphore was acquired before timeout milliseconds elapse. + * - false otherwise. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @see Lockable::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + /** + * Decrement the count, blocking that calling thread if the count becomes 0 or + * less than 0. The calling thread will remain blocked until the count is + * raised above 0 or if an exception is thrown. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @see Lockable::acquire() + */ + virtual void acquire(); + + /** + * Increment the count, unblocking one thread if count is positive. + * + * @see Lockable::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTCOUNTINGSEMAPHORE_H__ diff --git a/src/dep/include/zthread/Exceptions.h b/src/dep/include/zthread/Exceptions.h new file mode 100644 index 0000000..b720793 --- /dev/null +++ b/src/dep/include/zthread/Exceptions.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTEXCEPTIONS_H__ +#define __ZTEXCEPTIONS_H__ + + +#include "zthread/Config.h" +#include + +namespace ZThread { + +/** + * @class Synchronization_Exception + * + * Serves as a general base class for the Exception hierarchy used within + * this package. + * + */ +class Synchronization_Exception { + + // Restrict heap allocation + static void * operator new(size_t size); + static void * operator new[](size_t size); + + std::string _msg; + +public: + + /** + * Create a new exception with a default error message 'Synchronization + * Exception' + */ + Synchronization_Exception() : _msg("Synchronization exception") { } + + /** + * Create a new exception with a given error message + * + * @param const char* - error message + */ + Synchronization_Exception(const char* msg) : _msg(msg) { } + + /** + * Get additional info about the exception + * + * @return const char* for the error message + */ + const char* what() const { + return _msg.c_str(); + } + +}; + + +/** + * @class Interrupted_Exception + * + * Used to describe an interrupted operation that would have normally + * blocked the calling thread + */ +class Interrupted_Exception : public Synchronization_Exception { + + public: + + //! Create a new exception + Interrupted_Exception() : Synchronization_Exception("Thread interrupted") { } + + //! Create a new exception + Interrupted_Exception(const char* msg) : Synchronization_Exception(msg) { } + +}; + + + +/** + * @class Deadlock_Exception + * + * Thrown when deadlock has been detected + */ +class Deadlock_Exception : public Synchronization_Exception { + public: + + //! Create a new exception + Deadlock_Exception() : Synchronization_Exception("Deadlock detected") { } + + //! Create a new exception + Deadlock_Exception(const char* msg) : Synchronization_Exception(msg) { } + +}; + + +/** + * @class InvalidOp_Exception + * + * Thrown when performing an illegal operation this object + */ +class InvalidOp_Exception : public Synchronization_Exception { + public: + + //! Create a new exception + InvalidOp_Exception() : Synchronization_Exception("Invalid operation") { } + //! Create a new exception + InvalidOp_Exception(const char* msg) : Synchronization_Exception(msg) { } + +}; + + + +/** + * @class Initialization_Exception + * + * Thrown when the system has no more resources to create new + * synchronization controls + */ +class Initialization_Exception : public Synchronization_Exception { + + public: + + //! Create a new exception + Initialization_Exception() : Synchronization_Exception("Initialization error") { } + //! Create a new exception + Initialization_Exception(const char*msg) : Synchronization_Exception(msg) { } + +}; + +/** + * @class Cancellation_Exception + * + * Cancellation_Exceptions are thrown by 'Canceled' objects. + * @see Cancelable + */ +class Cancellation_Exception : public Synchronization_Exception { + + public: + + //! Create a new Cancelltion_Exception + Cancellation_Exception() : Synchronization_Exception("Canceled") { } + //! Create a new Cancelltion_Exception + Cancellation_Exception(const char*msg) : Synchronization_Exception(msg) { } + +}; + + +/** + * @class Timeout_Exception + * + * There is no need for error messaged simply indicates the last + * operation timed out + */ +class Timeout_Exception : public Synchronization_Exception { + public: + + //! Create a new Timeout_Exception + Timeout_Exception() : Synchronization_Exception("Timeout") { } + //! Create a new + Timeout_Exception(const char*msg) : Synchronization_Exception(msg) { } + +}; + +/** + * @class NoSuchElement_Exception + * + * The last operation that was attempted on a Queue could not find + * the item that was indicated (during that last Queue method invocation) + */ +class NoSuchElement_Exception { + public: + + //! Create a new exception + NoSuchElement_Exception() {} + +}; + +/** + * @class InvalidTask_Exception + * + * Thrown when a task is not valid (e.g. null or start()ing a thread with + * no overriden run() method) + */ +class InvalidTask_Exception : public InvalidOp_Exception { + public: + + //! Create a new exception + InvalidTask_Exception() : InvalidOp_Exception("Invalid task") {} + +}; + +/** + * @class BrokenBarrier_Exception + * + * Thrown when a Barrier is broken because one of the participating threads + * has been interrupted. + */ +class BrokenBarrier_Exception : public Synchronization_Exception { + + public: + + //! Create a new exception + BrokenBarrier_Exception() : Synchronization_Exception("Barrier broken") { } + + //! Create a new exception + BrokenBarrier_Exception(const char* msg) : Synchronization_Exception(msg) { } + +}; + +/** + * @class Future_Exception + * + * Thrown when there is an error using a Future. + */ +class Future_Exception : public Synchronization_Exception { + + public: + + //! Create a new exception + Future_Exception() : Synchronization_Exception() { } + + //! Create a new exception + Future_Exception(const char* msg) : Synchronization_Exception(msg) { } + +}; + +}; + +#endif // __ZTEXCEPTIONS_H__ diff --git a/src/dep/include/zthread/Executor.h b/src/dep/include/zthread/Executor.h new file mode 100644 index 0000000..833d0d4 --- /dev/null +++ b/src/dep/include/zthread/Executor.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTEXECUTOR_H__ +#define __ZTEXECUTOR_H__ + +#include "zthread/Thread.h" +#include "zthread/Waitable.h" + +namespace ZThread { + + + /** + * @class Executor + * + * @author Eric Crahen + * @date <2003-07-16T22:39:39-0400> + * @version 2.3.0 + * + * Execeutors are an implementation of the Executor pattern. This is + * a more versatile construct than a thread pool. A paper describing can + * be found in the proceedings of the 2002 VikingPLOP conference. + * + * Executing + * + * - execute()ing task with an Executor will submit the task, scheduling + * it for execution at some future time depending on the Executor being used. + * + * Disabling + * + * - cancel()ing an Executor will cause it to stop accepting + * new tasks. + * + * Interrupting + * + * - interrupt()ing an Executor will cause the any thread running + * a task which was submitted prior to the invocation of this function to + * be interrupted during the execution of that task. + * + * Waiting + * + * - wait()ing on a PoolExecutor will block the calling thread + * until all tasks that were submitted prior to the invocation of this function + * have completed. + * + * @see Cancelable + * @see Waitable + */ + class Executor : public Cancelable, public Waitable, private NonCopyable { + public: + + /** + * If supported by the Executor, interrupt all tasks submitted prior to + * the invocation of this function. + */ + virtual void interrupt() = 0; + + /** + * Submit a task to this Executor. + * + * @param task Task to be run by a thread managed by this executor + * + * @pre The Executor should have been canceled prior to this invocation. + * @post The submitted task will be run at some point in the future by this Executor. + * + * @exception Cancellation_Exception thrown if the Executor was canceled prior to + * the invocation of this function. + */ + virtual void execute(const Task& task) = 0; + + }; + +} // namespace ZThread + +#endif // __ZTEXECUTOR_H__ diff --git a/src/dep/include/zthread/FairReadWriteLock.h b/src/dep/include/zthread/FairReadWriteLock.h new file mode 100644 index 0000000..8f183b6 --- /dev/null +++ b/src/dep/include/zthread/FairReadWriteLock.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFAIRREADWRITELOCK_H__ +#define __ZTFAIRREADWRITELOCK_H__ + +#include "zthread/ReadWriteLock.h" +#include "zthread/Condition.h" +#include "zthread/Guard.h" +#include "zthread/Mutex.h" + +namespace ZThread { + + /** + * @class FairReadWriteLock + * + * @author Eric Crahen + * @date <2003-07-16T10:26:25-0400> + * @version 2.2.7 + * + * A FairReadWriteLock maintains a balance between the order read-only access + * and read-write access is allowed. Threads contending for the pair of Lockable + * objects this ReadWriteLock provides will gain access to the locks in FIFO order. + * + * @see ReadWriteLock + */ + class FairReadWriteLock : public ReadWriteLock { + + Mutex _lock; + Condition _cond; + + volatile int _readers; + + //! @class ReadLock + class ReadLock : public Lockable { + + FairReadWriteLock& _rwlock; + + public: + + ReadLock(FairReadWriteLock& rwlock) : _rwlock(rwlock) {} + + virtual ~ReadLock() {} + + virtual void acquire() { + + Guard g(_rwlock._lock); + ++_rwlock._readers; + + } + + virtual bool tryAcquire(unsigned long timeout) { + + if(!_rwlock._lock.tryAcquire(timeout)) + return false; + + ++_rwlock._readers; + _rwlock._lock.release(); + + return true; + } + + virtual void release() { + + Guard g(_rwlock._lock); + --_rwlock._readers; + + if(_rwlock._readers == 0) + _rwlock._cond.signal(); + + } + + }; + + //! @class WriteLock + class WriteLock : public Lockable { + + FairReadWriteLock& _rwlock; + + public: + + WriteLock(FairReadWriteLock& rwlock) : _rwlock(rwlock) {} + + virtual ~WriteLock() {} + + virtual void acquire() { + + _rwlock._lock.acquire(); + + try { + + while(_rwlock._readers > 0) + _rwlock._cond.wait(); + + } catch(...) { + + _rwlock._lock.release(); + throw; + + } + + } + + virtual bool tryAcquire(unsigned long timeout) { + + if(!_rwlock._lock.tryAcquire(timeout)) + return false; + + try { + + while(_rwlock._readers > 0) + _rwlock._cond.wait(timeout); + + } catch(...) { + + _rwlock._lock.release(); + throw; + + } + + return true; + + } + + virtual void release() { + _rwlock._lock.release(); + } + + }; + + friend class ReadLock; + friend class WriteLock; + + ReadLock _rlock; + WriteLock _wlock; + + public: + + /** + * Create a BiasedReadWriteLock + * + * @exception Initialization_Exception thrown if resources could not be + * allocated for this object. + */ + FairReadWriteLock() : _cond(_lock), _readers(0), _rlock(*this), _wlock(*this) {} + + //! Destroy this ReadWriteLock + virtual ~FairReadWriteLock() {} + + /** + * @see ReadWriteLock::getReadLock() + */ + virtual Lockable& getReadLock() { return _rlock; } + + /** + * @see ReadWriteLock::getWriteLock() + */ + virtual Lockable& getWriteLock() { return _wlock; } + + }; + +}; // __ZTFAIRREADWRITELOCK_H__ + +#endif diff --git a/src/dep/include/zthread/FastMutex.h b/src/dep/include/zthread/FastMutex.h new file mode 100644 index 0000000..1812c3e --- /dev/null +++ b/src/dep/include/zthread/FastMutex.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTMUTEX_H__ +#define __ZTFASTMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class FastLock; + + /** + * @class FastMutex + * @author Eric Crahen + * @date <2003-07-19T18:45:39-0400> + * @version 2.2.0 + * + * A FastMutex is a small fast implementation of a non-recursive, mutually exclusive + * Lockable object. This implementation is a bit faster than the other Mutex classes + * as it involved the least overhead. However, this slight increase in speed is + * gained by sacrificing the robustness provided by the other classes. + * + * A FastMutex has the useful property of not being interruptable; that is to say + * that acquire() and tryAcquire() will not throw Interrupted_Exceptions. + * + * @see Mutex + * + * Scheduling + * + * Scheduling is left to the operating systems and may vary. + * + * Error Checking + * + * No error checking is performed, this means there is the potential for deadlock. + */ + class ZTHREAD_API FastMutex : public Lockable, private NonCopyable { + + FastLock* _lock; + + public: + + //! Create a FastMutex + FastMutex(); + + //! Destroy a FastMutex + virtual ~FastMutex(); + + /** + * Acquire exclusive access to the mutex. The calling thread will block until the + * lock can be acquired. No safety or state checks are performed. + * + * @pre The calling thread should not have previously acquired this lock. + * Deadlock will result if the same thread attempts to acquire the mutex more + * than once. + * + * @post The calling thread obtains the lock successfully if no exception is thrown. + * @exception Interrupted_Exception never thrown + */ + virtual void acquire(); + + /** + * Release exclusive access. No safety or state checks are performed. + * + * @pre the caller should have previously acquired this lock + */ + virtual void release(); + + /** + * Try to acquire exclusive access to the mutex. The calling thread will block until the + * lock can be acquired. No safety or state checks are performed. + * + * @pre The calling thread should not have previously acquired this lock. + * Deadlock will result if the same thread attempts to acquire the mutex more + * than once. + * + * @param timeout unused + * @return + * - true if the lock was acquired + * - false if the lock was acquired + * + * @post The calling thread obtains the lock successfully if no exception is thrown. + * @exception Interrupted_Exception never thrown + */ + virtual bool tryAcquire(unsigned long timeout); + + }; /* FastMutex */ + +}; + +#endif // __ZTFASTMUTEX_H__ diff --git a/src/dep/include/zthread/FastRecursiveMutex.h b/src/dep/include/zthread/FastRecursiveMutex.h new file mode 100644 index 0000000..a30f4b5 --- /dev/null +++ b/src/dep/include/zthread/FastRecursiveMutex.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVEMUTEX_H__ +#define __ZTFASTRECURSIVEMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class FastRecursiveLock; + + /** + * @class FastRecursiveMutex + * + * @author Eric Crahen + * @date <2003-07-19T19:00:25-0400> + * @version 2.2.0 + * + * A FastRecursiveMutex is a small fast implementation of a recursive, mutally exclusive + * Lockable object. This implementation is a bit faster than the other Mutex classes + * as it involved the least overhead. However, this slight increase in speed is + * gained by sacrificing the robustness provided by the other classes. + * + * A FastRecursiveMutex has the useful property of not being interruptable; that is to say + * that acquire() and tryAcquire() will not throw Interrupted_Exceptions. + * + * @see RecursiveMutex + * + * Scheduling + * + * Scheduling is left to the operating systems and may vary. + * + * Error Checking + * + * No error checking is performed, this means there is the potential for deadlock. + */ + class ZTHREAD_API FastRecursiveMutex : public Lockable, private NonCopyable { + + FastRecursiveLock* _lock; + + public: + + //! Create a new FastRecursiveMutex + FastRecursiveMutex(); + + //! Destroy this FastRecursiveMutex + virtual ~FastRecursiveMutex(); + + /** + * Acquire exclusive access to the mutex. The calling thread will block until the + * lock can be acquired. No safety or state checks are performed. The calling thread + * may acquire the mutex nore than once. + * + * @post The calling thread obtains the lock successfully if no exception is thrown. + * @exception Interrupted_Exception never thrown + */ + virtual void acquire(); + + /** + * Release access. No safety or state checks are performed. + * + * @pre the caller should have previously acquired this lock at least once. + */ + virtual void release(); + + /** + * Try to acquire exclusive access to the mutex. The calling thread will block until the + * lock can be acquired. No safety or state checks are performed. The calling thread + * may acquire the mutex more than once. + * + * @param timeout unused + * @return + * - true if the lock was acquired + * - false if the lock was acquired + * + * @post The calling thread obtains the lock successfully if no exception is thrown. + * @exception Interrupted_Exception never thrown + */ + virtual bool tryAcquire(unsigned long timeout); + + }; + +} // namespace ZThread + +#endif // __ZTFASTRECURSIVEMUTEX_H__ diff --git a/src/dep/include/zthread/Guard.h b/src/dep/include/zthread/Guard.h new file mode 100644 index 0000000..04f265c --- /dev/null +++ b/src/dep/include/zthread/Guard.h @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTGUARD_H__ +#define __ZTGUARD_H__ + +#include "zthread/NonCopyable.h" +#include "zthread/Exceptions.h" + +namespace ZThread { + +// +// GuardLockingPolicyContract { +// +// createScope(lock_type&) +// bool createScope(lock_type&, unsigned long) +// destroyScope(lock_type&) +// +// } +// + +/** + * @class LockHolder + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * This is a simple base class for Guards class. It allows Guards + * that have compatible targets to refer to each others targets + * allowing for the construction of Guards that share the same lock + * but have different locking policies. + */ +template +class LockHolder { + + LockType &_lock; + bool _enabled; + + public: + + template + LockHolder(T& t) : _lock(extract(t)._lock), _enabled(true) { } + + LockHolder(LockHolder& holder) : _lock(holder._lock), _enabled(true) { } + + LockHolder(LockType& lock) : _lock(lock), _enabled(true) { } + + void disable() { + _enabled = false; + } + + bool isDisabled() { + return !_enabled; + } + + LockType& getLock() { + return _lock; + } + + protected: + + template + static LockHolder& extract(T& t) { + // Design and Evolution of C++, page 328 + return (LockHolder&)(t); + } + +}; + +/** + * @class CompoundScope + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Locking policy that aggregates two policies that share a target. + * It is not appropriate to use with any type of OverlappedScope + */ +template +class CompoundScope { + public: + + template + static void createScope(LockHolder& l) { + + Scope1::createScope(l); + Scope2::createScope(l); + + } + + template + static void createScope(LockHolder& l, unsigned long ms) { + + if(Scope1::createScope(l, ms)) + if(!Scope2::createScope(l, ms)) { + + Scope1::destroyScope(l); + return false; + + } + + return true; + + } + + template + static void destroyScope(LockHolder& l) { + + Scope1::destroyScope(l); + Scope2::destroyScope(l); + + } + +}; + + +/** + * @class LockedScope + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Locking policy for Lockable objects. This policy acquire()s a Lockable + * when the protection scope is created, and it release()s a Lockable + * when the scope is destroyed. + */ +class LockedScope { + public: + + /** + * A new protection scope is being created by l2, using an existing scope + * created by l1. + * + * @param lock1 LockType1& is the LockHolder that holds the desired lock + * @param lock2 LockType1& is the LockHolder that wants to share + template + static void shareScope(LockHolder& l1, LockHolder& l2) { + + l2.getLock().acquire(); + + } + */ + + /** + * A new protection scope is being created. + * + * @param lock LockType& is a type of LockHolder. + */ + template + static bool createScope(LockHolder& l, unsigned long ms) { + + return l.getLock().tryAcquire(ms); + + } + + /** + * A new protection scope is being created. + * + * @param lock LockType& is a type of LockHolder. + */ + template + static void createScope(LockHolder& l) { + + l.getLock().acquire(); + + } + + /** + * A protection scope is being destroyed. + * + * @param lock LockType& is a type of LockHolder. + */ + template + static void destroyScope(LockHolder& l) { + + l.getLock().release(); + + } + +}; + + +/** + * @class UnlockedScope + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Locking policy for Lockable objects. This policy release()s a Lockable + * when the protection scope is created, and it acquire()s a Lockable + * when the scope is destroyed. + */ +class UnlockedScope { + public: + + /** + * A new protection scope is being created by l2, using an existing scope + * created by l1. + * + * @param lock1 LockType1& is the LockHolder that holds the desired lock + * @param lock2 LockType1& is the LockHolder that wants to share + */ + template + static void shareScope(LockHolder& l1, LockHolder& l2) { + + l2.getLock().release(); + + } + + /** + * A new protection scope is being created. + * + * @param lock LockType& is a type of LockHolder. + template + static void createScope(LockHolder& l) { + + l.getLock().release(); + + } + */ + + /** + * A protection scope is being destroyed. + * + * @param lock LockType& is a type of LockHolder. + */ + template + static void destroyScope(LockHolder& l) { + + l.getLock().acquire(); + + } + +}; + + + +/** + * @class TimedLockedScope + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Locking policy that attempts to enterScope some resource + * in a certain amount of time using an tryEnterScope-relase protocol. + */ +template +class TimedLockedScope { + public: + + /** + * Try to enterScope the given LockHolder. + * + * @param lock LockType& is a type of LockHolder. + */ + template + static void shareScope(LockHolder& l1, LockHolder& l2) { + + if(!l2.getLock().tryAcquire(TimeOut)) + throw Timeout_Exception(); + + } + + template + static void createScope(LockHolder& l) { + + if(!l.getLock().tryAcquire(TimeOut)) + throw Timeout_Exception(); + + } + + template + static void destroyScope(LockHolder& l) { + + l.getLock().release(); + + } + +}; + + +/** + * @class OverlappedScope + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Locking policy allows the effective scope of two locks to overlap + * by releasing and disabling one lock before its Guard does so. + */ +class OverlappedScope { + public: + + template + static void transferScope(LockHolder& l1, LockHolder& l2) { + + l1.getLock().acquire(); + + l2.getLock().release(); + l2.disable(); + + } + + template + static void destroyScope(LockHolder& l) { + + l.getLock().release(); + + } + +}; + + + +/** + * @class Guard + * @author Eric Crahen + * @date <2003-07-16T17:55:42-0400> + * @version 2.2.0 + * + * Scoped locking utility. This template class can be given a Lockable + * synchronization object and can 'Guard' or serialize access to + * that method. + * + * For instance, consider a case in which a class or program have a + * Mutex object associated with it. Access can be serialized with a + * Guard as shown below. + * + * @code + * + * Mutex _mtx; + * void guarded() { + * + * Guard g(_mtx); + * + * } + * + * @endcode + * + * The Guard will lock the synchronization object when it is created and + * automatically unlock it when it goes out of scope. This eliminates + * common mistakes like forgetting to unlock your mutex. + * + * An alternative to the above example would be + * + * @code + * + * void guarded() { + * + * (Guard)(_mtx); + * + * } + * + * @endcode + * + * HOWEVER; using a Guard in this method is dangerous. Depending on your + * compiler an anonymous variable like this can go out of scope immediately + * which can result in unexpected behavior. - This is the case with MSVC + * and was the reason for introducing assertions into the Win32_MutexImpl + * to track this problem down + * + */ +template +class Guard : private LockHolder, private NonCopyable { + + friend class LockHolder; + +public: + + /** + * Create a Guard that enforces a the effective protection scope + * throughout the lifetime of the Guard object or until the protection + * scope is modified by another Guard. + * + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + * @post the protection scope may be ended prematurely + */ + Guard(LockType& lock) : LockHolder(lock) { + + LockingPolicy::createScope(*this); + + }; + + /** + * Create a Guard that enforces a the effective protection scope + * throughout the lifetime of the Guard object or until the protection + * scope is modified by another Guard. + * + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + * @post the protection scope may be ended prematurely + */ + Guard(LockType& lock, unsigned long timeout) : LockHolder(lock) { + + if(!LockingPolicy::createScope(*this, timeout)) + throw Timeout_Exception(); + + }; + + /** + * Create a Guard that shares the effective protection scope + * from the given Guard to this Guard. + * + * @param g Guard guard that is currently enabled + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + */ + template + Guard(Guard& g) : LockHolder(g) { + + LockingPolicy::shareScope(*this, extract(g)); + + } + + /** + * Create a Guard that shares the effective protection scope + * from the given Guard to this Guard. + * + * @param g Guard guard that is currently enabled + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + */ + Guard(Guard& g) : LockHolder(g) { + + LockingPolicy::shareScope(*this, g); + + } + + + /** + * Create a Guard that transfers the effective protection scope + * from the given Guard to this Guard. + * + * @param g Guard guard that is currently enabled + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + */ + template + Guard(Guard& g, LockType& lock) : LockHolder(lock) { + + LockingPolicy::transferScope(*this, extract(g)); + + } + + + /** + * Create a Guard that transfers the effective protection scope + * from the given Guard to this Guard. + * + * @param g Guard guard that is currently enabled + * @param lock LockType the lock this Guard will use to enforce its + * protection scope. + */ + Guard(Guard& g, LockType& lock) : LockHolder(lock) { + + LockingPolicy::transferScope(*this, g); + + } + + + /** + * Unlock a given Lockable object with the destruction of this Guard + */ + ~Guard() throw(); + +}; /* Guard */ + + +template +Guard::~Guard() throw() { + + try { + + if(!this->isDisabled()) + LockingPolicy::destroyScope(*this); + + } catch (...) { /* ignore */ } + +} + + +}; + +#endif // __ZTGUARD_H__ + + + + + + + diff --git a/src/dep/include/zthread/GuardedClass.h b/src/dep/include/zthread/GuardedClass.h new file mode 100644 index 0000000..4ef3879 --- /dev/null +++ b/src/dep/include/zthread/GuardedClass.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __GUARDEDCLASS_H__ +#define __GUARDEDCLASS_H__ + +#include "zthread/Guard.h" +#include "zthread/Mutex.h" + +namespace ZThread { + + /** + * @class GuardedClass + * @author Eric Crahen + * @date <2003-07-20T20:17:34-0400> + * @version 2.3.0 + * + * A simple wrapper template that uses Guard's to provide + * serialized access to an objects member functions. + */ + template + class GuardedClass { + + LockType _lock; + T* _ptr; + + class TransferedScope { + public: + + template + static void shareScope(LockHolder& l1, + LockHolder& l2) { + l1.disable(); + l2.getLock().acquire(); + } + + template + static void createScope(LockHolder& l) { + // Don't acquire the lock when scope the Guard is created + } + + template + static void destroyScope(LockHolder& l) { + l.getLock().release(); + } + + }; + + class Proxy : Guard { + + T* _object; + + public: + + Proxy(LockType& lock, T* object) : + Guard(lock), _object(object) { } + + T* operator->() { + return _object; + } + + }; + + GuardedClass(); + GuardedClass& operator=(const GuardedClass&); + + public: + + GuardedClass(T* ptr) : _ptr(ptr) {} + ~GuardedClass() { + if(_ptr) + delete _ptr; + } + + Proxy operator->() { + Proxy p(_lock, _ptr); + return p; + } + + }; + +} // namespace ZThread + +#endif // __ZTGUARDEDCLASS_H__ diff --git a/src/dep/include/zthread/Lockable.h b/src/dep/include/zthread/Lockable.h new file mode 100644 index 0000000..32f7eed --- /dev/null +++ b/src/dep/include/zthread/Lockable.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTLOCKABLE_H__ +#define __ZTLOCKABLE_H__ + +#include "zthread/Exceptions.h" + +namespace ZThread { + + /** + * @class Lockable + * @author Eric Crahen + * @date <2003-07-16T10:33:32-0400> + * @version 2.3.0 + * + * The Lockable interface defines a common method of adding general acquire-release + * semantics to an object. An acquire-release protocol does not necessarily imply + * exclusive access. + */ + class Lockable { + public: + + //! Destroy a Lockable object. + virtual ~Lockable() {} + + /** + * Acquire the Lockable object. + * + * This method may or may not block the caller for an indefinite amount + * of time. Those details are defined by specializations of this class. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted before + * the operation completes. + * + * @post The Lockable is acquired only if no exception was thrown. + */ + virtual void acquire() = 0; + + /** + * Attempt to acquire the Lockable object. + * + * This method may or may not block the caller for a definite amount + * of time. Those details are defined by specializations of this class; + * however, this method includes a timeout value that can be used to + * limit the maximum amount of time that a specialization could block. + * + * @param timeout - maximum amount of time (milliseconds) this method could block + * + * @return + * - true if the operation completes and the Lockable is acquired before + * the timeout expires. + * - false if the operation times out before the Lockable can be acquired. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted before + * the operation completes. + * + * @post The Lockable is acquired only if no exception was thrown. + */ + virtual bool tryAcquire(unsigned long timeout) = 0; + + /** + * Release the Lockable object. + * + * This method may or may not block the caller for an indefinite amount + * of time. Those details are defined by specializations of this class. + * + * @post The Lockable is released only if no exception was thrown. + */ + virtual void release() = 0; + + }; + + +} // namespace ZThread + +#endif // __ZTLOCKABLE_H__ diff --git a/src/dep/include/zthread/LockedQueue.h b/src/dep/include/zthread/LockedQueue.h new file mode 100644 index 0000000..3d42f65 --- /dev/null +++ b/src/dep/include/zthread/LockedQueue.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTLOCKEDQUEUE_H__ +#define __ZTLOCKEDQUEUE_H__ + +#include "zthread/Guard.h" +#include "zthread/Queue.h" + +#include + +namespace ZThread { + + /** + * @class LockedQueue + * @author Eric Crahen + * @date <2003-07-16T11:42:33-0400> + * @version 2.3.0 + * + * A LockedQueue is the simple Queue implementation that provides + * serialized access to the values added to it. + */ + template > + class LockedQueue : public Queue { + + //! Serialize access to the Queue + LockType _lock; + + //! Storage backing the queue + StorageType _queue; + + //! Cancellation flag + volatile bool _canceled; + + public: + + //! Create a LockedQueue + LockedQueue() : _canceled(false) {} + + //! Destroy a LockedQueue + virtual ~LockedQueue() { } + + /** + * @see Queue::add(const T& item) + */ + virtual void add(const T& item) { + + Guard g(_lock); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + + } + + /** + * @see Queue::add(const T& item, unsigned long timeout) + */ + virtual bool add(const T& item, unsigned long timeout) { + + try { + + Guard g(_lock, timeout); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + + } catch(Timeout_Exception&) { return false; } + + return true; + + } + + /** + * @see Queue::next() + */ + virtual T next() { + + Guard g(_lock); + + if(_queue.size() == 0 && _canceled) + throw Cancellation_Exception(); + + if(_queue.size() == 0) + throw NoSuchElement_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + return item; + + } + + + /** + * @see Queue::next(unsigned long timeout) + */ + virtual T next(unsigned long timeout) { + + Guard g(_lock, timeout); + + if(_queue.size() == 0 && _canceled) + throw Cancellation_Exception(); + + if(_queue.size() == 0) + throw NoSuchElement_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + return item; + + } + + + /** + * @see Queue::cancel() + */ + virtual void cancel() { + + Guard g(_lock); + + _canceled = true; + + } + + /** + * @see Queue::isCanceled() + */ + virtual bool isCanceled() { + + // Faster check since the queue will not become un-canceled + if(_canceled) + return true; + + Guard g(_lock); + + return _canceled; + + } + + /** + * @see Queue::size() + */ + virtual size_t size() { + + Guard g(_lock); + return _queue.size(); + + } + + /** + * @see Queue::size(unsigned long timeout) + */ + virtual size_t size(unsigned long timeout) { + + Guard g(_lock, timeout); + return _queue.size(); + + } + + }; /* LockedQueue */ + +} // namespace ZThread + +#endif // __ZTLOCKEDQUEUE_H__ diff --git a/src/dep/include/zthread/MonitoredQueue.h b/src/dep/include/zthread/MonitoredQueue.h new file mode 100644 index 0000000..07613aa --- /dev/null +++ b/src/dep/include/zthread/MonitoredQueue.h @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITOREDQUEUE_H__ +#define __ZTMONITOREDQUEUE_H__ + +#include "zthread/Condition.h" +#include "zthread/Guard.h" +#include "zthread/Queue.h" + +#include + +namespace ZThread { + + /** + * @class MonitoredQueue + * @author Eric Crahen + * @date <2003-07-16T20:23:28-0400> + * @version 2.3.0 + * + * A MonitoredQueue is a Queue implementation that provides serialized access to the + * items added to it. + * + * - Threads calling the empty() methods will be blocked until the BoundedQueue becomes empty. + * - Threads calling the next() methods will be blocked until the BoundedQueue has a value to + * return. + * + * @see Queue + */ + template > + class MonitoredQueue : public Queue, public Lockable { + + //! Serialize access + LockType _lock; + + //! Signaled on not empty + Condition _notEmpty; + + //! Signaled on empty + Condition _isEmpty; + + //! Storage backing the queue + StorageType _queue; + + //! Cancellation flag + volatile bool _canceled; + + public: + + //! Create a new MonitoredQueue + MonitoredQueue() + : _notEmpty(_lock), _isEmpty(_lock), _canceled(false) {} + + //! Destroy a MonitoredQueue, delete remaining items + virtual ~MonitoredQueue() { } + + /** + * Add a value to this Queue. + * + * @param item value to be added to the Queue + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to add a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If no exception is thrown, a copy of item will have been added to the Queue. + * + * @see Queue::add(const T& item) + */ + virtual void add(const T& item) { + + Guard g(_lock); + + // Allow no further additions in the canceled state + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back( item ); + + _notEmpty.signal(); // Wake one waiter + + } + + /** + * Add a value to this Queue. + * + * @param item value to be added to the Queue + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if a copy of item can be added before timeout + * milliseconds elapse. + * - false otherwise. + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to add a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If no exception is thrown, a copy of item will have been added to the Queue. + * + * @see Queue::add(const T& item, unsigned long timeout) + */ + virtual bool add(const T& item, unsigned long timeout) { + + try { + + Guard g(_lock, timeout); + + if(_canceled) + throw Cancellation_Exception(); + + _queue.push_back(item); + + _notEmpty.signal(); + + } catch(Timeout_Exception&) { return false; } + + return true; + + } + + /** + * Retrieve and remove a value from this Queue. + * + * If invoked when there are no values present to return then the calling thread + * will be blocked until a value arrives in the Queue. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Interrupted_Exception thrown if the thread was interrupted while waiting + * to retrieve a value + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next() { + + Guard g(_lock); + + while (_queue.size() == 0 && !_canceled) + _notEmpty.wait(); + + if(_queue.size() == 0) // Queue canceled + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + if(_queue.size() == 0) // Wake empty waiters + _isEmpty.broadcast(); + + return item; + + } + + /** + * Retrieve and remove a value from this Queue. + * + * If invoked when there are no values present to return then the calling thread + * will be blocked until a value arrives in the Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Timeout_Exception thrown if the timeout expires before a value + * can be retrieved. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next(unsigned long timeout) { + + Guard g(_lock, timeout); + + while(_queue.size() == 0 && !_canceled) { + if(!_notEmpty.wait(timeout)) + throw Timeout_Exception(); + } + + if( _queue.size() == 0) // Queue canceled + throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + if(_queue.size() == 0) // Wake empty waiters + _isEmpty.broadcast(); + + return item; + + } + + + /** + * Cancel this queue. + * + * @post Any threads blocked by a next() function will throw a Cancellation_Exception. + * + * @see Queue::cancel() + */ + virtual void cancel() { + + Guard g(_lock); + + _canceled = true; + _notEmpty.broadcast(); // Wake next() waiters + + } + + /** + * @see Queue::isCanceled() + */ + virtual bool isCanceled() { + + // Faster check since the queue will not become un-canceled + if(_canceled) + return true; + + Guard g(_lock); + + return _canceled; + + } + + + /** + * @see Queue::size() + */ + virtual size_t size() { + + Guard g(_lock); + return _queue.size(); + + } + + /** + * @see Queue::size(unsigned long timeout) + */ + virtual size_t size(unsigned long timeout) { + + Guard g(_lock, timeout); + return _queue.size(); + + } + + /** + * Test whether any values are available in this Queue. + * + * The calling thread is blocked until there are no values present + * in the Queue. + * + * @return + * - true if there are no values available. + * - false if there are values available. + * + * @see Queue::empty() + */ + virtual bool empty() { + + Guard g(_lock); + + while(_queue.size() > 0) // Wait for an empty signal + _isEmpty.wait(); + + return true; + + } + + /** + * Test whether any values are available in this Queue. + * + * The calling thread is blocked until there are no values present + * in the Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if there are no values available. + * - false if there are values available. + * + * @exception Timeout_Exception thrown if timeout milliseconds + * expire before a value becomes available + * + * @see Queue::empty() + */ + virtual bool empty(unsigned long timeout) { + + Guard g(_lock, timeout); + + while(_queue.size() > 0) // Wait for an empty signal + _isEmpty.wait(timeout); + + return true; + + } + + public: + + virtual void acquire() { + _lock.acquire(); + } + + virtual bool tryAcquire(unsigned long timeout) { + return _lock.tryAcquire(timeout); + } + + virtual void release() { + _lock.release(); + } + + + }; /* MonitoredQueue */ + + +} // namespace ZThread + +#endif // __ZTMONITOREDQUEUE_H__ + diff --git a/src/dep/include/zthread/Mutex.h b/src/dep/include/zthread/Mutex.h new file mode 100644 index 0000000..1b521b1 --- /dev/null +++ b/src/dep/include/zthread/Mutex.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMUTEX_H__ +#define __ZTMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class FifoMutexImpl; + + /** + * @class Mutex + * @author Eric Crahen + * @date <2003-07-16T19:35:28-0400> + * @version 2.2.1 + * + * A Mutex is used to provide serialized (one thread at a time) access to some portion + * of code. This is accomplished by attempting to acquire the Mutex before entering that + * piece of code, and by releasing the Mutex when leaving that region. It is a non-reentrant, + * MUTual EXclusion Lockable object. + * + * @see Guard + * + * Scheduling + * + * Threads competing to acquire() a Mutex are granted access in FIFO order. + * + * Error Checking + * + * A Mutex will throw a Deadlock_Exception if an attempt to acquire a Mutex more + * than once is made from the context of the same thread. + * + * A Mutex will throw an InvalidOp_Exception if an attempt to release a Mutex is + * made from the context of a thread that does not currently own that Mutex. + */ + class ZTHREAD_API Mutex : public Lockable, private NonCopyable { + + FifoMutexImpl* _impl; + + public: + + //! Create a new Mutex. + Mutex(); + + //! Destroy this Mutex. + virtual ~Mutex(); + + /** + * Acquire a Mutex, possibly blocking until either the current owner of the + * Mutex releases it or until an exception is thrown. + * + * Only one thread may acquire() the Mutex at any given time. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * @exception Deadlock_Exception thrown when the same thread attempts to acquire + * a Mutex more than once, without having first release()ed it. + * + * @pre the calling thread must not have already acquired Mutex + * + * @post the calling thread successfully acquired Mutex only if no exception + * was thrown. + * + * @see Lockable::acquire() + */ + virtual void acquire(); + + /** + * Acquire a Mutex, possibly blocking until the current owner of the + * Mutex releases it, until an exception is thrown or until the given amount + * of time expires. + * + * Only one thread may acquire the Mutex at any given time. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * @return + * - true if the lock was acquired + * - false if the lock was acquired + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * @exception Deadlock_Exception thrown when the same thread attempts to acquire + * a Mutex more than once, without having first released it. + * + * @pre the calling thread must not have already acquired Mutex + * + * @post the calling thread successfully acquired Mutex only if no exception + * was thrown. + * + * @see Lockable::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + /** + * Release a Mutex allowing another thread to acquire it. + * + * @exception InvalidOp_Exception - thrown if there is an attempt to release is + * a Mutex that was not owner by the calling thread. + * + * @pre the calling thread must have first acquired the Mutex. + * @post the calling thread successfully released Mutex only if no exception + * was thrown. + * + * @see Lockable::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTMUTEX_H__ diff --git a/src/dep/include/zthread/NonCopyable.h b/src/dep/include/zthread/NonCopyable.h new file mode 100644 index 0000000..5c33f34 --- /dev/null +++ b/src/dep/include/zthread/NonCopyable.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTNONCOPYABLE_H__ +#define __ZTNONCOPYABLE_H__ + +namespace ZThread { + + /** + * @class NonCopyable + * @author Eric Crahen + * @date <2003-07-16T19:36:00-0400> + * @version 2.2.11 + * + * Some objects kind of objects should not be copied. This is particularly true + * of objects involved in providing mutually exclusive access to something + * (e.g. Mutexes, Queues, Semaphores, etc.) + * + * Based on Dave Abrahams contribution to the Boost library. + */ + class NonCopyable { + + //! Restrict the copy constructor + NonCopyable(const NonCopyable&); + + //! Restrict the assignment operator + const NonCopyable& operator=(const NonCopyable&); + + protected: + + //! Create a NonCopyable object + NonCopyable() { } + + //! Destroy a NonCopyable object + ~NonCopyable() { } + + }; /* NonCopyable */ + +} // namespace ZThread + +#endif // __ZTNONCOPYABLE_H__ diff --git a/src/dep/include/zthread/PoolExecutor.h b/src/dep/include/zthread/PoolExecutor.h new file mode 100644 index 0000000..82f5c4f --- /dev/null +++ b/src/dep/include/zthread/PoolExecutor.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPOOLEXECUTOR_H__ +#define __ZTPOOLEXECUTOR_H__ + +#include "zthread/Executor.h" +#include "zthread/CountedPtr.h" +#include "zthread/Thread.h" + +namespace ZThread { + + namespace { class ExecutorImpl; } + + /** + * @class PoolExecutor + * + * @author Eric Crahen + * @date <2003-07-16T22:41:07-0400> + * @version 2.3.0 + * + * A PoolExecutor spawns a set of threads that are used to run tasks + * that are submitted in parallel. A PoolExecutor supports the following + * optional operations, + * + * - cancel()ing a PoolExecutor will cause it to stop accepting + * new tasks. + * + * - interrupt()ing a PoolExecutor will cause the any thread running + * a task which was submitted prior to the invocation of this function to + * be interrupted during the execution of that task. + * + * - wait()ing on a PoolExecutor will block the calling thread + * until all tasks that were submitted prior to the invocation of this function + * have completed. + * + * @see Executor. + */ + class PoolExecutor : public Executor { + + //! Reference to the internal implementation + CountedPtr< ExecutorImpl > _impl; + + //! Cancellation task + Task _shutdown; + + public: + + /** + * Create a PoolExecutor + * + * @param n number of threads to service tasks with + */ + PoolExecutor(size_t n); + + //! Destroy a PoolExecutor + virtual ~PoolExecutor(); + + /** + * Invoking this function causes each task that had been submitted prior to + * this function to be interrupted. Tasks submitted after the invocation of + * this function are unaffected. + * + * @post Any task submitted prior to the invocation of this function will be + * run in the context of an interrupted thread. + * @post Any thread already executing a task which was submitted prior to the + * invocation of this function will be interrupted. + */ + virtual void interrupt(); + + /** + * Alter the number of threads being used to execute submitted tasks. + * + * @param n number of worker threads. + * + * @pre n must be greater than 0. + * @post n threads will be executing tasks submitted to this executor. + * + * @exception InvalidOp_Exception thrown if the new number of threads + * n is less than 1. + */ + void size(size_t n); + + /** + * Get the current number of threads being used to execute submitted tasks. + * + * @return n number of worker threads. + */ + size_t size(); + + /** + * Submit a task to this Executor. + * + * This will not block the calling thread very long. The submitted task will + * be executed at some later point by another thread. + * + * @param task Task to be run by a thread managed by this executor + * + * @pre The Executor should have been canceled prior to this invocation. + * @post The submitted task will be run at some point in the future by this Executor. + * + * @exception Cancellation_Exception thrown if the Executor was canceled prior to + * the invocation of this function. + * + * @see PoolExecutor::cancel() + * @see Executor::execute(const Task& task) + */ + virtual void execute(const Task& task); + + /** + * @see Cancelable::cancel() + */ + virtual void cancel(); + + /** + * @see Cancelable::isCanceled() + */ + virtual bool isCanceled(); + + /** + * Block the calling thread until all tasks submitted prior to this invocation + * complete. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before the set of tasks being wait for can complete. + * + * @see Waitable::wait() + */ + virtual void wait(); + + /** + * Block the calling thread until all tasks submitted prior to this invocation + * complete or until the calling thread is interrupted. + * + * @param timeout maximum amount of time, in milliseconds, to wait for the + * currently submitted set of Tasks to complete. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before the set of tasks being wait for can complete. + * + * @return + * - true if the set of tasks being wait for complete before + * timeout milliseconds elapse. + * - false otherwise. + * + * @see Waitable::wait(unsigned long timeout) + */ + virtual bool wait(unsigned long timeout); + + }; /* PoolExecutor */ + + +} // namespace ZThread + +#endif // __ZTPOOLEXECUTOR_H__ + + + + diff --git a/src/dep/include/zthread/Priority.h b/src/dep/include/zthread/Priority.h new file mode 100644 index 0000000..907d1f1 --- /dev/null +++ b/src/dep/include/zthread/Priority.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPRIORITY_H__ +#define __ZTPRIORITY_H__ + +namespace ZThread { + + //! Priorities + typedef enum { + + Low, + Medium = Low + 1, + High = Low + 2 + + } Priority; + +} + +#endif // __ZTPRIORITY_H__ diff --git a/src/dep/include/zthread/PriorityCondition.h b/src/dep/include/zthread/PriorityCondition.h new file mode 100644 index 0000000..1fd86c4 --- /dev/null +++ b/src/dep/include/zthread/PriorityCondition.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPRIORITYCONDITION_H__ +#define __ZTPRIORITYCONDITION_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" +#include "zthread/Waitable.h" + +namespace ZThread { + + class PriorityConditionImpl; + + /** + * @class PriorityCondition + * @author Eric Crahen + * @date <2003-07-16T17:35:28-0400> + * @version 2.2.1 + * + * A PriorityCondition is a Condition that is sensitive to thread priority. + * + * @see Condition + * + * Scheduling + * + * Threads blocked on a PriorityCondition are resumed in priority order, highest priority + * first + */ + class ZTHREAD_API PriorityCondition : public Waitable, private NonCopyable { + + PriorityConditionImpl* _impl; + + public: + + /** + * @see Condition::Condition(Lockable& l) + */ + PriorityCondition(Lockable& l); + + /** + * @see Condition::~Condition() + */ + ~PriorityCondition(); + + /** + * @see Condition::signal() + */ + void signal(); + + /** + * @see Condition::broadcast() + */ + void broadcast(); + + /** + * @see Condition::wait() + */ + virtual void wait(); + + /** + * @see Condition::wait(unsigned long timeout) + */ + virtual bool wait(unsigned long timeout); + + }; + +} // namespace ZThread + +#endif // __ZTPRIORITYCONDITION_H__ diff --git a/src/dep/include/zthread/PriorityInheritanceMutex.h b/src/dep/include/zthread/PriorityInheritanceMutex.h new file mode 100644 index 0000000..1a5f5bf --- /dev/null +++ b/src/dep/include/zthread/PriorityInheritanceMutex.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPRIORITYINHERITANCEMUTEX_H__ +#define __ZTPRIORITYINHERITANCEMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class PriorityInheritanceMutexImpl; + + /** + * @class PriorityInheritanceMutex + * + * @author Eric Crahen + * @date <2003-07-16T19:37:36-0400> + * @version 2.2.1 + * + * A PriorityInheritanceMutex is similar to a PriorityMutex, it is a non-reentrant, + * priority sensitive MUTual EXclusion Lockable object. It differs only in its + * scheduling policy. + * + * @see PriorityMutex + * + * Scheduling + * + * Threads competing to acquire() a PriorityInheritanceMutex are granted access in + * order of priority. Threads with a higher priority will be given access first. + * + * When a higher priority thread tries to acquire() a PriorityInheritanceMutex and is + * about to be blocked by a lower priority thread that has already acquire()d it, the + * lower priority thread will temporarily have its effective priority raised to that + * of the higher priority thread until it release()s the mutex; at which point its + * previous priority will be restored. + */ + class ZTHREAD_API PriorityInheritanceMutex : public Lockable, private NonCopyable { + + PriorityInheritanceMutexImpl* _impl; + + public: + + /** + * @see Mutex::Mutex() + */ + PriorityInheritanceMutex(); + + /** + * @see Mutex::~Mutex() + */ + virtual ~PriorityInheritanceMutex(); + + /** + * @see Mutex::acquire() + */ + virtual void acquire(); + + /** + * @see Mutex::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + /** + * @see Mutex::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTPRIORITYINHERITANCEMUTEX_H__ diff --git a/src/dep/include/zthread/PriorityMutex.h b/src/dep/include/zthread/PriorityMutex.h new file mode 100644 index 0000000..477c8d9 --- /dev/null +++ b/src/dep/include/zthread/PriorityMutex.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPRIORITYMUTEX_H__ +#define __ZTPRIORITYMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class PriorityMutexImpl; + + /** + * @class PriorityMutex + * @author Eric Crahen + * @date <2003-07-16T17:35:46-0400> + * @version 2.2.1 + * + * A PriorityMutex is similar to a Mutex, with exception that a PriorityMutex + * has a difference scheduling policy. It is a non-reentrant, priority sensitive + * MUTual EXclusion Lockable object. + * + * @see Mutex + * + * Scheduling + * + * Threads competing to acquire() a Mutex are granted access in order of priority. Threads + * with a higher priority will be given access first. + */ + class ZTHREAD_API PriorityMutex : public Lockable, private NonCopyable { + + PriorityMutexImpl* _impl; + + public: + + /** + * @see Mutex::Mutex() + */ + PriorityMutex(); + + /** + * @see Mutex::~Mutex() + */ + virtual ~PriorityMutex(); + + /** + * @see Mutex::acquire() + */ + virtual void acquire(); + + /** + * @see Mutex::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + /** + * @see Mutex::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTPRIORITYMUTEX_H__ diff --git a/src/dep/include/zthread/PrioritySemaphore.h b/src/dep/include/zthread/PrioritySemaphore.h new file mode 100644 index 0000000..54ef2c4 --- /dev/null +++ b/src/dep/include/zthread/PrioritySemaphore.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +#ifndef __ZTPRIORITYSEMAPHORE_H__ +#define __ZTPRIORITYSEMAPHORE_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class PrioritySemaphoreImpl; + + /** + * @class PrioritySemaphore + * @author Eric Crahen + * @date <2003-07-16T15:36:07-0400> + * @version 2.2.1 + * + * A PrioritySemaphore operates in the same way as a Semaphore. Its an owner-less + * Lockable object that is sensitive to priority. + * + * Scheduling + * + * Threads blocked on a PrioritySemaphore are resumed in priority order, highest + * priority first. + * + * Error Checking + * + * An attempt to increase a PrioritySemaphore beyond its maximum value will result in + * an InvalidOp_Exception. + * + * @see Semaphore + */ + class ZTHREAD_API PrioritySemaphore : public Lockable, private NonCopyable { + + PrioritySemaphoreImpl* _impl; + + public: + + /** + * @see Semaphore::Semaphore(int count, unsigned int maxCount) + */ + PrioritySemaphore(int count = 1, unsigned int maxCount = 1); + + /** + * @see Semaphore::~Semaphore() + */ + virtual ~PrioritySemaphore(); + + /** + * @see Semaphore::wait() + */ + void wait(); + + /** + * @see Semaphore::tryWait(unsigned long) + */ + bool tryWait(unsigned long); + + /** + * @see Semaphore::post() + */ + void post(); + + /** + * @see Semaphore::count() + */ + virtual int count(); + + /** + * @see Semaphore::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + /** + * @see Semaphore::acquire() + */ + virtual void acquire(); + + /** + * @see Semaphore::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTPRIORITYSEMAPHORE_H__ diff --git a/src/dep/include/zthread/Queue.h b/src/dep/include/zthread/Queue.h new file mode 100644 index 0000000..98b83a1 --- /dev/null +++ b/src/dep/include/zthread/Queue.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTQUEUE_H__ +#define __ZTQUEUE_H__ + +#include "zthread/Cancelable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + /** + * @class Queue + * @author Eric Crahen + * @date <2003-07-16T11:32:42-0400> + * @version 2.3.0 + * + * A Queue defines an interface for a value-oriented collection objects (similar to + * STL collections). + */ + template + class Queue : public Cancelable, private NonCopyable { + public: + + //! Destroy a Queue + virtual ~Queue() { } + + /** + * Add an object to this Queue. + * + * @param item value to be added to the Queue + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If no exception is thrown, a copy of item will have been added to the Queue. + */ + virtual void add(const T& item) = 0; + + /** + * Add an object to this Queue. + * + * @param item value to be added to the Queue + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if a copy of item can be added before timeout + * milliseconds elapse. + * - false otherwise. + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post If this function returns true a copy of item will have been added to the Queue. + */ + virtual bool add(const T& item, unsigned long timeout) = 0; + + /** + * Retrieve and remove a value from this Queue. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next() = 0; + + /** + * Retrieve and remove a value from this Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return T next available value + * + * @exception Cancellation_Exception thrown if this Queue has been canceled. + * @exception Timeout_Exception thrown if the timeout expires before a value + * can be retrieved. + * + * @pre The Queue should not have been canceled prior to the invocation of this function. + * @post The value returned will have been removed from the Queue. + */ + virtual T next(unsigned long timeout) = 0; + + /** + * Canceling a Queue disables it, disallowing further additions. Values already + * present in the Queue can still be retrieved and are still available through + * the next() methods. + * + * Canceling a Queue more than once has no effect. + * + * @post The next() methods will continue to return objects until + * the Queue has been emptied. + * @post Once emptied, the next() methods will throw a Cancellation_Exception. + * @post The add() methods will throw a Cancellation_Exceptions from this point on. + */ + virtual void cancel() = 0; + + /** + * Count the values present in this Queue. + * + * @return size_t number of elements available in the Queue. + */ + virtual size_t size() = 0; + + /** + * Count the values present in this Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return size_t number of elements available in the Queue. + * + * @exception Timeout_Exception thrown if timeout milliseconds + * expire before a value becomes available + */ + virtual size_t size(unsigned long timeout) = 0; + + /** + * Test whether any values are available in this Queue. + * + * @return + * - true if there are no values available. + * - false if there are values available. + */ + virtual bool empty() { + + try { + + return size() == 0; + + } catch(Cancellation_Exception&) { } + + return true; + + } + + /** + * Test whether any values are available in this Queue. + * + * @param timeout maximum amount of time (milliseconds) this method may block + * the calling thread. + * + * @return + * - true if there are no values available. + * - false if there are values available. + * + * @exception Timeout_Exception thrown if timeout milliseconds + * expire before a value becomes available + */ + virtual bool empty(unsigned long timeout) { + + try { + + return size(timeout) == 0; + + } catch(Cancellation_Exception&) { } + + return true; + + } + + }; /* Queue */ + +} // namespace ZThread + +#endif // __ZTQUEUE_H__ diff --git a/src/dep/include/zthread/ReadWriteLock.h b/src/dep/include/zthread/ReadWriteLock.h new file mode 100644 index 0000000..e01643f --- /dev/null +++ b/src/dep/include/zthread/ReadWriteLock.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTREADWRITELOCK_H__ +#define __ZTREADWRITELOCK_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + /** + * @class ReadWriteLock + * + * @author Eric Crahen + * @date <2003-07-16T10:17:31-0400> + * @version 2.2.7 + * + * A ReadWriteLock provides a set of coordinated Lockable objects that can be used to + * guard an object; One for read-only access, and another for read-write access. + * + * @see BiasedReadWriteLock + * @see FairReadWriteLock + */ + class ReadWriteLock : public NonCopyable { + public: + + /** + * Create a ReadWriteLock + * + * @exception Initialization_Exception thrown if resources could not be + * allocated for this object. + */ + ReadWriteLock() {} + + //! Destroy this ReadWriteLock + virtual ~ReadWriteLock() {} + + /** + * Get a reference to the read-only Lockable. + * + * @return Lockable& reference to a Lockable that provides read-only + * access. + */ + virtual Lockable& getReadLock() = 0; + + /** + * Get a reference to the read-write Lockable. + * + * @return Lockable& reference to a Lockable that provides read-write + * access. + */ + virtual Lockable& getWriteLock() = 0; + + + }; /* ReadWriteLock */ + + +}; // __ZTREADWRITELOCK_H__ + +#endif diff --git a/src/dep/include/zthread/RecursiveMutex.h b/src/dep/include/zthread/RecursiveMutex.h new file mode 100644 index 0000000..7dda9c5 --- /dev/null +++ b/src/dep/include/zthread/RecursiveMutex.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTRECURSIVEMUTEX_H__ +#define __ZTRECURSIVEMUTEX_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class RecursiveMutexImpl; + + /** + * @class RecursiveMutex + * + * @author Eric Crahen + * @date <2003-07-16T17:51:33-0400> + * @version 2.2.1 + * + * A RecursiveMutex is a recursive, MUTual EXclusion Lockable object. It is + * recursive because it can be acquire()d and release()d more than once + * by the same thread, instead of causing a Deadlock_Exception. + * + * @see Mutex + * @see Guard + * + * Scheduling + * + * Threads competing to acquire() a Mutex are granted access in FIFO order. + * + * Error Checking + * + * A Mutex will throw an InvalidOp_Exception if an attempt to release() a Mutex is + * made from the context of a thread that does not currently own that Mutex. + */ + class ZTHREAD_API RecursiveMutex : public Lockable, private NonCopyable { + + RecursiveMutexImpl* _impl; + + public: + + //! Create a new RecursiveMutex. + RecursiveMutex(); + + //! Destroy this RecursiveMutex. + virtual ~RecursiveMutex(); + + /** + * Acquire a RecursiveMutex, possibly blocking until the the current owner of the + * releases it or until an exception is thrown. + * + * Only one thread may acquire the RecursiveMutex at any given time. + * The same thread may acquire a RecursiveMutex multiple times. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @post the calling thread successfully acquire ed RecursiveMutex only if no exception + * was thrown. + * + * @see Lockable::acquire() + */ + virtual void acquire(); + + /** + * Acquire a RecursiveMutex, possibly blocking until the the current owner + * releases it, until an exception is thrown or until the given amount + * of time expires. + * + * Only one thread may acquire the RecursiveMutex at any given time. + * The same thread may acquire a RecursiveMutex multiple times. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * @return + * - true if the lock was acquired + * - false if the lock was acquired + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @post the calling thread successfully acquired RecursiveMutex only if no exception + * was thrown. + * + * @see Lockable::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + + /** + * Release exclusive access. No safety or state checks are performed. + * + * @pre This should not be called more times than the acquire() method was + * called. + * + * @see Lockable::release() + */ + virtual void release(); + + }; + +} // namespace ZThread + +#endif // __ZTRECURSIVEMUTEX_H__ diff --git a/src/dep/include/zthread/Runnable.h b/src/dep/include/zthread/Runnable.h new file mode 100644 index 0000000..9862853 --- /dev/null +++ b/src/dep/include/zthread/Runnable.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +#ifndef __ZTRUNNABLE_H__ +#define __ZTRUNNABLE_H__ + +#include "zthread/Config.h" + +namespace ZThread { + + /** + * @class Runnable + * + * @author Eric Crahen + * @date <2003-07-16T17:45:35-0400> + * @version 2.2.11 + * + * Encapsulates a Runnable task. + */ + class Runnable { + public: + + /** + * Runnables should never throw in their destructors + */ + virtual ~Runnable() {} + + /** + * Task to be performed in another thread of execution + */ + virtual void run() = 0; + + }; + + +} + +#endif // __ZTRUNNABLE_H__ diff --git a/src/dep/include/zthread/Semaphore.h b/src/dep/include/zthread/Semaphore.h new file mode 100644 index 0000000..2a9e4d0 --- /dev/null +++ b/src/dep/include/zthread/Semaphore.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSEMAPHORE_H__ +#define __ZTSEMAPHORE_H__ + +#include "zthread/Lockable.h" +#include "zthread/NonCopyable.h" + +namespace ZThread { + + class FifoSemaphoreImpl; + + /** + * @class Semaphore + * @author Eric Crahen + * @date <2003-07-16T15:28:01-0400> + * @version 2.2.1 + * + * A Semaphore is an owner-less Lockable object. Its probably best described as + * a set of 'permits'. A Semaphore is initialized with an initial count and + * a maximum count, these would correspond to the number of 'permits' currently + * available and the number of' permits' in total. + * + * - Acquiring the Semaphore means taking a permit, but if there are none + * (the count is 0) the Semaphore will block the calling thread. + * + * - Releasing the Semaphore means returning a permit, unblocking a thread + * waiting for one. + * + * A Semaphore with an initial value of 1 and maximum value of 1 will act as + * a Mutex. + * + * Threads blocked on a Semaphore are resumed in FIFO order. + * + */ + class ZTHREAD_API Semaphore : public Lockable, private NonCopyable { + + FifoSemaphoreImpl* _impl; + + public: + + /** + * Create a new Semaphore. + * + * @param count initial count + * @param maxCount maximum count + */ + Semaphore(int count = 1, unsigned int maxCount = 1); + + //! Destroy the Semaphore + virtual ~Semaphore(); + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see acquire() + */ + void wait(); + + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see tryAcquire(unsigned long timeout) + */ + bool tryWait(unsigned long timeout); + + /** + * Provided to reflect the traditional Semaphore semantics + * + * @see release() + */ + void post(); + + + /** + * Get the current count of the semaphore. + * + * This value may change immediately after this function returns to the calling thread. + * + * @return int count + */ + virtual int count(); + + /** + * Decrement the count, blocking that calling thread if the count becomes 0 or + * less than 0. The calling thread will remain blocked until the count is + * raised above 0, an exception is thrown or the given amount of time expires. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * + * @return + * - true if the Semaphore was acquired before timeout milliseconds elapse. + * - false otherwise. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @see Lockable::tryAcquire(unsigned long timeout) + */ + virtual bool tryAcquire(unsigned long timeout); + + + /** + * Decrement the count, blocking that calling thread if the count becomes 0 or + * less than 0. The calling thread will remain blocked until the count is + * raised above 0 or if an exception is thrown. + * + * @exception Interrupted_Exception thrown when the calling thread is interrupted. + * A thread may be interrupted at any time, prematurely ending any wait. + * + * @see Lockable::acquire() + */ + virtual void acquire(); + + /** + * Increment the count, unblocking one thread if count is positive. + * + * @exception InvalidOp_Exception thrown if the maximum count would be exceeded. + * + * @see Lockable::release() + */ + virtual void release(); + + }; + + +} // namespace ZThread + +#endif // __ZTSEMAPHORE_H__ diff --git a/src/dep/include/zthread/Singleton.h b/src/dep/include/zthread/Singleton.h new file mode 100644 index 0000000..b66c9d0 --- /dev/null +++ b/src/dep/include/zthread/Singleton.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSINGLETON_H__ +#define __ZTSINGLETON_H__ + +#include "zthread/Guard.h" +#include "zthread/FastMutex.h" +#include + +namespace ZThread { + +// +// This policy controls how an object is instantiated +// as well as how and when its destroyed. Phoenix-style +// singletons are not supported easily with type of policy, +// this is intentional since I do not believe that is in +// the true spirit of a singleton. +// +// InstantiationPolicContract { +// +// create(pointer_type&) +// +// } + +/** + * @class LocalStaticInstantiation + * @author Eric Crahen + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The LocalStaticInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using static local values. This will + * abide by the standard C++ rules for static objects + * lifetimes. + */ +class LocalStaticInstantiation { +protected: + + /** + * Create an instance of an object, using a local static. The + * object will be destroyed by the system. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template + static void create(T*& ptr) { + + static T instance; + ptr = &instance; + + } + +}; + +//! Helper class +template +class StaticInstantiationHelper { + //! Friend class + friend class StaticInstantiation; + //! Holder + static T instance; + + }; + + template + T StaticInstantiationHelper::instance; + +/** + * @class StaticInstantiation + * @author Eric Crahen + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The StaticInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using static instantiation. This will + * abide by the standard C++ rules for static objects + * lifetimes. + */ +class StaticInstantiation { +protected: + + /** + * Create an instance of an object using by simply allocating it statically. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template + static void create(T*& ptr) { + ptr = &StaticInstantiationHelper::instance; + } + +}; + +//! SingletonDestroyer +template +class Destroyer { + + T* doomed; + + public: + + Destroyer(T* q) : doomed(q) { + assert(doomed); + } + + ~Destroyer(); + +}; + +template +Destroyer::~Destroyer() { + + try { + + if(doomed) + delete doomed; + + } catch(...) { } + + doomed = 0; + +} + + +/** + * @class LazyInstantiation + * @author Eric Crahen + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * The LazyInstantiation policy allows the creation + * and lifetime of an instance of a particular type + * to be managed using dynamic allocation and a singleton + * destroyer. This will abide by the standard C++ rules + * for static objects lifetimes. + */ +class LazyInstantiation { +protected: + + /** + * Create an instance of an object, using new, that will be + * destroyed when an associated Destroyer object (allocated + * statically) goes out of scope. + * + * @param ptr reference to location to receive the address + * of the allocated object + */ + template + static void create(T*& ptr) { + + ptr = new T; + static Destroyer destroyer(ptr); + + } + +}; + + +/** + * @class Singleton + * @author Eric Crahen + * @date <2003-07-16T17:57:45-0400> + * @version 2.2.0 + * + * Based on the work of John Vlissidles in his book 'Pattern Hatching' + * an article by Douglas Schmidtt on double-checked locking and policy + * templates described by Andrei Alexandrescu. + * + * This is a thread safe wrapper for creating Singleton classes. The + * synchronization method and instantiation methods can be changed + * easily by specifying different policy implementations as the + * templates parameters. + * + * @code + * + * // Most common Singleton + * Singletion + * + * // Singleton that uses static storage + * Singletion + * + * // Single-threaded singleton that uses static storage (Meyers-like) + * Singletion + * + * @endcode + */ +template +class Singleton : private InstantiationPolicy, private NonCopyable { +public: + + /** + * Provide access to the single instance through double-checked locking + * + * @return T* single instance + */ + static T* instance(); + +}; + +template +T* Singleton::instance() { + + // Uses local static storage to avoid static construction + // sequence issues. (regaring when the lock is created) + static T* ptr = 0; + static LockType lock; + + if(!ptr) { + + Guard g(lock); + if(!ptr) + InstantiationPolicy::create(ptr); + + } + + return const_cast(ptr); + + } + + +}; + +#endif + + diff --git a/src/dep/include/zthread/SynchronousExecutor.h b/src/dep/include/zthread/SynchronousExecutor.h new file mode 100644 index 0000000..b6dbbef --- /dev/null +++ b/src/dep/include/zthread/SynchronousExecutor.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSYNCHRONOUSEXECUTOR_H__ +#define __ZTSYNCHRONOUSEXECUTOR_H__ + +#include "zthread/Executor.h" +#include "zthread/Guard.h" +#include "zthread/Mutex.h" +#include "zthread/Thread.h" + +namespace ZThread { + + /** + * @class SynchronousExecutor + * + * @author Eric Crahen + * @date <2003-07-16T22:33:51-0400> + * @version 2.3.0 + * + * A SynchronousExecutor is an Executor which runs tasks using the thread that + * submits the task. It runs tasks serially, one at a time, in the order they + * were submitted to the executor. + * + * @see Executor. + */ + class SynchronousExecutor : public Executor { + + //! Serialize access + Mutex _lock; + + //! Cancellation flag + bool _canceled; + + public: + + //! Create a new SynchronousExecutor + SynchronousExecutor(); + + //! Destroy a SynchronousExecutor + virtual ~SynchronousExecutor(); + + /** + * This operation is not supported by this executor. + */ + virtual void interrupt(); + + /** + * Submit a task to this Executor, blocking the calling thread until the + * task is executed. + * + * @param task Task to be run by a thread managed by this executor + * + * @pre The Executor should have been canceled prior to this invocation. + * @post The submitted task will be run at some point in the future by this Executor. + * + * @exception Cancellation_Exception thrown if the Executor was canceled prior to + * the invocation of this function. + * + * @see Executor::execute(const Task& task) + */ + virtual void execute(const Task& task); + + /** + * @see Cancelable::cancel() + */ + virtual void cancel(); + + /** + * @see Cancelable::cancel() + */ + virtual bool isCanceled(); + + /** + * Block the calling thread until all tasks submitted prior to this invocation + * complete. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before the set of tasks being wait for can complete. + * + * @see Executor::wait() + */ + virtual void wait(); + + /** + * Block the calling thread until all tasks submitted prior to this invocation + * complete or until the calling thread is interrupted. + * + * @param timeout - maximum amount of time, in milliseconds, to wait for the + * currently submitted set of Tasks to complete. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before the set of tasks being wait for can complete. + * + * @return + * - true if the set of tasks being wait for complete before + * timeout milliseconds elapse. + * - false othewise. + */ + virtual bool wait(unsigned long timeout); + + + }; /* SynchronousExecutor */ + +} // namespace ZThread + +#endif // __ZTSYNCHRONOUSEXECUTOR_H__ diff --git a/src/dep/include/zthread/Task.h b/src/dep/include/zthread/Task.h new file mode 100644 index 0000000..6503be6 --- /dev/null +++ b/src/dep/include/zthread/Task.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTASK_H__ +#define __ZTTASK_H__ + +#include "zthread/CountedPtr.h" +#include "zthread/Runnable.h" + +namespace ZThread { + + class ThreadImpl; + + /** + * @class Task + * + * @author Eric Crahen + * @date <2003-07-20T05:22:38-0400> + * @version 2.3.0 + * + * A Task provides a CountedPtr wrapper for Runnable objects. + * This wrapper enables an implicit conversion from a + * Runnable* to a Task adding some syntactic sugar + * to the interface. + */ + class ZTHREAD_API Task : public CountedPtr { + public: + + +#if !defined(_MSC_VER) || (_MSC_VER > 1200) + + Task(Runnable* raw) + : CountedPtr(raw) { } + +#endif + + template + Task(U* raw) + : CountedPtr(raw) { } + + Task(const CountedPtr& ptr) + : CountedPtr(ptr) { } + + template + Task(const CountedPtr& ptr) + : CountedPtr(ptr) { } + + void operator()() { + (*this)->run(); + } + + }; /* Task */ + +} // namespace ZThread + +#endif // __ZTTASK_H__ + + + diff --git a/src/dep/include/zthread/Thread.h b/src/dep/include/zthread/Thread.h new file mode 100644 index 0000000..e1700c7 --- /dev/null +++ b/src/dep/include/zthread/Thread.h @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREAD_H__ +#define __ZTTHREAD_H__ + +#include "zthread/Cancelable.h" +#include "zthread/Priority.h" +#include "zthread/NonCopyable.h" +#include "zthread/Task.h" +#include "zthread/Waitable.h" + +namespace ZThread { + + class ThreadImpl; + + /** + * @class Thread + * @author Eric Crahen + * @date <2003-07-27T11:17:59-0400> + * @version 2.3.0 + * + * + * @see Task + * @see Executor + * + *

Examples

+ * - Launching a task + * - Waiting for a task + * - Sharing a task + * + *

Launching a task

+ * + * A thread is started simply by constructing a thread object and giving + * it a task to perform. The thread will continue to run its task, even + * after the Thread object used to launch the thread has gone out of scope. + * + * @code + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * class aRunnable : public Runnable { + * + * void run() { + * + * Thread::sleep(1000); + * std::cout << "Hello from another thread" << std::endl; + * + * } + * + * }; + * + * int main() { + * + * try { + * + * // Implictly constructs a Task + * Thread t(new aRunnable); + * + * } catch(Synchronization_Exception& e) { + * std::cerr << e.what() << std::endl; + * } + * + * std::cout << "Hello from the main thread" << std::endl; + * + * // Output: + * + * // Hello from the main thread + * // Hello from another thread + * + * return 0; + * + * } + * + * @endcode + * + *

Waiting for a task

+ * + * A user can exercise some simple synchronization by waiting for a thread + * to complete running its task. + * + * @code + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * class aRunnable : public Runnable { + * public: + * + * void run() { + * + * Thread::sleep(1000); + * std::cout << "Hello from another thread" << std::endl; + * + * } + * + * }; + * + * int main() { + * + * try { + * + * // Implictly constructs a Task + * Thread t(new aRunnable); + * t.wait(); + * + * } catch(Synchronization_Exception& e) { + * std::cerr << e.what() << std::endl; + * } + * + * std::cout << "Hello from the main thread" << std::endl; + * + * // Output: + * + * // Hello from another thread + * // Hello from the main thread + * + * return 0; + * + * } + * + * @endcode + * + *

Sharing a task

+ * + * The same task can be shared by more than one thread. A Task is constructed + * from a Runnable, and that Task object is copied by value and handed off to + * each thread. + * + * @code + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * class aRunnable : public Runnable { + * + * void run() { + * + * Thread::sleep(1000); + * std::cout << "Hello from another thread" << std::endl; + * + * } + * + * }; + * + * int main() { + * + * try { + * + * // Explictly constructs a Task + * Task task(new aRunnable); + * + * // Two threads created to run the same Task + * Thread t1(task); + * Thread t2(task); + * + * } catch(Synchronization_Exception& e) { + * std::cerr << e.what() << std::endl; + * } + * + * std::cout << "Hello from the main thread" << std::endl; + * + * // Output: + * + * // Hello from the main thread + * // Hello from another thread + * // Hello from another thread + * + * return 0; + * + * } + * + * @endcode + */ + class ZTHREAD_API Thread + : public Cancelable, public Waitable, public NonCopyable { + + //! Delegate + ThreadImpl* _impl; + + public: + + /** + * Create a Thread that represents the current thread. + * Using the static members of Thread should be preferred over using this constructor + */ + Thread(); + + /** + * Create a Thread that spawns a new thread to run the given task. + * + * @param task Task to be run by a thread managed by this executor + * @param autoCancel flag to requestion automatic cancellation + * + * @post if the autoCancel flag was true, this thread will + * automatically be canceled when main() goes out of scope. + */ + Thread(const Task&, bool autoCancel = false); + + //! Destroy the Thread + ~Thread(); + + //! Comparison operator + bool operator==(const Thread& t) const; + + //! Comparison operator + inline bool operator!=(const Thread& t) const { + return !(*this == t); + } + + /** + * Wait for the thread represented by this object to complete its task. + * The calling thread is blocked until the thread represented by this + * object exits. + * + * @exception Deadlock_Exception thrown if thread attempts to join itself + * @exception InvalidOp_Exception thrown if the thread cannot be joined + * @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed + */ + void wait(); + + /** + * Wait for the thread represented by this object to complete its task. + * The calling thread is blocked until the thread represented by this + * object exits, or until the timeout expires. + * + * @param timeout maximum amount of time (milliseconds) this method + * could block the calling thread. + * + * @return + * - true if the thread task complete before timeout + * milliseconds elapse. + * - false othewise. + * + * @exception Deadlock_Exception thrown if thread attempts to join itself + * @exception InvalidOp_Exception thrown if the thread cannot be joined + * @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed + */ + bool wait(unsigned long timeout); + + /** + * Change the priority of this Thread. This will change the actual + * priority of the thread when the OS supports it. + * + * If there is no real priority support, it's simulated. + * + * @param p - new Priority + */ + void setPriority(Priority p); + + /** + * Get the priority of this Thread. + * + * @return Priority + */ + Priority getPriority(); + + /** + * Interrupts this thread, setting the interrupted status of the thread. + * This status is cleared by one of three methods. + * + * If this thread is blocked when this method is called, the thread will + * abort that blocking operation with an Interrupted_Exception. + * + * - The first is by attempting an operation on a synchronization object that + * would normally block the calling thread; Instead of blocking the calling + * the calling thread, the function that would normally block will thrown an + * Interrupted_Exception and clear the interrupted status of the thread. + * + * - The second is by calling Thread::interrupted(). + * + * - The third is by calling Thread::canceled(). + * + * Threads already blocked by an operation on a synchronization object will abort + * that operation with an Interrupted_Exception, clearing the threads interrupted + * status as in the first case described above. + * + * Interrupting a thread that is no longer running will have no effect. + * + * @return + * - true if the thread was interrupted while not blocked by a wait + * on a synchronization object. + * - false othewise. + */ + bool interrupt(); + + /** + * Tests whether the current Thread has been interrupt()ed, clearing + * its interruption status. + * + * @return + * - true if the Thread was interrupted. + * - false otherwise. + * + * @post The interrupted status of the current thread will be cleared, + * allowing it to perform a blocking operation on a synchronization + * object without throwing an exception. + */ + static bool interrupted(); + + /** + * Tests whether the current Thread has been canceled, and clears the + * interrupted status. + * + * @return bool true only if the Thread::cancel() has been invoked. + */ + static bool canceled(); + + /** + * Tests whether this thread has been canceled. If called from the context + * of this thread, the interrupted status is cleared. + * + * @return + * - true if the Thread was canceled. + * - false otherwise. + * + * @see Cancelable::isCanceled() + */ + virtual bool isCanceled(); + + /** + * Interrupt and cancel this thread in a single operation. The thread will + * return true whenever its cancelation status is tested in the future. + * + * @exception InvalidOp_Exception thrown if a thread attempts to cancel itself + * + * @see Thread::interrupt() + * @see Cancelable::cancel() + */ + virtual void cancel(); + + /** + * Put the currently executing thread to sleep for a given amount of + * time. + * + * @param timeout maximum amount of time (milliseconds) this method could block + * + * @exception Interrupted_Exception thrown if the threads sleep is interrupted + * before timeout milliseconds expire. + */ + static void sleep(unsigned long timeout); + + /** + * Cause the currently executing thread to yield, allowing the scheduler + * to assign some execution time to another thread. + */ + static void yield(); + + + }; /* Thread */ + + +} // namespace ZThread + +#endif // __ZTTHREAD_H__ + + + diff --git a/src/dep/include/zthread/ThreadLocal.h b/src/dep/include/zthread/ThreadLocal.h new file mode 100644 index 0000000..bb83a0f --- /dev/null +++ b/src/dep/include/zthread/ThreadLocal.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADLOCAL_H__ +#define __ZTTHREADLOCAL_H__ + +#include "zthread/ThreadLocalImpl.h" + +namespace ZThread { + + /** + * @class ThreadLocal + * + * @author Eric Crahen + * @date <2003-07-27T11:18:21-0400> + * @version 2.3.0 + * + * Provides access to store and retrieve value types to and from a thread local + * storage context. A thread local storage context consists of the calling thread + * a specific ThreadLocal object. Since this context is specific to each thread + * whenever a value is stored in a ThreadLocal that is accessible from multiple + * threads, it can only be retrieved by the thread that stored it. + * + * The first time a thread accesses the value associated with a thread local storage + * context, a value is created. That value is either an initial value (determined by + * InitialValueT) or an inherited value (determined by ChildValueT). + * + * - If a threads parent had no value associated with a ThreadLocal when the thread was created, + * then the InitialValueT functor is used to create an initial value. + * + * - If a threads parent did have a value associated with a ThreadLocal when the thread was + * created, then the childValueT functor is used to create an initial value. + * + * Not all ThreadLocal's support the inheritance of values from parent threads. The default + * behavoir is to create values through the InitialValueT functor for all thread when + * they first access a thread local storage context. + * + * - Inheritance is enabled automatically when a user supplies a ChildValueT functor other + * than the default one supplied. + * + * - Inheritance can be controlled explicitly by the user through a third functor, + * InheritableValueT. + * + *

Examples

+ * + * - Default initial value + * - User-specified initial value + * - User-specified inherited value + * + *

Default initial value

+ * A ThreadLocal that does not inherit, and uses the default value + * for an int as its initial value. + * + * @code + * + * #include "zthread/ThreadLocal.h" + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * class aRunnable : public Runnable { + * ThreadLocal localValue; + * public: + * void run() { + * std::cout << localValue.get() << std::endl; + * } + * }; + * + * int main() { + * + * // Create a shared task to display ThreadLocal values + * Task task(new aRunnable); + * + * Thread t0(task); t0.wait(); + * Thread t1(task); t1.wait(); + * Thread t2(task); t2.wait(); + * + * // Output: + * + * // 0 + * // 0 + * // 0 + * + * return 0; + * + * } + * + * @endcode + * + *

User-specified initial value

+ * A ThreadLocal that does not inherit, and uses a custom initial value. + * + * @code + * + * #include "zthread/ThreadLocal.h" + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * struct anInitialValueFn { + * int operator()() { + * static int next = 100; + * int val = next; next += 100; + * return val; + * } + * }; + * + * class aRunnable : public Runnable { + * ThreadLocal localValue; + * public: + * void run() { + * std::cout << localValue.get() << std::endl; + * } + * }; + * + * int main() { + * + * // Create a shared task to display ThreadLocal values + * Task task(new aRunnable); + * + * Thread t0(task); t0.wait(); + * Thread t1(task); t1.wait(); + * Thread t2(task); t2.wait(); + * + * // Output: + * + * // 100 + * // 200 + * // 300 + * + * return 0; + * + * } + * + * @endcode + * + *

User-specified inherited value

+ * A ThreadLocal that does inherit and modify child values. + * (The default initial value functor is used) + * + * @code + * + * #include "zthread/ThreadLocal.h" + * #include "zthread/Thread.h" + * #include + * + * using namespace ZThread; + * + * struct anInheritedValueFn { + * int operator()(int val) { + * return val + 100; + * } + * }; + * + * // This Runnable associates no ThreadLocal value in the main thread; so + * // none of the child threads have anything to inherit. + * class aRunnable : public Runnable { + * ThreadLocal, anInheritedValueFn> localValue; + * public: + * void run() { + * std::cout << localValue.get() << std::endl; + * } + * }; + * + * // This Runnable associates a ThreadLocal value in the main thread which + * // is inherited when the child threads are created. + * class anotherRunnable : public Runnable { + * ThreadLocal, anInheritedValueFn> localValue; + * public: + * anotherRunnable() { + * localValue.set(100); + * } + * void run() { + * std::cout << localValue.get() << std::endl; + * } + * }; + * + * int main() { + * + * // Create a shared task to display ThreadLocal values + * Task task(new aRunnable); + * + * Thread t0(task); t0.wait(); + * Thread t1(task); t1.wait(); + * Thread t2(task); t2.wait(); + * + * // Output: + * + * // 0 + * // 0 + * // 0 + * + * task = Task(new anotherRunnable); + * + * Thread t10(task); t10.wait(); + * Thread t11(task); t11.wait(); + * Thread t12(task); t12.wait(); + * + * // Output: + * + * // 200 + * // 200 + * // 200 + * + * return 0; + * + * } + * + * @endcode + * + *

Parameters

+ * + * InitialValueT + * + * This template parameter should indicate the functor used to set + * the initial value. It should support the following operator: + * + * + * // required operator + * T operator() + * + * // supported expression + * InitialValueT()() + * + * + * + * ChildValueT + * + * This template parameter should indicate the functor used to set + * the value that will be inherited by thread whose parent have associated + * a value with the ThreadLocal's context at the time they are created. + * It should support the following operator: + * + * + * // required operator + * T operator(const T& parentValue) + * + * // supported expression + * ChildValueT()(parentValue) + * + * + * + * InheritableValueT + * + * This template parameter should indicate the functor, used to determine + * wheather or not this ThreadLocal will allow values from a parent threads + * context to be inherited by child threads when they are created. + * It should support the following operator: + * + * + * // required operator + * bool operator(const T& childValueFunctor) + * + * // supported expression + * InheritableValueT()( ChildValueT() ) + * + * + */ + template < + typename T, + typename InitialValueT = ThreadLocalImpl::InitialValueFn, + typename ChildValueT = ThreadLocalImpl::UniqueChildValueFn, + typename InheritableValueT = ThreadLocalImpl::InheritableValueFn + > + class ThreadLocal : private ThreadLocalImpl { + + typedef ThreadLocalImpl::ValuePtr ValuePtr; + + class Value : public ThreadLocalImpl::Value { + + T value; + + public: + + Value() : value( InitialValueT()() ) { } + + Value(const Value& v) : value( ChildValueT()(v.value) ) { } + + virtual ~Value() { } + + operator T() { return value; } + + const Value& operator=(const T& v) { value = v; } + + virtual bool isInheritable() const { + return InheritableValueT()( ChildValueT() ); + } + + virtual ValuePtr clone() const { + return ValuePtr( new Value(*this) ); + } + + }; + + static ValuePtr createValue() { + return ValuePtr( new Value ); + } + + public: + + /** + * Get the value associated with the context (this ThreadLocal and + * the calling thread) of the invoker. If no value is currently + * associated, then an intial value is created and associated; that value + * is returned. + * + * @return T associated value. + * + * @post If no value has been associated with the invoking context + * then an inital value will be associated. That value is + * created by the InitialValueT functor. + */ + T get() const { + return (T)reinterpret_cast( *value(&createValue) ); + } + + /** + * Replace the value associated with the context (this ThreadLocal and + * the calling thread) of the invoker. If no value is currently + * associated, then an intial value is first created and subsequently + * replaced by the new value. + * + * @param v value of type T to associate. + * + * @post If no value has been associated with the invoking context + * then an inital value will first be associated. That value is + * created by the InitialValueT functor and then + * replaced with the new value. + */ + void set(T v) const { + reinterpret_cast( *value(&createValue) ) = v; + } + + /** + * Remove any value current associated with this ThreadLocal. + * + * @post Upon thier next invocation the get() and set() functions will behave as + * if no value has been associated with this ThreadLocal and an + * initial value will be generated. + */ + void clear() const { + ThreadLocalImpl::clear(); + } + + /** + * Remove any value current associated with any ThreadLocal. + * + * @post Upon thier next invocation the get() and set() functions will behave as + * if no value has been associated with any ThreadLocal and new + * initial values will be generated. + */ + static void clearAll() { + ThreadLocalImpl::clearAll(); + } + + }; + + +} // namespace ZThread + +#endif // __ZTTHREADLOCAL_H__ diff --git a/src/dep/include/zthread/ThreadLocalImpl.h b/src/dep/include/zthread/ThreadLocalImpl.h new file mode 100644 index 0000000..3b4046f --- /dev/null +++ b/src/dep/include/zthread/ThreadLocalImpl.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADLOCALIMPL_H__ +#define __ZTTHREADLOCALIMPL_H__ + +#include "zthread/CountedPtr.h" + +namespace ZThread { + + /** + * @class ThreadLocalImpl + * @author Eric Crahen + * @date <2003-07-27T10:23:19-0400> + * @version 2.3.0 + * + * @see ThreadLocal + */ + class ZTHREAD_API ThreadLocalImpl : private NonCopyable { + public: + + class Value; + typedef CountedPtr ValuePtr; + + //! + class Value { + Value& operator=(const Value&); + public: + virtual ~Value() {} + virtual bool isInheritable() const = 0; + virtual ValuePtr clone() const = 0; + }; + + //! Create a ThreadLocalImpl + ThreadLocalImpl(); + + //! Destroy a ThreadLocalImpl + ~ThreadLocalImpl(); + + /** + * @class InitialValueFn + */ + template + struct InitialValueFn { + T operator()() { return T(); } + }; + + /** + * @class ChildValueFn + */ + struct ChildValueFn { + template + T operator()(const T& value) { return T(value); } + }; + + /** + * @class UniqueChildValueFn + */ + struct UniqueChildValueFn : public ChildValueFn { }; + + /** + * @class InheritableValueFn + */ + struct InheritableValueFn { + + template + bool operator()(const T&) { return true; } + + bool operator()(const UniqueChildValueFn&) { return false; } + + }; + + protected: + + //! Get the Value for the current thread + ValuePtr value( ValuePtr (*pfn)() ) const; + + //! Clear any value set for this thread + void clear() const; + + //! Clear any value set with any ThreadLocal for this thread + static void clearAll(); + + }; + +} // __ZTTHREADLOCALIMPL_H__ + +#endif + diff --git a/src/dep/include/zthread/ThreadedExecutor.h b/src/dep/include/zthread/ThreadedExecutor.h new file mode 100644 index 0000000..9bc29b3 --- /dev/null +++ b/src/dep/include/zthread/ThreadedExecutor.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADEDEXECUTOR_H__ +#define __ZTTHREADEDEXECUTOR_H__ + +#include "zthread/Executor.h" +#include "zthread/CountedPtr.h" + +namespace ZThread { + + namespace { class ExecutorImpl; } + + /** + * @class ThreadedExecutor + * + * @author Eric Crahen + * @date <2003-07-16T22:39:13-0400> + * @version 2.3.0 + * + * A ThreadedExecutor spawns a new thread to execute each task submitted. + * A ThreadedExecutor supports the following optional operations, + * + * - cancel()ing a ThreadedExecutor will cause it to stop accepting + * new tasks. + * + * - interrupt()ing a ThreadedExecutor will cause the any thread running + * a task which was submitted prior to the invocation of this function to + * be interrupted during the execution of that task. + * + * - wait()ing on a ThreadedExecutor will block the calling thread + * until all tasks that were submitted prior to the invocation of this function + * have completed. + * + * @see Executor. + */ + class ThreadedExecutor : public Executor { + + CountedPtr< ExecutorImpl > _impl; + + public: + + //! Create a new ThreadedExecutor + ThreadedExecutor(); + + //! Destroy a ThreadedExecutor + virtual ~ThreadedExecutor(); + + /** + * Interrupting a ThreadedExecutor will cause an interrupt() to be sent + * to every Task that has been submitted at the time this function is + * called. Tasks that are submitted after this function is called will + * not be interrupt()ed; unless this function is invoked again(). + */ + virtual void interrupt(); + + /** + * Submit a task to this Executor. This will not block the current thread + * for very long. A new thread will be created and the task will be run() + * within the context of that new thread. + * + * @exception Cancellation_Exception thrown if this Executor has been canceled. + * The Task being submitted will not be executed by this Executor. + * + * @see Executor::execute(const Task&) + */ + virtual void execute(const Task&); + + /** + * @see Cancelable::cancel() + */ + virtual void cancel(); + + /** + * @see Cancelable::isCanceled() + */ + virtual bool isCanceled(); + + /** + * Waiting on a ThreadedExecutor will block the current thread until all + * tasks submitted to the Executor up until the time this function was called + * have completed. + * + * Tasks submitted after this function is called will not delay a thread that + * was already waiting on the Executor any longer. In order to wait for + * those tasks to complete as well, another wait() would be needed. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupted + * before the set of tasks for which it was waiting complete. + * + * @see Waitable::wait() + */ + virtual void wait(); + + /** + * Operates the same as ThreadedExecutor::wait() but with a timeout. + * + * @param timeout maximum amount of time, in milliseconds, to wait for the + * currently submitted set of Tasks to complete. + * + * @exception Interrupted_Exception thrown if the calling thread is interrupt()ed + * while waiting for the current set of Tasks to complete. + * + * @return + * - true if the set of tasks running at the time this function is invoked complete + * before timeout milliseconds elapse. + * - false othewise. + * + * @see Waitable::wait(unsigned long timeout) + */ + virtual bool wait(unsigned long timeout); + + }; /* ThreadedExecutor */ + +} // namespace ZThread + +#endif // __ZTTHREADEDEXECUTOR_H__ diff --git a/src/dep/include/zthread/Time.h b/src/dep/include/zthread/Time.h new file mode 100644 index 0000000..374c4fd --- /dev/null +++ b/src/dep/include/zthread/Time.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIME_H__ +#define __ZTTIME_H__ + +#include "zthread/Config.h" + +namespace ZThread { + +/** + * @class Time + * @author Eric Crahen + * @date <2003-07-16T17:52:46-0400> + * @version 2.2.11 + * + * The Time class provides access to time values relative to when the program + * was started. In other words, this class might be thought of as a timer that + * starts at 0 and counts upwards. This class offers millisecond resolution. + */ +class ZTHREAD_API Time { + + unsigned long _seconds; + unsigned long _milliseconds; + + //! Create a new Time object + Time(unsigned long secs, unsigned long millis) + : _seconds(secs), _milliseconds(millis) { } + + /** + * Set the number of milliseconds in this Time object. + * + * @param millis - new milliseconds value + * @return unsigned long old milliseconds value + */ + unsigned long milliseconds(unsigned long millis) { + + unsigned long n = _milliseconds; + _milliseconds = millis; + + return n; + + } + + /** + * Set the number of seconds in this Time object. + * + * @param secs - new seconds value + * @return unsigned long old seconds value + */ + unsigned long seconds(unsigned long secs) { + + unsigned long n = _seconds; + _seconds = secs; + + return n; + + } + + public: + + + /** + * Create a Time object with the current time relative to the + * beginning of the program. + */ + Time(); + + /** + * Create a Time object by copying another. + * + * @param t - Time object to copy. + */ + Time(const Time& t) + : _seconds(t._seconds), _milliseconds(t._milliseconds) { } + + + /** + * Get the number of milliseconds in this Time object. + * + * @return unsigned long milliseconds value + */ + unsigned long milliseconds() const { + return _milliseconds; + } + + /** + * Get the number of seconds in this Time object. + * + * @return unsigned long seconds value + */ + unsigned long seconds() const { + return _seconds; + } + + /** + * Add some number of milliseconds to this Time object. + * + * @param millis - number of milliseconds to add to this Time object + * @return const Time& this object + */ + const Time& operator+=(unsigned long millis) { + + _milliseconds += millis; + _seconds += (_milliseconds / 1000); + _milliseconds %= 1000; + + return *this; + + } + + /** + * Subtract some number of milliseconds to this Time object. + * + * @param millis - number of milliseconds to subtract from this Time object + * @return const Time& this object + */ +const Time& operator-=(unsigned long millis) { + + if(_milliseconds > millis) + _milliseconds -= millis; + + else { + + while(_seconds > 0 && _milliseconds < millis) { + + _milliseconds += 1000; + _seconds -= 1; + + } + + _milliseconds = (_milliseconds < millis) ? 0 : (_milliseconds - millis); + + } + + return *this; + +} + + + /** + * Add the value of another Time object to this one. + * + * @param t - Time object whose value should be added to this object + * @return const Time& this object + */ + const Time& operator+=(const Time& t) { + + _milliseconds += t.milliseconds(); + _seconds += (_milliseconds / 1000) + t.seconds(); + _milliseconds %= 1000; + + return *this; + + } + + /** + * Subtract the value of another Time object from this one. + * This function has a floor of 0. + * + * @param t - Time object whose value should be subtracted from this object + * @return const Time& this object + */ +const Time& operator-=(const Time& t) { + + unsigned long millis = t.milliseconds(); + unsigned long secs = t.seconds(); + + if(_seconds >= secs) { + + if(_milliseconds > millis) { + _milliseconds -= millis; + _seconds -= secs; + + } else { + + while(_seconds > 0 && _milliseconds < millis) { + + _milliseconds += 1000; + _seconds -= 1; + + } + + _milliseconds = (_milliseconds < millis) ? 0 : (_milliseconds - millis); + _seconds = (_seconds < secs) ? 0 : (_seconds - secs); + + } + + } else { + + _milliseconds = 0; + _seconds = 0; + + } + + return *this; + +} + +}; + + + +} // namespace ZThread + +#endif // __ZTTIME_H__ diff --git a/src/dep/include/zthread/Waitable.h b/src/dep/include/zthread/Waitable.h new file mode 100644 index 0000000..3d925f2 --- /dev/null +++ b/src/dep/include/zthread/Waitable.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTWAITABLE_H__ +#define __ZTWAITABLE_H__ + +#include "zthread/Exceptions.h" + +namespace ZThread { + + /** + * @class Waitable + * + * @author Eric Crahen + * @date <2003-07-16T22:16:41-0400> + * @version 2.3.0 + * + * The Waitable interface defines a common method of adding generic wait semantics + * to a class. + * + * Waiting + * + * An object implementing the Waitable interface externalizes a mechanism for testing + * some internal condition. Another object may wait()s for a Waitable object; + * in doing so, it wait()s for that condition to become true by blocking the caller + * while the condition is false. + * + * For example, a Condition is Waitable object that extends wait semantics + * so that wait()ing means a thread is blocked until some external stimulus + * specifically performs an operation on the Condition to make its internal condition true. + * (serialization aside) + * + * A Barrier extends wait semantics so that wait()ing mean waiting for other + * waiters, and may include automatically resetting the condition once a wait is complete. + * + * @see Condition + * @see Barrier + * @see Executor + */ + class Waitable { + public: + + //! Destroy a Waitable object. + virtual ~Waitable() {} + + /** + * Waiting on an object will generally cause the calling thread to be blocked + * for some indefinite period of time. The thread executing will not proceed + * any further until the Waitable object releases it unless or an exception + * is thrown. + */ + virtual void wait() = 0; + + /** + * Waiting on an object will generally cause the calling thread to be blocked + * for some indefinite period of time. The thread executing will not proceed + * any further until the Waitable object releases it unless or an exception + * is thrown. + * + * @param timeout maximum amount of time, in milliseconds, to spend waiting. + * + * @return + * - true if the set of tasks being wait for complete before + * timeout milliseconds elapse. + * - false othewise. + */ + virtual bool wait(unsigned long timeout) = 0; + + + }; /* Waitable */ + + +} // namespace ZThread + +#endif // __ZTWAITABLE_H__ diff --git a/src/dep/include/zthread/ZThread.h b/src/dep/include/zthread/ZThread.h new file mode 100644 index 0000000..1df5bb6 --- /dev/null +++ b/src/dep/include/zthread/ZThread.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTLIBRARY_H__ +#define __ZTLIBRARY_H__ + + +#include "zthread/Barrier.h" +#include "zthread/BiasedReadWriteLock.h" +#include "zthread/BlockingQueue.h" +#include "zthread/BoundedQueue.h" +#include "zthread/Cancelable.h" +#include "zthread/ClassLockable.h" +#include "zthread/ConcurrentExecutor.h" +#include "zthread/Condition.h" +#include "zthread/Config.h" +#include "zthread/CountedPtr.h" +#include "zthread/CountingSemaphore.h" +#include "zthread/Exceptions.h" +#include "zthread/Executor.h" +#include "zthread/FairReadWriteLock.h" +#include "zthread/FastMutex.h" +#include "zthread/FastRecursiveMutex.h" +#include "zthread/Guard.h" +#include "zthread/Lockable.h" +#include "zthread/LockedQueue.h" +#include "zthread/MonitoredQueue.h" +#include "zthread/Mutex.h" +#include "zthread/NonCopyable.h" +#include "zthread/PoolExecutor.h" +#include "zthread/Priority.h" +#include "zthread/PriorityCondition.h" +#include "zthread/PriorityInheritanceMutex.h" +#include "zthread/PriorityMutex.h" +#include "zthread/PrioritySemaphore.h" +#include "zthread/Queue.h" +#include "zthread/ReadWriteLock.h" +#include "zthread/RecursiveMutex.h" +#include "zthread/Runnable.h" +#include "zthread/Semaphore.h" +#include "zthread/Singleton.h" +#include "zthread/SynchronousExecutor.h" +#include "zthread/Thread.h" +#include "zthread/ThreadLocal.h" +#include "zthread/Time.h" +#include "zthread/Waitable.h" + +#endif diff --git a/src/dep/src/zlib/Makefile.am b/src/dep/src/zlib/Makefile.am new file mode 100644 index 0000000..c7d57b1 --- /dev/null +++ b/src/dep/src/zlib/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES += -I$(srcdir)/../../include -I$(srcdir)/../../include/zlib + +noinst_LIBRARIES = libzlib.a + +libzlib_a_SOURCES = \ +adler32.c \ +compress.c \ +crc32.c \ +deflate.c \ +example.c \ +gzio.c \ +infback.c \ +inffast.c \ +inflate.c \ +inftrees.c \ +trees.c \ +uncompr.c \ +zutil.c + diff --git a/src/dep/src/zlib/Makefile.in b/src/dep/src/zlib/Makefile.in new file mode 100644 index 0000000..2af7b13 --- /dev/null +++ b/src/dep/src/zlib/Makefile.in @@ -0,0 +1,482 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# 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. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = dep/src/zlib +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libzlib_a_AR = $(AR) $(ARFLAGS) +libzlib_a_LIBADD = +am_libzlib_a_OBJECTS = adler32.$(OBJEXT) compress.$(OBJEXT) \ + crc32.$(OBJEXT) deflate.$(OBJEXT) example.$(OBJEXT) \ + gzio.$(OBJEXT) infback.$(OBJEXT) inffast.$(OBJEXT) \ + inflate.$(OBJEXT) inftrees.$(OBJEXT) trees.$(OBJEXT) \ + uncompr.$(OBJEXT) zutil.$(OBJEXT) +libzlib_a_OBJECTS = $(am_libzlib_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libzlib_a_SOURCES) +DIST_SOURCES = $(libzlib_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMPILER_OPTIONS = @COMPILER_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_COMPILER_OPTIONS = @EXTRA_COMPILER_OPTIONS@ +EXTRA_LINKER_OPTIONS = @EXTRA_LINKER_OPTIONS@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INCLUDES = @INCLUDES@ -I$(srcdir)/../../include \ + -I$(srcdir)/../../include/zlib +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINKER_OPTIONS = @LINKER_OPTIONS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LTMS_AGE = @LTMS_AGE@ +LTMS_CURRENT = @LTMS_CURRENT@ +LTMS_RELEASE = @LTMS_RELEASE@ +LTMS_REVISION = @LTMS_REVISION@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_RELEASE = @LT_RELEASE@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MANGOSD_CONFIG = @MANGOSD_CONFIG@ +MANGOSD_CONFIGDIR = @MANGOSD_CONFIGDIR@ +MANGOSD_DATA = @MANGOSD_DATA@ +MANGOSD_ENABLE_CLI = @MANGOSD_ENABLE_CLI@ +MANGOSD_ENABLE_RA = @MANGOSD_ENABLE_RA@ +MYSQL_INCLUDES = @MYSQL_INCLUDES@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +REALMD_CONFIG = @REALMD_CONFIG@ +REALMD_CONFIGDIR = @REALMD_CONFIGDIR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WITH_APIDOCS = @WITH_APIDOCS@ +WITH_APIDOCS_TARGET = @WITH_APIDOCS_TARGET@ +WITH_PYTHON_SUBDIR = @WITH_PYTHON_SUBDIR@ +WITH_PYTHON_SUBPACKAGE = @WITH_PYTHON_SUBPACKAGE@ +WITH_PYTHON_VERSION = @WITH_PYTHON_VERSION@ +__DOXYGEN = @__DOXYGEN@ +__PYTHON = @__PYTHON@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_LIBRARIES = libzlib.a +libzlib_a_SOURCES = \ +adler32.c \ +compress.c \ +crc32.c \ +deflate.c \ +example.c \ +gzio.c \ +infback.c \ +inffast.c \ +inflate.c \ +inftrees.c \ +trees.c \ +uncompr.c \ +zutil.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu dep/src/zlib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu dep/src/zlib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libzlib.a: $(libzlib_a_OBJECTS) $(libzlib_a_DEPENDENCIES) + -rm -f libzlib.a + $(libzlib_a_AR) libzlib.a $(libzlib_a_OBJECTS) $(libzlib_a_LIBADD) + $(RANLIB) libzlib.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adler32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deflate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/infback.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inffast.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inflate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inftrees.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trees.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uncompr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zutil.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/dep/src/zlib/adler32.c b/src/dep/src/zlib/adler32.c new file mode 100644 index 0000000..007ba26 --- /dev/null +++ b/src/dep/src/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/src/dep/src/zlib/compress.c b/src/dep/src/zlib/compress.c new file mode 100644 index 0000000..df04f01 --- /dev/null +++ b/src/dep/src/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/src/dep/src/zlib/crc32.c b/src/dep/src/zlib/crc32.c new file mode 100644 index 0000000..f658a9e --- /dev/null +++ b/src/dep/src/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/src/dep/src/zlib/deflate.c b/src/dep/src/zlib/deflate.c new file mode 100644 index 0000000..29ce1f6 --- /dev/null +++ b/src/dep/src/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/src/dep/src/zlib/example.c b/src/dep/src/zlib/example.c new file mode 100644 index 0000000..6c8a0ee --- /dev/null +++ b/src/dep/src/zlib/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2004 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/src/dep/src/zlib/gzio.c b/src/dep/src/zlib/gzio.c new file mode 100644 index 0000000..7e90f49 --- /dev/null +++ b/src/dep/src/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/src/dep/src/zlib/infback.c b/src/dep/src/zlib/infback.c new file mode 100644 index 0000000..455dbc9 --- /dev/null +++ b/src/dep/src/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/src/dep/src/zlib/inffast.c b/src/dep/src/zlib/inffast.c new file mode 100644 index 0000000..bbee92e --- /dev/null +++ b/src/dep/src/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/src/dep/src/zlib/inflate.c b/src/dep/src/zlib/inflate.c new file mode 100644 index 0000000..792fdee --- /dev/null +++ b/src/dep/src/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/src/dep/src/zlib/inftrees.c b/src/dep/src/zlib/inftrees.c new file mode 100644 index 0000000..8a9c13f --- /dev/null +++ b/src/dep/src/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/src/dep/src/zlib/trees.c b/src/dep/src/zlib/trees.c new file mode 100644 index 0000000..395e4e1 --- /dev/null +++ b/src/dep/src/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/src/dep/src/zlib/uncompr.c b/src/dep/src/zlib/uncompr.c new file mode 100644 index 0000000..b59e3d0 --- /dev/null +++ b/src/dep/src/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/src/dep/src/zlib/zutil.c b/src/dep/src/zlib/zutil.c new file mode 100644 index 0000000..d55f594 --- /dev/null +++ b/src/dep/src/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/src/dep/src/zthread/AtomicCount.cxx b/src/dep/src/zthread/AtomicCount.cxx new file mode 100644 index 0000000..ac0d077 --- /dev/null +++ b/src/dep/src/zthread/AtomicCount.cxx @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNTSELECT_H__ +#define __ZTATOMICCOUNTSELECT_H__ + +#include "zthread/AtomicCount.h" +#include "zthread/Config.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* +// Select the correct AtomicCount implementation based on +// what the compilation environment has defined + +#ifndef ZT_VANILLA + +#if defined(HAVE_ATOMIC_LINUX) +# include "linux/AtomicCount.cxx" +#elif defined(ZT_WIN32) +# include "win32/AtomicCount.cxx" +#elif defined(ZT_WIN9X) +# include "win9x/AtomicCount.cxx" +#endif + +#endif + +// Default to an AtomicCount that just uses a FastLock +#ifndef __ZTATOMICCOUNTIMPL_H__ +# include "vanilla/SimpleAtomicCount.cxx" +#endif +*/ + +# include "vanilla/SimpleAtomicCount.cxx" + +#endif // __ZTATOMICCOUNTSELECT_H__ diff --git a/src/dep/src/zthread/ConcurrentExecutor.cxx b/src/dep/src/zthread/ConcurrentExecutor.cxx new file mode 100644 index 0000000..a65e9c5 --- /dev/null +++ b/src/dep/src/zthread/ConcurrentExecutor.cxx @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/ConcurrentExecutor.h" + +namespace ZThread { + + ConcurrentExecutor::ConcurrentExecutor() + : _executor(1) {} + + void ConcurrentExecutor::interrupt() { + _executor.interrupt(); + } + + void ConcurrentExecutor::execute(const Task& task) { + _executor.execute(task); + } + + void ConcurrentExecutor::cancel() { + _executor.cancel(); + } + + bool ConcurrentExecutor::isCanceled() { + return _executor.isCanceled(); + } + + void ConcurrentExecutor::wait() { + _executor.wait(); + } + + bool ConcurrentExecutor::wait(unsigned long timeout) { + return _executor.wait(timeout); + } + +} diff --git a/src/dep/src/zthread/Condition.cxx b/src/dep/src/zthread/Condition.cxx new file mode 100644 index 0000000..39485fb --- /dev/null +++ b/src/dep/src/zthread/Condition.cxx @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Condition.h" +#include "ConditionImpl.h" + +namespace ZThread { + + class FifoConditionImpl : public ConditionImpl { + public: + FifoConditionImpl(Lockable& l) : ConditionImpl(l) {} + + }; + + Condition::Condition(Lockable& lock) { + + _impl = new FifoConditionImpl(lock); + + } + + + Condition::~Condition() { + + if(_impl != 0) + delete _impl; + + } + + + + void Condition::wait() { + + _impl->wait(); + + } + + + + bool Condition::wait(unsigned long ms) { + + return _impl->wait(ms); + + } + + + + void Condition::signal() { + + _impl->signal(); + + } + + + void Condition::broadcast() { + + _impl->broadcast(); + + } + +} // namespace ZThread + diff --git a/src/dep/src/zthread/ConditionImpl.h b/src/dep/src/zthread/ConditionImpl.h new file mode 100644 index 0000000..6a450cc --- /dev/null +++ b/src/dep/src/zthread/ConditionImpl.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTCONDITIONIMPL_H__ +#define __ZTCONDITIONIMPL_H__ + +#include "zthread/Guard.h" + +#include "Debug.h" +#include "Scheduling.h" +#include "DeferredInterruptionScope.h" + +namespace ZThread { + +/** + * @class ConditionImpl + * @author Eric Crahen + * @date <2003-07-18T08:15:37-0400> + * @version 2.2.11 + * + * The ConditionImpl template allows how waiter lists are sorted + * to be parameteized + */ +template +class ConditionImpl { + + //! Waiters currently blocked + List _waiters; + + //! Serialize access to this object + FastLock _lock; + + //! External lock + Lockable& _predicateLock; + + public: + + /** + * Create a new ConditionImpl. + * + * @exception Initialization_Exception thrown if resources could not be + * allocated + */ + ConditionImpl(Lockable& predicateLock) : _predicateLock(predicateLock) { + + } + + /** + * Destroy this ConditionImpl, release its resources + */ + ~ConditionImpl(); + + void signal(); + + void broadcast(); + + void wait(); + + bool wait(unsigned long timeout); + +}; + + +template +ConditionImpl::~ConditionImpl() { + +#ifndef NDEBUG + + // It is an error to destroy a condition with threads waiting on it. + if(_waiters.size() != 0) { + + ZTDEBUG("** You are destroying a condition variable which still has waiting threads. **\n"); + assert(0); + + } + +#endif + + } + + +/** + * Signal the condition variable, waking one thread if any. + */ +template +void ConditionImpl::signal() { + + Guard g1(_lock); + + // Try to find a waiter with a backoff & retry scheme + for(;;) { + + // Go through the list, attempt to notify() a waiter. + for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) { + + // Try the monitor lock, if it cant be locked skip to the next waiter + ThreadImpl* impl = *i; + Monitor& m = impl->getMonitor(); + + if(m.tryAcquire()) { + + // Notify the monitor & remove from the waiter list so time isn't + // wasted checking it again. + i = _waiters.erase(i); + + // If notify() is not sucessful, it is because the wait() has already + // been ended (killed/interrupted/notify'd) + bool woke = m.notify(); + + m.release(); + + // Once notify() succeeds, return + if(woke) + return; + + } else ++i; + + } + + if(_waiters.empty()) + return; + + { // Backoff and try again + + Guard g2(g1); + ThreadImpl::yield(); + + } + + } + + } + +/** + * Broadcast to the condition variable, waking all threads waiting at the time of + * the broadcast. + */ +template +void ConditionImpl::broadcast() { + + Guard g1(_lock); + + // Try to find a waiter with a backoff & retry scheme + for(;;) { + + // Go through the list, attempt to notify() a waiter. + for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) { + + // Try the monitor lock, if it cant be locked skip to the next waiter + ThreadImpl* impl = *i; + Monitor& m = impl->getMonitor(); + + if(m.tryAcquire()) { + + // Notify the monitor & remove from the waiter list so time isn't + // wasted checking it again. + i = _waiters.erase(i); + + // Try to wake the waiter, it doesn't matter if this is successful + // or not (only fails when the monitor is already going to stop waiting). + m.notify(); + + m.release(); + + } else ++i; + + } + + if(_waiters.empty()) + return; + + { // Backoff and try again + + Guard g2(g1); + ThreadImpl::yield(); + + } + + } + + } + +/** + * Cause the currently executing thread to block until this ConditionImpl has + * been signaled, the threads state changes. + * + * @param predicate Lockable& + * + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ +template +void ConditionImpl::wait() { + + // Get the monitor for the current thread + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Monitor::STATE state; + + { + + Guard g1(_lock); + + // Release the _predicateLock + _predicateLock.release(); + + // Stuff the waiter into the list + _waiters.insert(self); + + // Move to the monitor's lock + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(); + + } + + // Move back to the Condition's lock + m.release(); + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + } + + // Defer interruption until the external lock is acquire()d + Guard g3(m); + { + +#if !defined(NDEBUG) + try { +#endif + _predicateLock.acquire(); // Should not throw +#if !defined(NDEBUG) + } catch(...) { assert(0); } +#endif + + } + + switch(state) { + + case Monitor::SIGNALED: + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + throw Synchronization_Exception(); + } + + } + + +/** + * Cause the currently executing thread to block until this ConditionImpl has + * been signaled, or the timeout expires or the threads state changes. + * + * @param _predicateLock Lockable& + * @param timeout maximum milliseconds to block. + * + * @return bool + * + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ +template +bool ConditionImpl::wait(unsigned long timeout) { + + // Get the monitor for the current thread + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Monitor::STATE state; + + { + + Guard g1(_lock); + + // Release the _predicateLock + _predicateLock.release(); + + // Stuff the waiter into the list + _waiters.insert(self); + + state = Monitor::TIMEDOUT; + + // Don't bother waiting if the timeout is 0 + if(timeout) { + + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(timeout); + + } + + m.release(); + + } + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + } + + + // Defer interruption until the external lock is acquire()d + Guard g3(m); + { + +#if !defined(NDEBUG) + try { +#endif + _predicateLock.acquire(); // Should not throw +#if !defined(NDEBUG) + } catch(...) { assert(0); } +#endif + + } + + switch(state) { + + case Monitor::SIGNALED: + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + case Monitor::TIMEDOUT: + return false; + + default: + throw Synchronization_Exception(); + } + + return true; + + } + +} // namespace ZThread + +#endif // __ZTCONDITIONIMPL_H__ diff --git a/src/dep/src/zthread/CountingSemaphore.cxx b/src/dep/src/zthread/CountingSemaphore.cxx new file mode 100644 index 0000000..43e8b8c --- /dev/null +++ b/src/dep/src/zthread/CountingSemaphore.cxx @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/CountingSemaphore.h" +#include "SemaphoreImpl.h" + +using namespace ZThread; + +namespace ZThread { + + + CountingSemaphore::CountingSemaphore(int initialCount) { + + _impl = new FifoSemaphoreImpl(initialCount, 0 , false); + + } + + + CountingSemaphore::~CountingSemaphore() { + + try { + + if(_impl != 0) + delete _impl; + + } catch(...) { } + + } + + + void CountingSemaphore::wait() { + _impl->acquire(); + } + + + bool CountingSemaphore::tryWait(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + + void CountingSemaphore::post() { + + _impl->release(); + + } + + int CountingSemaphore::count() { + + return _impl->count(); + + } + + void CountingSemaphore::acquire() { + + _impl->acquire(); + + } + + bool CountingSemaphore::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + void CountingSemaphore::release() { + + _impl->release(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/Debug.h b/src/dep/src/zthread/Debug.h new file mode 100644 index 0000000..484b37f --- /dev/null +++ b/src/dep/src/zthread/Debug.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef ZTDEBUG + +#ifndef NDEBUG +# include +# define ZTDEBUG printf +#else +# define ZTDEBUG(x) +#endif + +#endif diff --git a/src/dep/src/zthread/DeferredInterruptionScope.h b/src/dep/src/zthread/DeferredInterruptionScope.h new file mode 100644 index 0000000..041d1e4 --- /dev/null +++ b/src/dep/src/zthread/DeferredInterruptionScope.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTDEFERREDINTERRUPTIONSCOPE_H__ +#define __ZTDEFERREDINTERRUPTIONSCOPE_H__ + +#include "ThreadImpl.h" +#include + +namespace ZThread { + +/** + * @class DeferredInterruptionScope + * @author Eric Crahen + * @date <2003-07-16T19:45:18-0400> + * @version 2.3.0 + * + * Locking policy for a Guard that will defer any state reported + * for the reported Status of a thread except SIGNALED until the + * scope has ended. This allows a Guard to be used to create an + * uninterruptible region in code. + */ +class DeferredInterruptionScope { + public: + + template + static void createScope(LockHolder& l) { + + l.getLock().interest(Monitor::SIGNALED); + + } + + template + static void destroyScope(LockHolder& l) { + + l.getLock().interest(Monitor::ANYTHING); + + } + +}; + +} + +#endif // __ZTDEFERREDINTERRUPTIONSCOPE_H__ diff --git a/src/dep/src/zthread/FastLock.h b/src/dep/src/zthread/FastLock.h new file mode 100644 index 0000000..4d7f34a --- /dev/null +++ b/src/dep/src/zthread/FastLock.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCKSELECT_H__ +#define __ZTFASTLOCKSELECT_H__ + +#include "zthread/Config.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// Select the correct FastLock implementation based on +// what the compilation environment has defined + +#if defined(ZT_POSIX) + +# if defined(HAVE_ATOMIC_LINUX) + +# if defined(ZTHREAD_USE_SPIN_LOCKS) +# include "linux/AtomicFastLock.h" +# endif + +# endif + +# include "posix/FastLock.h" + +// Use spin locks +#elif defined(ZTHREAD_USE_SPIN_LOCKS) + +# if defined(ZT_WIN9X) +# include "win9x/AtomicFastLock.h" +# elif defined(ZT_WIN32) +# include "win32/AtomicFastLock.h" +# endif + +// Use normal Mutex objects +#elif defined(ZT_WIN9X) || defined(ZT_WIN32) + +# include "win32/FastLock.h" + +#elif defined(ZT_MACOS) + +# include "macos/FastLock.h" + +#endif + +#ifndef __ZTFASTLOCK_H__ +#error "No FastLock implementation could be selected" +#endif + +#endif // __ZTFASTLOCKSELECT_H__ diff --git a/src/dep/src/zthread/FastMutex.cxx b/src/dep/src/zthread/FastMutex.cxx new file mode 100644 index 0000000..464dd83 --- /dev/null +++ b/src/dep/src/zthread/FastMutex.cxx @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/FastMutex.h" +#include "FastLock.h" + +namespace ZThread { + + FastMutex::FastMutex() : _lock(new FastLock) { } + + FastMutex::~FastMutex() { + delete _lock; + } + + + void FastMutex::acquire() { + + _lock->acquire(); + + } + + bool FastMutex::tryAcquire(unsigned long timeout) { + + return _lock->tryAcquire(timeout); + + } + + void FastMutex::release() { + + _lock->release(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/FastRecursiveLock.h b/src/dep/src/zthread/FastRecursiveLock.h new file mode 100644 index 0000000..0a36f62 --- /dev/null +++ b/src/dep/src/zthread/FastRecursiveLock.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCKSELECT_H__ +#define __ZTFASTRECURSIVELOCKSELECT_H__ + +#include "zthread/Config.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +// Select the correct FastRecusriveLock implementation based on +// what the compilation environment has defined + +#if defined(ZTHREAD_DUAL_LOCKS) +# include "vanilla/DualMutexRecursiveLock.h" +#else + +# ifndef ZT_VANILLA + +# if defined(ZT_POSIX) + +// Linux and Solaris have working pthreads recursive locks. These +// are created differently, and there are some system don't seem to +// include recursive locks at all. Several recursive implementations +// are provided + +# if defined(__linux__) +# include "linux/FastRecursiveLock.h" +# elif defined(HAVE_MUTEXATTR_SETTYPE) +# include "solaris/FastRecursiveLock.h" +# elif defined(ZTHREAD_CONDITION_LOCKS) +# include "posix/ConditionRecursiveLock.h" +# endif + +// Use spin locks +# elif defined(ZT_WIN32) && defined(ZTHREAD_USE_SPIN_LOCKS) +# include "win32/AtomicFastRecursiveLock.h" + +// Use normal Mutex objects +# elif defined(ZT_WIN32) || defined(ZT_WIN9X) +# include "win32/FastRecursiveLock.h" +# endif + +# endif + +#endif + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#include "vanilla/SimpleRecursiveLock.h" +#endif + +#endif // __ZTFASTRECURSIVELOCKSELECT_H__ diff --git a/src/dep/src/zthread/FastRecursiveMutex.cxx b/src/dep/src/zthread/FastRecursiveMutex.cxx new file mode 100644 index 0000000..5ca677a --- /dev/null +++ b/src/dep/src/zthread/FastRecursiveMutex.cxx @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/FastRecursiveMutex.h" +#include "FastRecursiveLock.h" + +namespace ZThread { + + FastRecursiveMutex::FastRecursiveMutex() + : _lock(new FastRecursiveLock) { } + + FastRecursiveMutex::~FastRecursiveMutex() + { delete _lock; } + + + void FastRecursiveMutex::acquire() { + + _lock->acquire(); + + } + + bool FastRecursiveMutex::tryAcquire(unsigned long timeout) { + + return _lock->tryAcquire(timeout); + + } + + void FastRecursiveMutex::release() { + + _lock->release(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/IntrusivePtr.h b/src/dep/src/zthread/IntrusivePtr.h new file mode 100644 index 0000000..47d5afb --- /dev/null +++ b/src/dep/src/zthread/IntrusivePtr.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTINTRUSIVEPTR_H__ +#define __ZTINTRUSIVEPTR_H__ + +#include "zthread/Guard.h" +#include + +namespace ZThread { + +/** + * @class IntrusivePtr + * @author Eric Crahen + * @date <2003-07-16T17:54:23-0400> + * @version 2.2.0 + * + * This template creates an intrusively reference counted object + * an IntrusivePtr starts out with a 1 count, which is updated as references are + * added and removed. When the reference count drops to 0, the + * IntrusivePtr will delete itself. + */ +template +class IntrusivePtr : NonCopyable { + + //! Intrusive reference count + size_t _count; + + //! Synchornization object + LockType _lock; + +public: + + /** + * Create an IntrusivePtr with a count. + */ + IntrusivePtr(size_t InitialCount=1) : _count(InitialCount) { } + + /** + * Destroy an IntrusivePtr + */ + virtual ~IntrusivePtr() {} + + /** + * Add a reference to this object, it will take one more + * call to delReference() for it to be deleted. + */ + void addReference() { + + Guard g(_lock); + _count++; + + } + + /** + * Remove a reference from this object, if the reference count + * drops to 0 as a result, the object deletes itself. + */ + void delReference() { + + bool result = false; + + { + + Guard g(_lock); + result = (--_count == 0); + + } + + if(result) + delete this; + + } + +}; + + +}; + +#endif diff --git a/src/dep/src/zthread/Makefile.am b/src/dep/src/zthread/Makefile.am new file mode 100644 index 0000000..dc47166 --- /dev/null +++ b/src/dep/src/zthread/Makefile.am @@ -0,0 +1,62 @@ +## Copyright (c) 2005, Eric Crahen +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is furnished +## to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +AM_CXXFLAGS = @COMPILER_OPTIONS@ @EXTRA_COMPILER_OPTIONS@ +INCLUDES += -I$(srcdir)/../../include -I$(srcdir)/../../include/zthread +SUBDIRS=. + +libdir=$(prefix)/lib + +lib_LTLIBRARIES = libZThread.la + +libZThread_la_LIBADD=@LINKER_OPTIONS@ @EXTRA_LINKER_OPTIONS@ +libZThread_la_LDFLAGS= \ + -release $(LT_RELEASE) \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + + +LIBADD=@LINKER_OPTIONS@ @EXTRA_LINKER_OPTIONS@ + + +libZThread_la_SOURCES = \ +AtomicCount.cxx \ +Condition.cxx \ +ConcurrentExecutor.cxx \ +CountingSemaphore.cxx \ +FastMutex.cxx \ +FastRecursiveMutex.cxx \ +Mutex.cxx \ +RecursiveMutexImpl.cxx \ +RecursiveMutex.cxx \ +Monitor.cxx \ +PoolExecutor.cxx \ +PriorityCondition.cxx \ +PriorityInheritanceMutex.cxx \ +PriorityMutex.cxx \ +PrioritySemaphore.cxx \ +Semaphore.cxx \ +SynchronousExecutor.cxx \ +Thread.cxx \ +ThreadedExecutor.cxx \ +ThreadImpl.cxx \ +ThreadLocalImpl.cxx \ +ThreadQueue.cxx \ +Time.cxx \ +ThreadOps.cxx + diff --git a/src/dep/src/zthread/Makefile.in b/src/dep/src/zthread/Makefile.in new file mode 100644 index 0000000..e167ce4 --- /dev/null +++ b/src/dep/src/zthread/Makefile.in @@ -0,0 +1,659 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# 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. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = dep/src/zthread +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libZThread_la_DEPENDENCIES = +am_libZThread_la_OBJECTS = AtomicCount.lo Condition.lo \ + ConcurrentExecutor.lo CountingSemaphore.lo FastMutex.lo \ + FastRecursiveMutex.lo Mutex.lo RecursiveMutexImpl.lo \ + RecursiveMutex.lo Monitor.lo PoolExecutor.lo \ + PriorityCondition.lo PriorityInheritanceMutex.lo \ + PriorityMutex.lo PrioritySemaphore.lo Semaphore.lo \ + SynchronousExecutor.lo Thread.lo ThreadedExecutor.lo \ + ThreadImpl.lo ThreadLocalImpl.lo ThreadQueue.lo Time.lo \ + ThreadOps.lo +libZThread_la_OBJECTS = $(am_libZThread_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libZThread_la_SOURCES) +DIST_SOURCES = $(libZThread_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMPILER_OPTIONS = @COMPILER_OPTIONS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_COMPILER_OPTIONS = @EXTRA_COMPILER_OPTIONS@ +EXTRA_LINKER_OPTIONS = @EXTRA_LINKER_OPTIONS@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INCLUDES = @INCLUDES@ -I$(srcdir)/../../include \ + -I$(srcdir)/../../include/zthread +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINKER_OPTIONS = @LINKER_OPTIONS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LTMS_AGE = @LTMS_AGE@ +LTMS_CURRENT = @LTMS_CURRENT@ +LTMS_RELEASE = @LTMS_RELEASE@ +LTMS_REVISION = @LTMS_REVISION@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_RELEASE = @LT_RELEASE@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MANGOSD_CONFIG = @MANGOSD_CONFIG@ +MANGOSD_CONFIGDIR = @MANGOSD_CONFIGDIR@ +MANGOSD_DATA = @MANGOSD_DATA@ +MANGOSD_ENABLE_CLI = @MANGOSD_ENABLE_CLI@ +MANGOSD_ENABLE_RA = @MANGOSD_ENABLE_RA@ +MYSQL_INCLUDES = @MYSQL_INCLUDES@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +REALMD_CONFIG = @REALMD_CONFIG@ +REALMD_CONFIGDIR = @REALMD_CONFIGDIR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WITH_APIDOCS = @WITH_APIDOCS@ +WITH_APIDOCS_TARGET = @WITH_APIDOCS_TARGET@ +WITH_PYTHON_SUBDIR = @WITH_PYTHON_SUBDIR@ +WITH_PYTHON_SUBPACKAGE = @WITH_PYTHON_SUBPACKAGE@ +WITH_PYTHON_VERSION = @WITH_PYTHON_VERSION@ +__DOXYGEN = @__DOXYGEN@ +__PYTHON = @__PYTHON@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = $(prefix)/lib +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CXXFLAGS = @COMPILER_OPTIONS@ @EXTRA_COMPILER_OPTIONS@ +SUBDIRS = . +lib_LTLIBRARIES = libZThread.la +libZThread_la_LIBADD = @LINKER_OPTIONS@ @EXTRA_LINKER_OPTIONS@ +libZThread_la_LDFLAGS = \ + -release $(LT_RELEASE) \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +LIBADD = @LINKER_OPTIONS@ @EXTRA_LINKER_OPTIONS@ +libZThread_la_SOURCES = \ +AtomicCount.cxx \ +Condition.cxx \ +ConcurrentExecutor.cxx \ +CountingSemaphore.cxx \ +FastMutex.cxx \ +FastRecursiveMutex.cxx \ +Mutex.cxx \ +RecursiveMutexImpl.cxx \ +RecursiveMutex.cxx \ +Monitor.cxx \ +PoolExecutor.cxx \ +PriorityCondition.cxx \ +PriorityInheritanceMutex.cxx \ +PriorityMutex.cxx \ +PrioritySemaphore.cxx \ +Semaphore.cxx \ +SynchronousExecutor.cxx \ +Thread.cxx \ +ThreadedExecutor.cxx \ +ThreadImpl.cxx \ +ThreadLocalImpl.cxx \ +ThreadQueue.cxx \ +Time.cxx \ +ThreadOps.cxx + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cxx .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu dep/src/zthread/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu dep/src/zthread/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libZThread.la: $(libZThread_la_OBJECTS) $(libZThread_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libZThread_la_LDFLAGS) $(libZThread_la_OBJECTS) $(libZThread_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AtomicCount.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConcurrentExecutor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Condition.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CountingSemaphore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FastMutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FastRecursiveMutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Monitor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Mutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PoolExecutor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PriorityCondition.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PriorityInheritanceMutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PriorityMutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PrioritySemaphore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RecursiveMutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RecursiveMutexImpl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Semaphore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SynchronousExecutor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadImpl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadLocalImpl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadOps.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadQueue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadedExecutor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Time.Plo@am__quote@ + +.cxx.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-libLTLIBRARIES install-man \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-info-am uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/dep/src/zthread/Monitor.cxx b/src/dep/src/zthread/Monitor.cxx new file mode 100644 index 0000000..9a578e7 --- /dev/null +++ b/src/dep/src/zthread/Monitor.cxx @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITORIMPLSELECT_CXX__ +#define __ZTMONITORIMPLSELECT_CXX__ + +#include "Monitor.h" + +// This file will select an implementation for a Monitor based on +// what Monitor.h selects. This method is for selecting the +// source files, to improve portability. Currently, the project is +// based on the autoconf tool-set, which doesn't support conditional +// compilation well. Additionally, this should make the library +// easier to port since its working around conditional compilation +// by using C++ features and people won't have to fiddle around with +// their make tool as much to compile the source + +#include ZT_MONITOR_IMPLEMENTATION + +#endif diff --git a/src/dep/src/zthread/Monitor.h b/src/dep/src/zthread/Monitor.h new file mode 100644 index 0000000..6f9492f --- /dev/null +++ b/src/dep/src/zthread/Monitor.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITORSELECT_H__ +#define __ZTMONITORSELECT_H__ + +#include "zthread/Config.h" + +#if defined(ZT_MONITOR_IMPLEMENTATION) +# error "Reserved symbol defined" +#endif + +// Include the dependencies for a Montior +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +// Select the correct Monitor implementation based on +// what the compilation environment has defined +#if defined(ZT_POSIX) + +# include "posix/Monitor.h" +# define ZT_MONITOR_IMPLEMENTATION "posix/Monitor.cxx" + +#elif defined(ZT_WIN32) || defined(ZT_WIN9X) + +# include "win32/Monitor.h" +# define ZT_MONITOR_IMPLEMENTATION "win32/Monitor.cxx" + +#elif defined(ZT_MACOS) + +# include "macos/Monitor.h" +# define ZT_MONITOR_IMPLEMENTATION "macos/Monitor.cxx" + +#endif + +#ifndef __ZTMONITOR_H__ +#error "No Monitor implementation could be selected" +#endif + +#endif // __ZTMONITORSELECT_H__ diff --git a/src/dep/src/zthread/Mutex.cxx b/src/dep/src/zthread/Mutex.cxx new file mode 100644 index 0000000..eca38ba --- /dev/null +++ b/src/dep/src/zthread/Mutex.cxx @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Mutex.h" +#include "MutexImpl.h" + +namespace ZThread { + + class FifoMutexImpl : public MutexImpl { }; + + + Mutex::Mutex() { + + _impl = new FifoMutexImpl(); + + } + + Mutex::~Mutex() { + + if(_impl != 0) + delete _impl; + } + + // P + void Mutex::acquire() { + + _impl->acquire(); + + } + + + // P + bool Mutex::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + // V + void Mutex::release() { + + _impl->release(); + + } + + + +} // namespace ZThread + diff --git a/src/dep/src/zthread/MutexImpl.h b/src/dep/src/zthread/MutexImpl.h new file mode 100644 index 0000000..212e567 --- /dev/null +++ b/src/dep/src/zthread/MutexImpl.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Exceptions.h" +#include "zthread/Guard.h" + +#include "Debug.h" +#include "FastLock.h" +#include "Scheduling.h" + +#include +#include + +namespace ZThread { + + +/** + * @author Eric Crahen + * @date <2003-07-16T19:52:12-0400> + * @version 2.2.11 + * @class NullBehavior + */ +class NullBehavior { +protected: + + inline void waiterArrived(ThreadImpl*) { } + + inline void waiterDeparted(ThreadImpl*) { } + + inline void ownerAcquired(ThreadImpl*) { } + + inline void ownerReleased(ThreadImpl*) { } + +}; + +/** + * @author Eric Crahen + * @date <2003-07-16T19:52:12-0400> + * @version 2.2.11 + * @class MutexImpl + * + * The MutexImpl template allows how waiter lists are sorted, and + * what actions are taken when a thread interacts with the mutex + * to be parametized. + */ +template +class MutexImpl : Behavior { + + //! List of Events that are waiting for notification + List _waiters; + + //! Serialize access to this Mutex + FastLock _lock; + + //! Current owner + volatile ThreadImpl* _owner; + + public: + + + /** + * Create a new MutexImpl + * + * @exception Initialization_Exception thrown if resources could not be + * properly allocated + */ + MutexImpl() : _owner(0) { } + + ~MutexImpl(); + + void acquire(); + + void release(); + + bool tryAcquire(unsigned long timeout); + +}; + + /** + * Destroy this MutexImpl and release its resources + */ +template +MutexImpl::~MutexImpl() { + +#ifndef NDEBUG + + // It is an error to destroy a mutex that has not been released + if(_owner != 0) { + + ZTDEBUG("** You are destroying a mutex which was never released. **\n"); + assert(0); // Destroyed mutex while in use + + } + + if(_waiters.size() > 0) { + + ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size()); + assert(0); // Destroyed mutex while in use + + } + +#endif + + } + + + /** + * Acquire a lock on the mutex. If this operation succeeds the calling + * thread holds an exclusive lock on this mutex, otherwise it is blocked + * until the lock can be acquired. + * + * @exception Deadlock_Exception thrown when the caller attempts to acquire() more + * than once, If the checking flag is set. + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ +template +void MutexImpl::acquire() { + + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Monitor::STATE state; + + Guard g1(_lock); + + // Deadlock will occur if the current thread is the owner + // and there is no entry count. + if(_owner == self) + throw Deadlock_Exception(); + + // Acquire the lock if it is free and there are no waiting threads + if(_owner == 0 && _waiters.empty()) { + + _owner = self; + + this->ownerAcquired(self); + + } + + // Otherwise, wait for a signal from a thread releasing its + // ownership of the lock + else { + + _waiters.insert(self); + m.acquire(); + + this->waiterArrived(self); + + { + + Guard g2(g1); + state = m.wait(); + + } + + this->waiterDeparted(self); + + m.release(); + + // Remove from waiter list, regardless of wether release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called (e.g. interrupted) + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + // If awoke due to a notify(), take ownership. + switch(state) { + case Monitor::SIGNALED: + + assert(_owner == 0); + _owner = self; + + this->ownerAcquired(self); + + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + throw Synchronization_Exception(); + } + + } + + } + + + /** + * Acquire a lock on the mutex. If this operation succeeds the calling + * thread holds an exclusive lock on this mutex. If the lock cannot be + * obtained before the timeout expires, the caller returns false. + * + * @exception Deadlock_Exception thrown when the caller attempts to acquire() more + * than once, If the checking flag is set. + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ +template +bool MutexImpl::tryAcquire(unsigned long timeout) { + + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Guard g1(_lock); + + // Deadlock will occur if the current thread is the owner + // and there is no entry count. + if(_owner == self) + throw Deadlock_Exception(); + + // Acquire the lock if it is free and there are no waiting threads + if(_owner == 0 && _waiters.empty()) { + + _owner = self; + + this->ownerAcquired(self); + + } + + // Otherwise, wait for a signal from a thread releasing its + // ownership of the lock + else { + + _waiters.insert(self); + + Monitor::STATE state = Monitor::TIMEDOUT; + + // Don't bother waiting if the timeout is 0 + if(timeout) { + + m.acquire(); + + this->waiterArrived(self); + + { + + Guard g2(g1); + state = m.wait(timeout); + + } + + this->waiterDeparted(self); + + m.release(); + + } + + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + // If awoke due to a notify(), take ownership. + switch(state) { + case Monitor::SIGNALED: + + assert(0 == _owner); + _owner = self; + + this->ownerAcquired(self); + + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + case Monitor::TIMEDOUT: + return false; + + default: + throw Synchronization_Exception(); + } + + } + + return true; + + } + + /** + * Release a lock on the mutex. If this operation succeeds the calling + * thread no longer holds an exclusive lock on this mutex. If there are + * waiting threads, one will be selected, assigned ownership and specifically + * awakened. + * + * @exception InvalidOp_Exception - thrown if an attempt is made to + * release a mutex not owned by the calling thread. + */ +template +void MutexImpl::release() { + + ThreadImpl* impl = ThreadImpl::current(); + + Guard g1(_lock); + + // Make sure the operation is valid + if(_owner != impl) + throw InvalidOp_Exception(); + + _owner = 0; + + this->ownerReleased(impl); + + // Try to find a waiter with a backoff & retry scheme + for(;;) { + + // Go through the list, attempt to notify() a waiter. + for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) { + + // Try the monitor lock, if it cant be locked skip to the next waiter + impl = *i; + Monitor& m = impl->getMonitor(); + + if(m.tryAcquire()) { + + // If notify() is not sucessful, it is because the wait() has already + // been ended (killed/interrupted/notify'd) + bool woke = m.notify(); + + m.release(); + + // Once notify() succeeds, return + if(woke) + return; + + } else ++i; + + } + + if(_waiters.empty()) + return; + + { // Backoff and try again + + Guard g2(g1); + ThreadImpl::yield(); + + } + + } + + } + +} // namespace ZThread + + + + + + diff --git a/src/dep/src/zthread/PoolExecutor.cxx b/src/dep/src/zthread/PoolExecutor.cxx new file mode 100644 index 0000000..cf84e14 --- /dev/null +++ b/src/dep/src/zthread/PoolExecutor.cxx @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ThreadImpl.h" +#include "zthread/PoolExecutor.h" +#include "zthread/MonitoredQueue.h" +#include "zthread/FastMutex.h" +#include "ThreadImpl.h" +#include "ThreadQueue.h" + +#include +#include +#include + +using namespace ZThread; + +namespace ZThread { + + namespace { + + /** + */ + class WaiterQueue { + + typedef std::deque ThreadList; + + typedef struct group_t { + size_t id; + size_t count; + ThreadList waiters; + group_t(size_t n) : id(n), count(0) {} + } Group; + + typedef std::deque GroupList; + + //! Predicate to find a specific group + struct by_id : public std::unary_function { + size_t id; + by_id(size_t n) : id(n) {} + bool operator()(const Group& grp) { + return grp.id == id; + } + }; + + //! Functor to count groups + struct counter : public std::unary_function { + size_t count; + counter() : count(0) {} + void operator()(const Group& grp) { count += grp.count; } + operator size_t() { return count; } + }; + + FastMutex _lock; + GroupList _list; + size_t _id; + size_t _generation; + + public: + + WaiterQueue() : _id(0), _generation(0) { + // At least one empty-group exists + _list.push_back( Group(_id++) ); + } + + /** + * Insert the current thread into the current waiter list + * + * @pre At least one empty group exists + * @post At least one empty group exists + */ + bool wait(unsigned long timeout) { + + ThreadImpl* current = ThreadImpl::current(); + Monitor& m = current->getMonitor(); + + Monitor::STATE state; + + Guard g1(_lock); + + // At least one empty-group exists + assert(!_list.empty()); + + // Return w/o waiting if there are no executing tasks + if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1) + return true; + + // Update the waiter list for the active group + _list.back().waiters.push_back(current); + size_t n = _list.back().id; + + m.acquire(); + + { + + Guard g2(g1); + state = timeout == 0 ? m.wait() : m.wait(timeout); + + } + + m.release(); + + // If awoke due to a reason other than the last task in the group 'n' completing, + // then then find the group 'current' is waiting in + GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n)); + if(i != _list.end()) { + + // Remove 'current' from that list if it is still a member + ThreadList::iterator j = std::find(i->waiters.begin(), i->waiters.end(), current); + if(j != i->waiters.end()) + i->waiters.erase(j); + + } + + // At least one empty-group exists + assert(!_list.empty()); + + switch(state) { + case Monitor::SIGNALED: + break; + case Monitor::TIMEDOUT: + return false; + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + default: + throw Synchronization_Exception(); + } + + return true; + + } + + /** + * Increment the active group count + * + * @pre at least 1 empty group exists + * @post at least 1 non-empty group exists + */ + std::pair increment() { + + Guard g(_lock); + + // At least one empty-group exists + assert(!_list.empty()); + + GroupList::iterator i = --_list.end(); + size_t n = i->id; + + if(i == _list.end()) { + + // A group should never have been removed until + // the final task in that group completed + assert(0); + + } + + i->count++; + + // When the active group is being incremented, insert a new active group + // to replace it if there were waiting threads + if(i == --_list.end() && !i->waiters.empty()) + _list.push_back(Group(_id++)); + + // At least 1 non-empty group exists + assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0); + + return std::make_pair(n, _generation); + + } + + + /** + * Decrease the count for the group with the given id. + * + * @param n group id + * + * @pre At least 1 non-empty group exists + * @post At least 1 empty group exists + */ + void decrement(size_t n) { + + Guard g1(_lock); + + // At least 1 non-empty group exists + assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0); + + // Find the requested group + GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n)); + if(i == _list.end()) { + + // A group should never have been removed until + // the final task in that group completed + assert(0); + + } + + // Decrease the count for tasks in this group, + if(--i->count == 0 && i == _list.begin()) { + + do { + + // When the first group completes, wake all waiters for every + // group, starting from the first until a group that is not + // complete is reached + + /* + // Don't remove the empty active group + if(i == --_list.end() && i->waiters.empty()) + break; + */ + + if( awaken(*i) ) { + + // If all waiters were awakened, remove the group + i = _list.erase(i); + + } else { + + { + + // Otherwise, unlock and yield allowing the waiter + // lists to be updated if other threads are busy + Guard g2(g1); + ThreadImpl::yield(); + + } + + i = _list.begin(); + + } + + } while(i != _list.end() && i->count == 0); + + // Ensure that an active group exists + if(_list.empty()) + _list.push_back( Group(++_id) ); + + } + + // At least one group exists + assert(!_list.empty()); + + } + + /** + */ + size_t generation(bool next = false) { + + Guard g(_lock); + return next ? _generation++ : _generation; + + } + + private: + + /** + * Awaken all the waiters remaining in the given group + * + * @return + * - true if all the waiting threads were successfully awakened. + * - false if there were one or more threads that could not be awakened. + */ + bool awaken(Group& grp) { + + // Go through the waiter list in the given group; + for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) { + + ThreadImpl* impl = *i; + Monitor& m = impl->getMonitor(); + + // Try the monitor lock, if it cant be locked skip to the next waiter + if(m.tryAcquire()) { + + // Notify the monitor & remove from the waiter list so time isn't + // wasted checking it again. + i = grp.waiters.erase(i); + + // Try to wake the waiter, it doesn't matter if this is successful + // or not (only fails when the monitor is already going to stop waiting). + m.notify(); + m.release(); + + } else ++i; + + } + + return grp.waiters.empty(); + + } + + }; + + /** + * @class GroupedRunnable + * + * Wrap a task with group and generation information. + * + * - 'group' allows tasks to be grouped together so that lists of waiting + * threads can be managed. + * + * - 'generation' allows tasks to be interrupted + */ + class GroupedRunnable : public Runnable { + + Task _task; + WaiterQueue& _queue; + + size_t _group; + size_t _generation; + + public: + + GroupedRunnable(const Task& task, WaiterQueue& queue) + : _task(task), _queue(queue) { + + std::pair pr( _queue.increment() ); + + _group = pr.first; + _generation = pr.second; + + } + + size_t group() const { + return _group; + } + + size_t generation() const { + return _generation; + } + + void run() { + + try { + + _task->run(); + + } catch(...) { + + } + + _queue.decrement( group() ); + + } + + }; + + typedef CountedPtr ExecutorTask; + + /** + * + */ + class ExecutorImpl { + + typedef MonitoredQueue TaskQueue; + typedef std::deque ThreadList; + + TaskQueue _taskQueue; + WaiterQueue _waitingQueue; + + ThreadList _threads; + volatile size_t _size; + + + public: + + ExecutorImpl() : _size(0) {} + + + void registerThread() { + + Guard g(_taskQueue); + + ThreadImpl* impl = ThreadImpl::current(); + _threads.push_back(impl); + + // current cancel if too many threads are being created + if(_threads.size() > _size) + impl->cancel(); + + } + + void unregisterThread() { + + Guard g(_taskQueue); + std::remove(_threads.begin(), _threads.end(), ThreadImpl::current()); + + } + + void execute(const Task& task) { + + // Wrap the task with a grouped task + GroupedRunnable* runnable = new GroupedRunnable(task, _waitingQueue); + + try { + + _taskQueue.add( ExecutorTask(runnable) ); + + } catch(...) { + + // Incase the queue is canceled between the time the WaiterQueue is + // updated and the task is added to the TaskQueue + _waitingQueue.decrement( runnable->group() ); + throw; + + } + + } + + void interrupt() { + + // Bump the generation number + _waitingQueue.generation(true); + + Guard g(_taskQueue); + + // Interrupt all threads currently running, thier tasks would be + // from an older generation + for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i) + (*i)->interrupt(); + + } + + //! Adjust the number of desired workers and return the number of Threads needed + size_t workers(size_t n) { + + Guard g(_taskQueue); + + size_t m = (_size < n) ? (n - _size) : 0; + _size = n; + + return m; + + } + + size_t workers() { + + Guard g(_taskQueue); + return _size; + + } + + ExecutorTask next() { + + ExecutorTask task; + + // Draw the task from the queue + for(;;) { + + try { + + task = _taskQueue.next(); + break; + + } catch(Interrupted_Exception&) { + + // Ignore interruption here, it can only come from + // another thread interrupt()ing the executor. The + // thread was interrupted in the hopes it was busy + // with a task + + } + + } + + // Interrupt the thread running the tasks when the generation + // does not match the current generation + if( task->generation() != _waitingQueue.generation() ) + ThreadImpl::current()->interrupt(); + + // Otherwise, clear the interrupted status for the thread and + // give it a clean slate to start with + else + ThreadImpl::current()->isInterrupted(); + + return task; + + } + + bool isCanceled() { + return _taskQueue.isCanceled(); + } + + void cancel() { + _taskQueue.cancel(); + } + + bool wait(unsigned long timeout) { + return _waitingQueue.wait(timeout); + } + + }; + + //! Executor job + class Worker : public Runnable { + + CountedPtr< ExecutorImpl > _impl; + + public: + + //! Create a Worker that draws upon the given Queue + Worker(const CountedPtr< ExecutorImpl >& impl) + : _impl(impl) { } + + //! Run until Thread or Queue are canceled + void run() { + + _impl->registerThread(); + + // Run until the Queue is canceled + while(!Thread::canceled()) { + + // Draw tasks from the queue + ExecutorTask task( _impl->next() ); + task->run(); + + } + + _impl->unregisterThread(); + + } + + }; /* Worker */ + + + //! Helper + class Shutdown : public Runnable { + + CountedPtr< ExecutorImpl > _impl; + + public: + + Shutdown(const CountedPtr< ExecutorImpl >& impl) + : _impl(impl) { } + + void run() { + _impl->cancel(); + } + + }; /* Shutdown */ + + } + + PoolExecutor::PoolExecutor(size_t n) + : _impl( new ExecutorImpl() ), _shutdown( new Shutdown(_impl) ) { + + size(n); + + // Request cancelation when main() exits + ThreadQueue::instance()->insertShutdownTask(_shutdown); + + } + + PoolExecutor::~PoolExecutor() { + + try { + + /** + * If the shutdown task for this executor has not already been + * selected to run, then run it locally + */ + if(ThreadQueue::instance()->removeShutdownTask(_shutdown)) + _shutdown->run(); + + } catch(...) { } + + } + + void PoolExecutor::interrupt() { + _impl->interrupt(); + } + + void PoolExecutor::size(size_t n) { + + if(n < 1) + throw InvalidOp_Exception(); + + for(size_t m = _impl->workers(n); m > 0; --m) + Thread t(new Worker(_impl)); + + } + + size_t PoolExecutor::size() { + return _impl->workers(); + } + + + void PoolExecutor::execute(const Task& task) { + + // Enqueue the task, the Queue will reject it with a + // Cancelation_Exception if the Executor has been canceled + _impl->execute(task); + + } + + void PoolExecutor::cancel() { + _impl->cancel(); + } + + bool PoolExecutor::isCanceled() { + return _impl->isCanceled(); + } + + void PoolExecutor::wait() { + _impl->wait(0); + } + + bool PoolExecutor::wait(unsigned long timeout) { + return _impl->wait(timeout == 0 ? 1 : timeout); + } + +} diff --git a/src/dep/src/zthread/PriorityCondition.cxx b/src/dep/src/zthread/PriorityCondition.cxx new file mode 100644 index 0000000..c43953f --- /dev/null +++ b/src/dep/src/zthread/PriorityCondition.cxx @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/PriorityCondition.h" +#include "ConditionImpl.h" + +namespace ZThread { + + class PriorityConditionImpl : public ConditionImpl { + public: + PriorityConditionImpl(Lockable& l) : ConditionImpl(l) {} + + }; + + PriorityCondition::PriorityCondition(Lockable& lock) { + + _impl = new PriorityConditionImpl(lock); + + } + + + PriorityCondition::~PriorityCondition() { + + if(_impl != 0) + delete _impl; + + } + + + + void PriorityCondition::wait() { + + _impl->wait(); + + } + + + + bool PriorityCondition::wait(unsigned long ms) { + + return _impl->wait(ms); + + } + + + + void PriorityCondition::signal() { + + _impl->signal(); + + } + + + void PriorityCondition::broadcast() { + + _impl->broadcast(); + + } + +} // namespace ZThread + diff --git a/src/dep/src/zthread/PriorityInheritanceMutex.cxx b/src/dep/src/zthread/PriorityInheritanceMutex.cxx new file mode 100644 index 0000000..108e4a7 --- /dev/null +++ b/src/dep/src/zthread/PriorityInheritanceMutex.cxx @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/PriorityInheritanceMutex.h" +#include "MutexImpl.h" +#include "ThreadOps.h" + + +namespace ZThread { + + class InheritPriorityBehavior : public NullBehavior { + + ThreadImpl* owner; + Priority p; + + protected: + + // Temporarily raise the effective priority of the owner + inline void waiterArrived(ThreadImpl* impl) { + + Priority q = impl->getPriority(); + if((int)q > (int)p) { + + ThreadOps::setPriority(impl, p); + p = q; + + } + + } + + + // Note the owners priority + inline void ownerAcquired(ThreadImpl* impl) { + + p = impl->getPriority(); + owner = impl; + + } + + // Restore its original priority + inline void ownerReleased(ThreadImpl* impl) { + + if(p > owner->getPriority()) + ThreadOps::setPriority(impl, impl->getPriority()); + + } + + }; + + class PriorityInheritanceMutexImpl : + public MutexImpl { }; + + PriorityInheritanceMutex::PriorityInheritanceMutex() { + + _impl = new PriorityInheritanceMutexImpl(); + + } + + PriorityInheritanceMutex::~PriorityInheritanceMutex() { + + if(_impl != 0) + delete _impl; + + } + + // P + void PriorityInheritanceMutex::acquire() { + + _impl->acquire(); + + } + + + // P + bool PriorityInheritanceMutex::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + // V + void PriorityInheritanceMutex::release() { + + _impl->release(); + + } + + +} // namespace ZThread + diff --git a/src/dep/src/zthread/PriorityMutex.cxx b/src/dep/src/zthread/PriorityMutex.cxx new file mode 100644 index 0000000..c25eaeb --- /dev/null +++ b/src/dep/src/zthread/PriorityMutex.cxx @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/PriorityMutex.h" +#include "MutexImpl.h" +#include "ThreadOps.h" + + +namespace ZThread { + + class PriorityMutexImpl : public MutexImpl { }; + + PriorityMutex::PriorityMutex() { + + _impl = new PriorityMutexImpl(); + + } + + PriorityMutex::~PriorityMutex() { + + if(_impl != 0) + delete _impl; + + } + + // P + void PriorityMutex::acquire() { + + _impl->acquire(); + + } + + + // P + bool PriorityMutex::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + // V + void PriorityMutex::release() { + + _impl->release(); + + } + + +} // namespace ZThread + diff --git a/src/dep/src/zthread/PrioritySemaphore.cxx b/src/dep/src/zthread/PrioritySemaphore.cxx new file mode 100644 index 0000000..15138b5 --- /dev/null +++ b/src/dep/src/zthread/PrioritySemaphore.cxx @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Debug.h" +#include "zthread/PrioritySemaphore.h" +#include "SemaphoreImpl.h" + +namespace ZThread { + + class PrioritySemaphoreImpl : public SemaphoreImpl { + public: + + PrioritySemaphoreImpl(int count, unsigned int maxCount) + : SemaphoreImpl(count, maxCount, true) { } + + }; + + /** + * Create a new semaphore of a given size with a given count + * + * @param initialCount initial count to assign this semaphore + * @param maxCount maximum size of the semaphore count + */ + PrioritySemaphore::PrioritySemaphore(int count, unsigned int maxCount) { + + _impl = new PrioritySemaphoreImpl(count, maxCount); + + } + + PrioritySemaphore::~PrioritySemaphore() { + + if(_impl != 0) + delete _impl; + + } + + void PrioritySemaphore::wait() { + + _impl->acquire(); + + } + + + bool PrioritySemaphore::tryWait(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + void PrioritySemaphore::post() { + + _impl->release(); + + } + + int PrioritySemaphore::count() { + + return _impl->count(); + + } + + /////////////////////////////////////////////////////////////////////////////// + // Locakable compatibility + // + + void PrioritySemaphore::acquire() { + + _impl->acquire(); + + } + + bool PrioritySemaphore::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + + } + + void PrioritySemaphore::release() { + + _impl->release(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/RecursiveMutex.cxx b/src/dep/src/zthread/RecursiveMutex.cxx new file mode 100644 index 0000000..57994f5 --- /dev/null +++ b/src/dep/src/zthread/RecursiveMutex.cxx @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/RecursiveMutex.h" +#include "RecursiveMutexImpl.h" + +namespace ZThread { + + RecursiveMutex::RecursiveMutex() { + + _impl = new RecursiveMutexImpl(); + + } + + RecursiveMutex::~RecursiveMutex() { + + if(_impl != (RecursiveMutexImpl*)0 ) + delete _impl; + + } + + + void RecursiveMutex::acquire() { + + _impl->acquire(); + + } + + + bool RecursiveMutex::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + void RecursiveMutex::release() { + + _impl->release(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/RecursiveMutexImpl.cxx b/src/dep/src/zthread/RecursiveMutexImpl.cxx new file mode 100644 index 0000000..896d6f5 --- /dev/null +++ b/src/dep/src/zthread/RecursiveMutexImpl.cxx @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Debug.h" + +#include "RecursiveMutexImpl.h" +#include "ThreadImpl.h" + +#include "zthread/Guard.h" + +#include +#include +#include + +namespace ZThread { + + /** + * Create a new RecursiveMutexImpl + * + * @exception Initialization_Exception thrown if resources could not be + * properly allocated + */ + RecursiveMutexImpl::RecursiveMutexImpl() + : _owner(0), _count(0) { + + } + + /** + * Destroy this RecursiveMutexImpl and release its resources + */ + RecursiveMutexImpl::~RecursiveMutexImpl() { + +#ifndef NDEBUG + + // It is an error to destroy a mutex that has not been released + if(_owner != 0) { + + ZTDEBUG("** You are destroying a mutex which was never released. **\n"); + assert(0); // Destroyed mutex while in use + + } + + if(_waiters.size() > 0) { + + ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size()); + assert(0); // Destroyed mutex while in use + + } + +#endif + + } + + + void RecursiveMutexImpl::acquire() { + + // Get the monitor for the current thread + Monitor& m = ThreadImpl::current()->getMonitor(); + Monitor::STATE state; + + Guard g1(_lock); + + // If there is an entry count and the current thread is + // the owner, increment the count and continue. + if(_owner == &m) + _count++; + + else { + + // Acquire the lock if it is free and there are no waiting threads + if(_owner == 0 && _waiters.empty()) { + + assert(_count == 0); + + _owner = &m; + _count++; + + } else { // Otherwise, wait() + + _waiters.push_back(&m); + + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(); + + } + + m.release(); + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m); + if(i != _waiters.end()) + _waiters.erase(i); + + // If awoke due to a notify(), take ownership. + switch(state) { + case Monitor::SIGNALED: + + assert(_owner == 0); + assert(_count == 0); + + _owner = &m; + _count++; + + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + throw Synchronization_Exception(); + } + + } + + } + + } + + bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) { + + // Get the monitor for the current thread + Monitor& m = ThreadImpl::current()->getMonitor(); + + Guard g1(_lock); + + // If there is an entry count and the current thread is + // the owner, increment the count and continue. + if(_owner == &m) + _count++; + + else { + + // Acquire the lock if it is free and there are no waiting threads + if(_owner == 0 && _waiters.empty()) { + + assert(_count == 0); + + _owner = &m; + _count++; + + } else { // Otherwise, wait() + + _waiters.push_back(&m); + + Monitor::STATE state = Monitor::TIMEDOUT; + + // Don't bother waiting if the timeout is 0 + if(timeout) { + + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(timeout); + + } + + m.release(); + + } + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m); + if(i != _waiters.end()) + _waiters.erase(i); + + // If awoke due to a notify(), take ownership. + switch(state) { + case Monitor::SIGNALED: + + assert(_count == 0); + assert(_owner == 0); + + _owner = &m; + _count++; + + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + case Monitor::TIMEDOUT: + return false; + + default: + throw Synchronization_Exception(); + } + + } + + } + + return true; + + } + + void RecursiveMutexImpl::release() { + + // Get the monitor for the current thread + Monitor& m = ThreadImpl::current()->getMonitor(); + + Guard g1(_lock); + + // Make sure the operation is valid + if(!(_owner == &m)) + throw InvalidOp_Exception(); + + // Update the count, if it has reached 0, wake another waiter. + if(--_count == 0) { + + _owner = 0; + + // Try to find a waiter with a backoff & retry scheme + for(;;) { + + // Go through the list, attempt to notify() a waiter. + for(List::iterator i = _waiters.begin(); i != _waiters.end();) { + + // Try the monitor lock, if it cant be locked skip to the next waiter + Monitor* n = *i; + if(n->tryAcquire()) { + + // If notify() is not sucessful, it is because the wait() has already + // been ended (killed/interrupted/notify'd) + bool woke = n->notify(); + n->release(); + + // Once notify() succeeds, return + if(woke) + return; + + } else ++i; + + } + + if(_waiters.empty()) + return; + + { // Backoff and try again + + Guard g2(g1); + ThreadImpl::yield(); + + } + + } + + } + + } + +} // namespace ZThread + + + + diff --git a/src/dep/src/zthread/RecursiveMutexImpl.h b/src/dep/src/zthread/RecursiveMutexImpl.h new file mode 100644 index 0000000..9e1ae05 --- /dev/null +++ b/src/dep/src/zthread/RecursiveMutexImpl.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTRECURSIVEMUTEXIMPL_H__ +#define __ZTRECURSIVEMUTEXIMPL_H__ + +#include "zthread/Exceptions.h" + +#include "FastLock.h" + +#include + +namespace ZThread { + + class Monitor; + + /** + * @class RecursiveMutexImpl + * @author Eric Crahen + * @date <2003-07-16T19:58:26-0400> + * @version 2.1.6 + * + * This synchronization object provides serialized access + * through an acquire/release protocol. + */ + class ZTHREAD_API RecursiveMutexImpl { + + typedef std::vector List; + + //! List of Events that are waiting for notification + List _waiters; + + //! Serialize access to this Mutex + FastLock _lock; + + //! Current owning Event object + Monitor* _owner; + + //! Entry count + size_t _count; + + public: + + RecursiveMutexImpl(); + + virtual ~RecursiveMutexImpl(); + + void acquire(); + + bool tryAcquire(unsigned long); + + void release(); + + }; /* RecursiveMutexImpl */ + + +}; + +#endif diff --git a/src/dep/src/zthread/Scheduling.h b/src/dep/src/zthread/Scheduling.h new file mode 100644 index 0000000..b12f7ff --- /dev/null +++ b/src/dep/src/zthread/Scheduling.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSCHEDULING_H__ +#define __ZTSCHEDULING_H__ + +#include "ThreadImpl.h" + +#include +#include +#include +#include + +namespace ZThread { + + /** + * @author Eric Crahen + * @date <2003-07-16T20:01:18-0400> + * @version 2.2.0 + * @class fifo_list + */ + class fifo_list : public std::deque { + public: + + void insert(const value_type& val) { push_back(val); } + + }; + + /** + * @author Eric Crahen + * @date <2003-07-16T20:01:18-0400> + * @version 2.2.0 + * @struct priority_order + */ + struct priority_order : public std::binary_function { + + std::less id; + + bool operator()(const ThreadImpl* t0, const ThreadImpl* t1) const { + + if(t0->getPriority() > t1->getPriority()) + return true; + + else if (t0->getPriority() < t1->getPriority()) + return false; + + return id(t0, t1); + + } + + }; + + + /** + * @author Eric Crahen + * @date <2003-07-16T20:01:18-0400> + * @version 2.2.0 + * @class priority_list + */ + class priority_list : public std::deque { + + priority_order comp; + + public: + + void insert(const value_type& val) { + + push_back(val); + std::sort(begin(), end(), comp); + + } + + }; + +} // namespace ZThread + +#endif // __ZTSCHEDULING_H__ diff --git a/src/dep/src/zthread/Semaphore.cxx b/src/dep/src/zthread/Semaphore.cxx new file mode 100644 index 0000000..b9fb8d0 --- /dev/null +++ b/src/dep/src/zthread/Semaphore.cxx @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Semaphore.h" +#include "SemaphoreImpl.h" + +namespace ZThread { + + /** + * Create a new semaphore of a given size with a given count + * + * @param initialCount initial count to assign this semaphore + * @param maxCount maximum size of the semaphore count + */ + Semaphore::Semaphore(int count, unsigned int maxCount) { + + _impl = new FifoSemaphoreImpl(count, maxCount, true); + + } + + Semaphore::~Semaphore() { + + if(_impl != 0) + delete _impl; + + } + + void Semaphore::wait() { + + _impl->acquire(); + + } + + + bool Semaphore::tryWait(unsigned long ms) { + + return _impl->tryAcquire(ms); + + } + + void Semaphore::post() { + + _impl->release(); + + } + + int Semaphore::count() { + + return _impl->count(); + + } + + /////////////////////////////////////////////////////////////////////////////// + // Locakable compatibility + // + + void Semaphore::acquire() { + + _impl->acquire(); + + } + + bool Semaphore::tryAcquire(unsigned long ms) { + + return _impl->tryAcquire(ms); + + + } + + void Semaphore::release() { + + _impl->release(); + + } + +} // namespace ZThread + + + + + + diff --git a/src/dep/src/zthread/SemaphoreImpl.h b/src/dep/src/zthread/SemaphoreImpl.h new file mode 100644 index 0000000..1f19128 --- /dev/null +++ b/src/dep/src/zthread/SemaphoreImpl.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSEMAPHOREIMPL_H__ +#define __ZTSEMAPHOREIMPL_H__ + +#include "zthread/Guard.h" + +#include "Debug.h" +#include "FastLock.h" +#include "Scheduling.h" + +#include + +namespace ZThread { + + class Monitor; + + /** + * @class SemaphoreImpl + * @author Eric Crahen + * @date <2003-07-16T20:03:20-0400> + * @version 2.2.11 + * + * The SemaphoreImpl template allows how waiter lists are sorted + * to be parameteized + */ + template + class SemaphoreImpl { + + //! List of waiting events + List _waiters; + + //! Serialize access to this object + FastLock _lock; + + //! Current count + volatile int _count; + + //! Maximum count if any + volatile int _maxCount; + + //! Flag for bounded or unbounded count + volatile bool _checked; + + //! Entry count + volatile int _entryCount; + + public: + + + /** + * Create a new SemaphoreImpl. Initialzes one pthreads mutex for + * internal use. + * + * @exception Initialization_Exception thrown if resources could not be + * properly allocated + */ + SemaphoreImpl(int count, unsigned int maxCount, bool checked) + : _count(count), _maxCount(maxCount), _checked(checked), _entryCount(0) { } + + + ~SemaphoreImpl(); + + void acquire(); + + void release(); + + bool tryAcquire(unsigned long timeout); + + int count(); + + }; + + + /** + * Destroy this SemaphoreImpl and release its resources. + */ + template + SemaphoreImpl::~SemaphoreImpl() { + +#ifndef NDEBUG + + if(_waiters.size() > 0) { + + ZTDEBUG("** You are destroying a semaphore which is blocking %d threads. **\n", _waiters.size()); + assert(0); // Destroyed semaphore while in use + + } + +#endif + + } + + + /** + * Get the count for the Semaphore + * + * @return int + */ + template + int SemaphoreImpl::count() { + + Guard g(_lock); + return _count; + + } + + /** + * Decrement the count, blocking when that count becomes 0 or less. + * + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ + template + void SemaphoreImpl::acquire() { + + // Get the monitor for the current thread + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Monitor::STATE state; + + Guard g1(_lock); + + // Update the count without waiting if possible. + if(_count > 0 && _entryCount == 0) + _count--; + + // Otherwise, wait() for the lock by placing the waiter in the list + else { + + ++_entryCount; + _waiters.insert(self); + + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(); + + } + + m.release(); + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + --_entryCount; + + switch(state) { + // If awoke due to a notify(), update the count + case Monitor::SIGNALED: + + _count--; + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + throw Synchronization_Exception(); + } + + } + + } + + /** + * Decrement the count, blocking when it that count is 0 or less. If the timeout + * expires before the count is raise above 0, the thread will stop blocking + * and return. + * + * @exception Interrupted_Exception thrown when the caller status is interrupted + * @exception Synchronization_Exception thrown if there is some other error. + */ + template + bool SemaphoreImpl::tryAcquire(unsigned long timeout) { + + // Get the monitor for the current thread + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Guard g1(_lock); + + // Update the count without waiting if possible. + if(_count > 0 && _entryCount == 0) + _count--; + + // Otherwise, wait() for the lock by placing the waiter in the list + else { + + ++_entryCount; + _waiters.push_back(self); + + Monitor::STATE state = Monitor::TIMEDOUT; + + // Don't bother waiting if the timeout is 0 + if(timeout) { + + m.acquire(); + + { + + Guard g2(g1); + state = m.wait(timeout); + + } + + m.release(); + + } + + // Remove from waiter list, regarless of weather release() is called or + // not. The monitor is sticky, so its possible a state 'stuck' from a + // previous operation and will leave the wait() w/o release() having + // been called. + typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self); + if(i != _waiters.end()) + _waiters.erase(i); + + --_entryCount; + + switch(state) { + // If awoke due to a notify(), update the count + case Monitor::SIGNALED: + + _count--; + break; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + case Monitor::TIMEDOUT: + return false; + + default: + throw Synchronization_Exception(); + } + + } + + return true; + + } + + /** + * Increment the count and release a waiter if there are any. If the semaphore + * is checked, then an exception will be raised if the maximum count is about to + * be exceeded. + * + * @exception InvalidOp_Exception thrown if the maximum count is exceeded while + * the checked flag is set. + */ + template + void SemaphoreImpl::release() { + + Guard g1(_lock); + + // Make sure the operation is valid + if(_checked && _count == _maxCount) + throw InvalidOp_Exception(); + + // Increment the count + _count++; + + // Try to find a waiter with a backoff & retry scheme + for(;;) { + + // Go through the list, attempt to notify() a waiter. + for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) { + + // Try the monitor lock, if it cant be locked skip to the next waiter + ThreadImpl* impl = *i; + Monitor& m = impl->getMonitor(); + + if(m.tryAcquire()) { + + // Notify the monitor & remove from the waiter list so time isn't + // wasted checking it again. + i = _waiters.erase(i); + + // If notify() is not sucessful, it is because the wait() has already + // been ended (killed/interrupted/notify'd) + bool woke = m.notify(); + + m.release(); + + // Once notify() succeeds, return + if(woke) + return; + + } else ++i; + + } + + if(_waiters.empty()) + return; + + { // Backoff and try again + + Guard g2(g1); + ThreadImpl::yield(); + + } + + } + + } + + class FifoSemaphoreImpl : public SemaphoreImpl { + public: + + FifoSemaphoreImpl(int count, unsigned int maxCount, bool checked) + /* throw(Synchronization_Exception) */ + : SemaphoreImpl(count, maxCount, checked) { } + + }; + + +} // namespace ZThread + +#endif // __ZTSEMAPHOREIMPL_H__ diff --git a/src/dep/src/zthread/State.h b/src/dep/src/zthread/State.h new file mode 100644 index 0000000..85279f4 --- /dev/null +++ b/src/dep/src/zthread/State.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTSTATE_H__ +#define __ZTSTATE_H__ + +namespace ZThread { + +/** + * @class State + * @author Eric Crahen + * @date <2003-07-16T20:04:01-0400> + * @version 2.2.1 + * + * Class to encapsulate the current state of the threads life-cycle. + */ +class State { + public: + + //! Various states + typedef enum { REFERENCE, IDLE, RUNNING, JOINED } STATE; + + /** + * Create State with the given flag set. + */ + State(STATE initialState) : _state(initialState) {} + + /** + * Test for the IDLE state. No task has yet run. + */ + bool isIdle() const { + return _state == IDLE; + } + + /** + * Test for the JOINED state. A task has completed and + * the thread is join()ed. + * + * @return bool + */ + bool isJoined() const { + return _state == JOINED; + } + + /** + * Test for the RUNNING state. A task is in progress. + * + * @return bool + */ + bool isRunning() const { + return _state == RUNNING; + } + + /** + * Test for the REFERENCE state. A task is in progress but not + * under control of this library. + * + * @return bool + */ + bool isReference() const { + return _state == REFERENCE; + } + + /** + * Transition to the IDLE state. + * + * @return bool true if successful + */ + bool setIdle() { + + if(_state != RUNNING) + return false; + + _state = IDLE; + return true; + + } + + /** + * Transition to the RUNNING state. + * + * @return bool true if successful + */ + bool setRunning() { + + if(_state != IDLE) + return false; + + _state = RUNNING; + return true; + + } + + /** + * Transition to the REFERENCE state. + * + * @return bool true if successful + */ + bool setReference() { + + if(_state != IDLE) + return false; + + _state = REFERENCE; + return true; + + } + + + /** + * Transition to the JOINED state. + * + * @return bool true if successful + */ + bool setJoined() { + + _state = JOINED; + return true; + + } + + private: + + //! Current state + STATE _state; + +}; + + +}; + +#endif diff --git a/src/dep/src/zthread/Status.h b/src/dep/src/zthread/Status.h new file mode 100644 index 0000000..bc1db99 --- /dev/null +++ b/src/dep/src/zthread/Status.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTBLOCKINGSTATE_H__ +#define __ZTBLOCKINGSTATE_H__ + +#include + +namespace ZThread { + + /** + * @class Status + * @version 2.3.0 + * + * A Status is associated with each Thread's Monitor. Monitors rely on a + * Status object for providing information that will affect a blocking operations. + */ + class Status { + public: + //! Aggregate of pending status changes + volatile unsigned short _pending; + + //! Interest mask + volatile unsigned short _mask; + + public: + + //! State for the monitor + typedef enum { + + // Default + INVALID = 0x00, + + // Valid states + SIGNALED = 0x01, + INTERRUPTED = 0x02, + TIMEDOUT = 0x04, + CANCELED = 0x08, + + // Mask + ANYTHING = (~INVALID & ~CANCELED) + + } STATE; + + Status() : _pending(INVALID), _mask(ANYTHING) { } + + /** + * Set the mask for the STATE's that next() will report. + * STATE's not covered by the interest mask can still be + * set, they just aren't reported until the mask is changed + * to cover that STATE. + * + * @param STATE + * @pre accessed ONLY by the owning thread. + */ + void interest(STATE mask) { + _mask = static_cast(mask); + } + + bool masked(STATE mask) { + return (_mask & static_cast(mask)) == 0; + } + + /** + * Return true if next() will return a STATE covered + * by the current interest mask and by the mask given + * to this function. + * + * @param unsigned short + * @pre accessed ONLY by the owning thread. + */ + bool pending(unsigned short mask) { + + assert(mask != INVALID); + return ((_pending & _mask) & mask) != INVALID; + + } + + /** + * Check the state without the interest mask. + * + * @param state + * @return true if the flag is set + * @pre access must be serial + */ + bool examine(STATE state) { + return (_pending & static_cast(state)) != INVALID; + } + + /** + * Add the flags to the current state. + * + * @param interest - the flags to add to the current state. + * @pre access must be serial + */ + void push(STATE interest) { + _pending |= interest; + } + + /** + * Clear the flags from the current state + * + * @param interest - the flags to clear from the current state. + * @pre access must be serial + */ + void clear(STATE interest) { + + assert(interest != INVALID); + assert(interest != ANYTHING); + assert(interest != CANCELED); + + _pending &= ~interest; + + } + + /** + * Get the next state from set that has accumulated. The order STATES are + * reported in is SIGNALED, TIMEOUT, or INTERRUPTED. Setting the + * intrest mask allows certain state to be selectively ignored for + * a time - but not lost. The states will become visible again as soon + * as the interest mask is changed appropriately. The interest mask is + * generally used to create uninterruptable waits (waiting for threads + * to start, reacquiring a conditions predicate lock, etc) + * + * @return STATE + * @pre access must be serial + */ + STATE next() { + + STATE state = INVALID; + + if(((_pending & _mask) & SIGNALED) != 0) { + + // Absorb the timeout if it happens when a signal + // is available at the same time + _pending &= ~(SIGNALED|TIMEDOUT); + state = SIGNALED; + + } else if(((_pending & _mask) & TIMEDOUT) != 0) { + + _pending &= ~TIMEDOUT; + state = TIMEDOUT; + + } else if(((_pending & _mask) & INTERRUPTED) != 0) { + + _pending &= ~INTERRUPTED; + state = INTERRUPTED; + + } + + assert(state != INVALID); + return state; + + } + + }; + +}; // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/SynchronousExecutor.cxx b/src/dep/src/zthread/SynchronousExecutor.cxx new file mode 100644 index 0000000..0dc75b5 --- /dev/null +++ b/src/dep/src/zthread/SynchronousExecutor.cxx @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/SynchronousExecutor.h" + +namespace ZThread { + + SynchronousExecutor::SynchronousExecutor() + : _canceled(false) {} + + SynchronousExecutor::~SynchronousExecutor() { + } + + void SynchronousExecutor::cancel() { + + Guard g(_lock); + _canceled = true; + + } + + bool SynchronousExecutor::isCanceled() { + + Guard g(_lock); + return _canceled; + + } + + void SynchronousExecutor::interrupt() { + } + + void SynchronousExecutor::execute(const Task& task) { + + // Canceled Executors will not accept new tasks, quick + // check to avoid excessive locking in the canceled state + if(_canceled) + throw Cancellation_Exception(); + + Guard g(_lock); + + if(_canceled) // Double check + throw Cancellation_Exception(); + + // Run the task. + Task(task)->run(); + + } + + void SynchronousExecutor::wait() { + + if(Thread::interrupted()) + throw Interrupted_Exception(); + + Guard g(_lock); + + } + + /** + * @see Executor::wait(unsigned long) + */ + bool SynchronousExecutor::wait(unsigned long) { + + if(Thread::interrupted()) + throw Interrupted_Exception(); + + Guard g(_lock); + return true; + + } + + +} diff --git a/src/dep/src/zthread/TSS.h b/src/dep/src/zthread/TSS.h new file mode 100644 index 0000000..ed29230 --- /dev/null +++ b/src/dep/src/zthread/TSS.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTSSSELECT_H__ +#define __ZTTSSSELECT_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// Select the correct TSS implementation based on +// what the compilation environment has defined + +#if defined(ZT_POSIX) + +#include "posix/TSS.h" + +#elif defined(ZT_WIN32) || defined(ZT_WIN9X) + +#include "win32/TSS.h" + +#elif defined(ZT_MACOS) + +#include "macos/TSS.h" + +#endif + + +#ifndef __ZTTSS_H__ +#error "No TSS implementation could be selected" +#endif + +#endif // __ZTTSSSELECT_H__ diff --git a/src/dep/src/zthread/Thread.cxx b/src/dep/src/zthread/Thread.cxx new file mode 100644 index 0000000..25cde79 --- /dev/null +++ b/src/dep/src/zthread/Thread.cxx @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Runnable.h" +#include "zthread/Thread.h" +#include "ThreadImpl.h" + +namespace ZThread { + + + Thread::Thread() + : _impl( ThreadImpl::current() ) { + + // ThreadImpl's start out life with a reference count + // of one, and the they are added to the ThreadQueue. + _impl->addReference(); + + } + + Thread::Thread(const Task& task, bool autoCancel) + : _impl( new ThreadImpl(task, autoCancel) ) { + + _impl->addReference(); + + } + + bool Thread::operator==(const Thread& t) const { + return (t._impl == _impl); + } + + Thread::~Thread() { + + _impl->delReference(); + + } + + void Thread::wait() { + _impl->join(0); + } + + bool Thread::wait(unsigned long timeout) { + + return _impl->join(timeout == 0 ? 1 : timeout); + + } + + bool Thread::interrupted() { + + return ThreadImpl::current()->isInterrupted(); + + } + + + bool Thread::canceled() { + + return ThreadImpl::current()->isCanceled(); + + } + + void Thread::setPriority(Priority n) { + + _impl->setPriority(n); + + } + + + Priority Thread::getPriority() { + + return _impl->getPriority(); + + } + + bool Thread::interrupt() { + + return _impl->interrupt(); + + } + + void Thread::cancel() { + + if(ThreadImpl::current() == _impl) + throw InvalidOp_Exception(); + + _impl->cancel(); + + } + + bool Thread::isCanceled() { + + return _impl->isCanceled(); + + } + + + void Thread::sleep(unsigned long ms) { + + ThreadImpl::sleep(ms); + + } + + + void Thread::yield() { + + ThreadImpl::yield(); + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/ThreadImpl.cxx b/src/dep/src/zthread/ThreadImpl.cxx new file mode 100644 index 0000000..c7c2288 --- /dev/null +++ b/src/dep/src/zthread/ThreadImpl.cxx @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Debug.h" + +#include "zthread/Runnable.h" +#include "ThreadImpl.h" +#include "ThreadQueue.h" +#include "DeferredInterruptionScope.h" + +#include + +namespace ZThread { + + TSS ThreadImpl::_threadMap; + + namespace { + + class Launcher : public Runnable { + + ThreadImpl* x; + ThreadImpl* y; + Task z; + + public: + + Launcher(ThreadImpl* a, ThreadImpl* b, const Task& c) : x(a), y(b), z(c) {} + + void run() { + y->dispatch(x,y,z); + } + + }; + + } + + ThreadImpl::ThreadImpl() + : _state(State::REFERENCE), _priority(Medium), _autoCancel(false) { + + ZTDEBUG("Reference thread created.\n"); + + } + + ThreadImpl::ThreadImpl(const Task& task, bool autoCancel) + : _state(State::IDLE), _priority(Medium), _autoCancel(autoCancel) { + + ZTDEBUG("User thread created.\n"); + + start(task); + + } + + + ThreadImpl::~ThreadImpl() { + + _tls.clear(); + + if(isActive()) { + + ZTDEBUG("You are destroying an executing thread!\n"); + abort(); + + } + + ZTDEBUG("Thread destroyed.\n"); + + } + + Monitor& ThreadImpl::getMonitor() { + return _monitor; + } + + void ThreadImpl::cancel(bool autoCancel) { + if(!autoCancel || _autoCancel) + _monitor.cancel(); + } + + bool ThreadImpl::interrupt() { + return _monitor.interrupt(); + } + + bool ThreadImpl::isInterrupted() { + return _monitor.isInterrupted(); + } + + bool ThreadImpl::isCanceled() { + return _monitor.isCanceled(); + } + + Priority ThreadImpl::getPriority() const { + return _priority; + } + + + + bool ThreadImpl::isReference() { + return _state.isReference(); + } + + /** + * Join the thread, blocking the caller until it is interrupted or until + * the thread represented by this object exits. + * + * Reference threads are not under the control of ZThreads and cannot be + * joined. + */ + bool ThreadImpl::join(unsigned long timeout) { + + // Serial access to this ThreadImpl's state + Guard g1(_monitor); + + // Make sure a thread is not trying to join() itself. + if(ThreadOps::isCurrent(this)) + throw Deadlock_Exception("Cannot join self."); + + // Reference threads can't be joined. + if(_state.isReference()) + throw InvalidOp_Exception("Can not join this thread."); + + /* + + TODO: Insert cyclic join check. + + */ + + // If the task has not completed yet, wait for completion + if(!_state.isJoined()) { + + // Add the current thread to the joiner list + ThreadImpl* impl = current(); + _joiners.push_back(impl); + + Monitor::STATE result; + + { // Release this ThreadImpl's lock while the joiner sleeps + + _monitor.release(); + Guard g3(impl->getMonitor()); + + result = impl->_monitor.wait(timeout); + + _monitor.acquire(); + + } + + // Update the joiner list + List::iterator i = std::find(_joiners.begin(), _joiners.end(), impl); + if(i != _joiners.end()) + _joiners.erase(i); + + + switch(result) { + + case Monitor::TIMEDOUT: + return false; + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + break; + + } + + } + + return true; + + } + + + /** + * Translate the priority into a pthread value, and update the thread priority. + * + * This is not available on all platforms, and probably works differently + * the platforms that do support it. Pthreads does not have very portable + * priority support as far I am aware. + * + * If SCHED_OTHER is not supported priority values are still set but + * dont not actually in affect anything. + * + * @param prio PRIORITY value + * + * @exception Killed_Exception thrown by KILLED threads. + * @exception InvalidOp_Exception thrown by IDLE, JOINING or JOINED threads. + */ + void ThreadImpl::setPriority(Priority p) { + + Guard g(_monitor); + + // Only set the native priority when the thread is running + if(_state.isRunning()) + ThreadOps::setPriority(this, p); + + _priority = p; + + } + + + /** + * Test the state Monitor of this thread to determine if the thread + * is an active thread created by zthreads. + * + * @return bool indicating the activity of the thread. + */ + bool ThreadImpl::isActive() { + + Guard g(_monitor); + return _state.isRunning(); + + } + + + /** + * Get a reference to an implmenetation that maps to the current thread. + * Accomplished by checking the TLS map. This will always return a valid + * ThreadImpl instance. + * + * @return ThreadImpl* current implementation that maps to the + * executing thread. + */ + ThreadImpl* ThreadImpl::current() { + + // Get the ThreadImpl previously mapped onto the executing thread. + ThreadImpl* impl = _threadMap.get(); + + // Create a reference thread for any threads that have been 'discovered' + // because they are not created by ZThreads. + if(impl == 0) { + + // Create a ThreadImpl to represent this thread. + impl = new ThreadImpl(); + impl->_state.setReference(); + + ThreadOps::activate(impl); + + // Map a reference thread and insert it into the queue + _threadMap.set(impl); + + ThreadQueue::instance()->insertReferenceThread(impl); + + } + + assert(impl != 0); + return impl; + + } + + /** + * Make current thread sleep for the given number of milliseconds. + * This sleep can be interrupt()ed. + * + * @param ms timeout for the sleep. + * + * @post the calling thread is blocked by waiting on the internal condition + * variable. This can be signaled in the monitor of an interrupt + */ + void ThreadImpl::sleep(unsigned long ms) { + + // Make sleep()ing for 0 milliseconds equivalent to a yield. + if(ms == 0) { + + yield(); + return; + + } + + // Get the monitor for the current thread + Monitor& monitor = current()->getMonitor(); + + // Acquire that threads Monitor with a Guard + Guard g(monitor); + + for(;;) { + + switch(monitor.wait(ms)) { + + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + + default: + return; + + } + + } + + } + + + /** + * Yield the current timeslice to another thread. + * If sched_yield() is available it is used. + * Otherwise, the state Monitor for this thread is used to simiulate a + * yield by blocking for 1 millisecond, which should give the + * scheduler a chance to schedule another thread. + */ + void ThreadImpl::yield() { + + // Try to yield with the native operation. If it fails, then + // simulate with a short wait() on the monitor. + if(!ThreadOps::yield()) { + + // Get the monitor for the current thread + Monitor& monitor = current()->getMonitor(); + + // Attempt a wait(). + Guard g(monitor); + monitor.wait(1); + + } + + } + + void ThreadImpl::start(const Task& task) { + + Guard g1(_monitor); + + // A Thread must be idle in order to be eligable to run a task. + if(!_state.isIdle()) + throw InvalidOp_Exception("Thread is not idle."); + + _state.setRunning(); + + // Spawn a new thread, blocking the parent (current) thread until + // the child starts. + + ThreadImpl* parent = current(); + Launcher launch(parent, this, task); + + // Attempt to start the child thread + Guard g2(parent->_monitor); + + if(!spawn(&launch)) { + + // Return to the idle state & report the error if it doesn't work out. + _state.setIdle(); + throw Synchronization_Exception(); + + + } + + // Wait, uninterruptably, for the child's signal. The parent thread + // still can be interrupted and killed; it just won't take effect + // until the child has started. + + Guard g3(parent->_monitor); + + if(parent->_monitor.wait() != Monitor::SIGNALED) { + assert(0); + } + + + } + + + void ThreadImpl::dispatch(ThreadImpl* parent, ThreadImpl* impl, Task task) { + + // Map the implementation object onto the running thread. + _threadMap.set(impl); + + // Update the reference count on a ThreadImpl before the 'Thread' + // that owns it can go out of scope (by signaling the parent) + impl->addReference(); + + // Update the priority of the thread + if(parent->_state.isReference()) + ThreadOps::setPriority(impl, + parent->_state.isReference() ? impl->_priority : parent->_priority); + + // Inherit ThreadLocal values from the parent + typedef ThreadLocalMap::const_iterator It; + + for(It i = parent->getThreadLocalMap().begin(); i != parent->getThreadLocalMap().end(); ++i) + if( (i->second)->isInheritable() ) + impl->getThreadLocalMap()[ i->first ] = (i->second)->clone(); + + // Insert a user-thread mapping + ThreadQueue::instance()->insertUserThread(impl); + // Wake the parent once the thread is setup + parent->_monitor.notify(); + + ZTDEBUG("Thread starting...\n"); + + // not catch exceptions, let program terminate + //try { + + task->run(); + + //} catch(...) { + + // Result of running a task that threw an exception. + // ZTDEBUG("The task has thrown an unhandled exception\n"); + //assert(0); // UQ1: Go to debugger... + + //} + + ZTDEBUG("Thread joining...\n"); + + { // Update the state of the thread + + Guard g(impl->_monitor); + impl->_state.setJoined(); + + // Wake the joiners that will be easy to join first + for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end();) { + + ThreadImpl* joiner = *i; + Monitor& m = joiner->getMonitor(); + + if(m.tryAcquire()) { + + m.notify(); + m.release(); + + i = impl->_joiners.erase(i); + + } else + ++i; + + } + + // Wake the joiners that might take a while next + for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end(); ++i) { + + ThreadImpl* joiner = *i; + Monitor& m = joiner->getMonitor(); + + m.acquire(); + m.notify(); + m.release(); + + } + + } + + ZTDEBUG("Thread exiting...\n"); + + // Insert a pending-thread mapping, allowing the resources to be reclaimed + ThreadQueue::instance()->insertPendingThread(impl); + + // Cleanup ThreadLocal values + impl->getThreadLocalMap().clear(); + + // Update the reference count allowing it to be destroyed + impl->delReference(); + + } + + +} // namespace ZThread diff --git a/src/dep/src/zthread/ThreadImpl.h b/src/dep/src/zthread/ThreadImpl.h new file mode 100644 index 0000000..ae2c8f2 --- /dev/null +++ b/src/dep/src/zthread/ThreadImpl.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADIMPL_H__ +#define __ZTTHREADIMPL_H__ + +#include "zthread/ThreadLocalImpl.h" +#include "zthread/Thread.h" +#include "zthread/Exceptions.h" +#include "IntrusivePtr.h" + +#include "Monitor.h" +#include "TSS.h" +#include "ThreadOps.h" +#include "State.h" + +#include +#include + +namespace ZThread { + +/** + * @class ThreadImpl + * @author Eric Crahen + * @date <2003-07-27T13:39:03-0400> + * @version 2.3.0 + */ +class ThreadImpl : public IntrusivePtr, public ThreadOps { + + typedef std::deque List; + + //! TSS to store implementation to current thread mapping. + static TSS _threadMap; + + //! The Monitor for controlling this thread + Monitor _monitor; + + //! Current state for the thread + State _state; + + //! Joining threads + List _joiners; + + public: + + typedef std::map ThreadLocalMap; + + private: + + ThreadLocalMap _tls; + + //! Cached thread priority + Priority _priority; + + //! Request cancel() when main() goes out of scope + bool _autoCancel; + + void start(const Task& task); + + public: + + ThreadImpl(); + + ThreadImpl(const Task&, bool); + + ~ThreadImpl(); + + Monitor& getMonitor(); + + void cancel(bool autoCancel = false); + + bool interrupt(); + + bool isInterrupted(); + + bool isCanceled(); + + Priority getPriority() const; + + // ThreadLocalMap& getThreadLocalMap(); + ThreadLocalMap& getThreadLocalMap() { return _tls; } + + bool join(unsigned long); + + void setPriority(Priority); + + bool isActive(); + + bool isReference(); + + static void sleep(unsigned long); + + static void yield(); + + static ThreadImpl* current(); + + static void dispatch(ThreadImpl*, ThreadImpl*, Task); + +}; + +} // namespace ZThread + +#endif // __ZTTHREADIMPL_H__ diff --git a/src/dep/src/zthread/ThreadLocalImpl.cxx b/src/dep/src/zthread/ThreadLocalImpl.cxx new file mode 100644 index 0000000..25682e6 --- /dev/null +++ b/src/dep/src/zthread/ThreadLocalImpl.cxx @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/ThreadLocalImpl.h" +#include "ThreadImpl.h" + +namespace ZThread { + + ThreadLocalImpl::ThreadLocalImpl() {} + + ThreadLocalImpl::~ThreadLocalImpl() {} + + void ThreadLocalImpl::clearAll() { + + typedef ThreadImpl::ThreadLocalMap Map; + Map& m = ThreadImpl::current()->getThreadLocalMap(); + + m.clear(); + + } + + void ThreadLocalImpl::clear() const { + + typedef ThreadImpl::ThreadLocalMap Map; + Map& m = ThreadImpl::current()->getThreadLocalMap(); + + Map::iterator i = m.find(this); + if(i != m.end()) + m.erase(i); + + } + + ThreadLocalImpl::ValuePtr ThreadLocalImpl::value( ValuePtr(*pfn)() ) const { + + typedef ThreadImpl::ThreadLocalMap Map; + Map& m = ThreadImpl::current()->getThreadLocalMap(); + + Map::iterator i = m.find(this); + if(i != m.end()) + return i->second; + + m[ this ] = ValuePtr( pfn() ); + return m[ this ]; + + } + +} // namespace ZThread diff --git a/src/dep/src/zthread/ThreadOps.cxx b/src/dep/src/zthread/ThreadOps.cxx new file mode 100644 index 0000000..53a3e44 --- /dev/null +++ b/src/dep/src/zthread/ThreadOps.cxx @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADOPSIMPLSELECT_CXX__ +#define __ZTTHREADOPSIMPLSELECT_CXX__ + +#include "ThreadOps.h" + +// This file will select an implementation for a ThreadOps based on +// what ThreadOps.h selects. This method is for selecting the +// source files, to improve portability. Currently, the project is +// based on the autoconf tool-set, which doesn't support conditional +// compilation well. Additionally, this should make the library +// easier to port since its working around conditional compilation +// by using C++ features and people won't have to fiddle around with +// their make tool as much to compile the source + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +// Check for sched_yield() + +#if !defined(HAVE_SCHED_YIELD) +# if defined(HAVE_UNISTD_H) +# include +# if defined(_POSIX_PRIORITY_SCHEDULING) +# define HAVE_SCHED_YIELD 1 +# endif +# endif +#endif + +#include ZT_THREADOPS_IMPLEMENTATION + +#endif diff --git a/src/dep/src/zthread/ThreadOps.h b/src/dep/src/zthread/ThreadOps.h new file mode 100644 index 0000000..eef9f3c --- /dev/null +++ b/src/dep/src/zthread/ThreadOps.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADOPSSELECT_H__ +#define __ZTTHREADOPSSELECT_H__ + +#include "zthread/Config.h" + +#if defined(ZT_THREADOPS_IMPLEMENTATION) +# error "Reserved symbol defined" +#endif + + +// Select the correct implementation +#if defined(ZT_POSIX) + +# include "posix/ThreadOps.h" +# define ZT_THREADOPS_IMPLEMENTATION "posix/ThreadOps.cxx" + +#elif defined(ZT_WIN32) || defined(ZT_WIN9X) + +// Visual C provides the _beginthreadex function, other compilers +// might not have this if they don't use Microsoft's C runtime. +// _beginthreadex is similar to in effect defining REENTRANT on a +// POSIX system. CreateThreadEx doesn't use reentrant parts of the +// Microsfot C runtime, but if your not using that runtime, no problem. + +# if !defined(HAVE_BEGINTHREADEX) +# if defined(_MSC_VER) +# define HAVE_BEGINTHREADEX +# endif +# endif + +# include "win32/ThreadOps.h" +# define ZT_THREADOPS_IMPLEMENTATION "win32/ThreadOps.cxx" + +#elif defined(ZT_MACOS) + +# include "macos/ThreadOps.h" +# define ZT_THREADOPS_IMPLEMENTATION "macos/ThreadOps.cxx" + +#endif + +#ifndef __ZTTHREADOPS_H__ +#error "No ThreadOps implementation could be selected" +#endif + +#endif // __ZTTHREADOPSSELECT_H__ diff --git a/src/dep/src/zthread/ThreadQueue.cxx b/src/dep/src/zthread/ThreadQueue.cxx new file mode 100644 index 0000000..0234950 --- /dev/null +++ b/src/dep/src/zthread/ThreadQueue.cxx @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "DeferredInterruptionScope.h" +#include "Debug.h" +#include "ThreadImpl.h" +#include "ThreadQueue.h" + +#include +#include + +namespace ZThread { + + ThreadQueue::ThreadQueue() + : _waiter(0) { + + ZTDEBUG("ThreadQueue created\n"); + + } + + ThreadQueue::~ThreadQueue() { + + ZTDEBUG("ThreadQueue waiting on remaining threads...\n"); + + // Ensure the current thread is mapped. + ThreadImpl* impl = ThreadImpl::current(); + + bool threadsWaiting = false; + bool waitRequired = false; + + { + + TaskList shutdownTasks; + + { // Check the queue to for pending user threads + + Guard g(_lock); + + waitRequired = (_waiter != (ThreadImpl*)1); + _waiter = impl; + + threadsWaiting = !_userThreads.empty() || !_pendingThreads.empty(); + + //ZTDEBUG("Wait required: %d\n", waitRequired); + //ZTDEBUG("Threads waiting: %d\n", threadsWaiting); + + // Auto-cancel any active threads at the time main() goes out of scope + // "force" a gentle exit from the executing tasks; eventually the user- + // threads will transition into pending-threads + pollUserThreads(); + + // Remove all the tasks about to be run from the task list so an indication + // can be given to threads calling removeShutdownTask() too late. + std::remove_copy(_shutdownTasks.begin(), + _shutdownTasks.end(), + std::back_inserter(shutdownTasks), + Task((Runnable*)0)); + + //ZTDEBUG("Threads waiting: %d\n", threadsWaiting); + + } + + // Execute the shutdown tasks + for(TaskList::iterator i = shutdownTasks.begin(); i != shutdownTasks.end(); ++i) { + try { + (*i)->run(); + } catch(...) { } + } + + } + + // Wait for all the users threads to get into the appropriate state + if(threadsWaiting) { + + + Monitor& m = _waiter->getMonitor(); + + // Defer interruption while this thread waits for a signal from + // the last pending user thread + Guard > g(m); + //ZTDEBUG("Threads waiting: %d %d\n", _userThreads.size(), _pendingThreads.size()); + + // Avoid race-condition where the last threads are done with thier tasks, but + // only begin the final part of the clean up phase after this destructor begins + // to run. Takes advantage of the fact that if all remaining threads have transitioned + // into a pending state by the time execution reaches this point, then there is no + // need to wait. + waitRequired = waitRequired && !(_userThreads.empty() && !_pendingThreads.empty()); + + // Reference threads can't be interrupted or otherwise + // manipulated. The only signal this monitor will receive + // at this point will be from the last pending thread. + if(waitRequired && m.wait() != Monitor::SIGNALED) { + assert(0); + } + + // Join those pending threads + pollPendingThreads(); + + } + + // Clean up the reference threads + pollReferenceThreads(); + + ZTDEBUG("ThreadQueue destroyed\n"); + + } + + + void ThreadQueue::insertPendingThread(ThreadImpl* impl) { + ZTDEBUG("insertPendingThread()\n"); + Guard g(_lock); + + // Move from the user-thread list to the pending-thread list + ThreadList::iterator i = std::find(_userThreads.begin(), _userThreads.end(), impl); + if(i != _userThreads.end()) + _userThreads.erase(i); + + _pendingThreads.push_back(impl); + + // Wake the main thread,if its waiting, when the last pending-thread becomes available; + // Otherwise, take note that no wait for pending threads to finish is needed + if(_userThreads.empty()) + if(_waiter && _waiter != (ThreadImpl*)1) + _waiter->getMonitor().notify(); + else + _waiter = (ThreadImpl*)!_waiter; + + ZTDEBUG("1 pending-thread added.\n"); + + } + + void ThreadQueue::insertReferenceThread(ThreadImpl* impl) { + + Guard g(_lock); + _referenceThreads.push_back(impl); + + ZTDEBUG("1 reference-thread added.\n"); + + } + + void ThreadQueue::insertUserThread(ThreadImpl* impl) { + + Guard g(_lock); + _userThreads.push_back(impl); + + // Reclaim pending-threads + pollPendingThreads(); + + // Auto-cancel threads that are started when main() is out of scope + if(_waiter) + impl->cancel(true); + + ZTDEBUG("1 user-thread added.\n"); + + } + + + void ThreadQueue::pollPendingThreads() { + + ZTDEBUG("pollPendingThreads()\n"); + + for(ThreadList::iterator i = _pendingThreads.begin(); i != _pendingThreads.end();) { + + ThreadImpl* impl = (ThreadImpl*)*i; + ThreadOps::join(impl); + + impl->delReference(); + + i = _pendingThreads.erase(i); + + ZTDEBUG("1 pending-thread reclaimed.\n"); + + } + + } + + void ThreadQueue::pollReferenceThreads() { + + ZTDEBUG("pollReferenceThreads()\n"); + + for(ThreadList::iterator i = _referenceThreads.begin(); i != _referenceThreads.end(); ++i) { + + ThreadImpl* impl = (ThreadImpl*)*i; + impl->delReference(); + + ZTDEBUG("1 reference-thread reclaimed.\n"); + + } + + } + + void ThreadQueue::pollUserThreads() { + + ZTDEBUG("pollUserThreads()\n"); + + for(ThreadList::iterator i = _userThreads.begin(); i != _userThreads.end(); ++i) { + + ThreadImpl* impl = *i; + impl->cancel(true); + + ZTDEBUG("1 user-thread reclaimed.\n"); + + } + + } + + void ThreadQueue::insertShutdownTask(Task& task) { + + bool hasWaiter = false; + + { + + Guard g(_lock); + + // Execute later when the ThreadQueue is destroyed + if( !(hasWaiter = (_waiter != 0)) ) { + + _shutdownTasks.push_back(task); + //ZTDEBUG("1 shutdown task added. %d\n", _shutdownTasks.size()); + + } + + } + + // Execute immediately if things are shutting down + if(hasWaiter) + task->run(); + + } + + bool ThreadQueue::removeShutdownTask(const Task& task) { + + Guard g(_lock); + + TaskList::iterator i = std::find(_shutdownTasks.begin(), _shutdownTasks.end(), task); + bool removed = (i != _shutdownTasks.end()); + if(removed) + _shutdownTasks.erase(i); + + //ZTDEBUG("1 shutdown task removed (%d)-%d\n", removed, _shutdownTasks.size()); + + return removed; + + } + +}; diff --git a/src/dep/src/zthread/ThreadQueue.h b/src/dep/src/zthread/ThreadQueue.h new file mode 100644 index 0000000..044f826 --- /dev/null +++ b/src/dep/src/zthread/ThreadQueue.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADQUEUE_H__ +#define __ZTTHREADQUEUE_H__ + +#include "zthread/Singleton.h" +#include "zthread/Guard.h" +#include "FastLock.h" + + +namespace ZThread { + + class ThreadImpl; + + /** + * @class ThreadQueue + * @version 2.3.0 + * @author Eric Crahen + * @date <2003-07-27T20:52:05-0400> + * + * A ThreadQueue accumulates references to user and reference threads. + * These are threads that are running outside the scope of the Thread + * object that created them. ZThreads doesn't have a central manager for + * all threads (partly why I renamed the ThreadManager to someting more + * appropriate). Instead, ZThreads will discover threads it did not create + * and create a reference thread that allows ZThreads to interact with it. + * Non user threads that are created by the user never have to touch the + * ThreadQueue. + */ + class ThreadQueue : public Singleton { + + typedef std::deque ThreadList; + typedef std::deque TaskList; + + //! Managed thread lists + ThreadList _pendingThreads; + ThreadList _referenceThreads; + ThreadList _userThreads; + + //! Shutdown handlers + TaskList _shutdownTasks; + + //! Serilize access to the thread list + FastLock _lock; + + //! Reference thread waiting to cleanup any user & reference threads + ThreadImpl* _waiter; + + public: + + ThreadQueue(); + + /** + * The thread destroys a ThreadQueue will be a reference thread, + * probably the main thread; but it could be another thread that + * started and loaded the library. + */ + ~ThreadQueue(); + + /** + * Insert a user-thread into the queue. User-threads are inserted as they + * begin thier task. Once that task completes, user-threads are automatically + * transitioned to pending-threads via insertPendingThread(). + * + * User-threads are known to be executing thier tasks and will be cancel()ed + * as the ThreadQueue is destroyed when main() goes out of scope. This sends + * a request to the task to complete soon. Once the task exits, the thread is + * transitioned to pending-thread status. + */ + void insertUserThread(ThreadImpl*); + + /** + * Insert a pending-thread into the queue. + * + * Pending-threads are known to have completed thier tasks and thier + * resources are reclaimed (lazily) as more threads are started or as the + * ThreadQueue is destroyed. + */ + void insertPendingThread(ThreadImpl*); + + + /** + * Insert reference thread. Reference threads are not removed until + * the ThreadQueue goes out of scope. + */ + void insertReferenceThread(ThreadImpl*); + + /** + * Insert a task to be run before threads are joined. + * Any items inserted after the ThreadQueue desctructor has begun to + * execute will be run() immediately. + */ + void insertShutdownTask(Task&); + + /** + * Remove an existing shutdown task. + */ + bool removeShutdownTask(const Task&); + + private: + + void pollPendingThreads(); + + void pollUserThreads(); + + void pollReferenceThreads(); + + }; + + +} // namespace ZThread + + +#endif // __ZTTHREADQUEUE_H__ diff --git a/src/dep/src/zthread/ThreadedExecutor.cxx b/src/dep/src/zthread/ThreadedExecutor.cxx new file mode 100644 index 0000000..44a213e --- /dev/null +++ b/src/dep/src/zthread/ThreadedExecutor.cxx @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/ThreadedExecutor.h" +#include "zthread/Guard.h" +#include "zthread/FastMutex.h" +#include "zthread/Time.h" + +#include "ThreadImpl.h" + +namespace ZThread { + + namespace { + + //! + class WaiterQueue { + + typedef std::deque ThreadList; + + typedef struct group_t { + size_t id; + size_t count; + ThreadList waiters; + group_t(size_t n) : id(n), count(0) {} + } Group; + + typedef std::deque GroupList; + + //! Predicate to find a specific group + struct by_id : public std::unary_function { + size_t id; + by_id(size_t n) : id(n) {} + bool operator()(const Group& grp) { + return grp.id == id; + } + }; + + //! Functor to count groups + struct counter : public std::unary_function { + size_t count; + counter() : count(0) {} + void operator()(const Group& grp) { count += grp.count; } + operator size_t() { return count; } + }; + + FastMutex _lock; + GroupList _list; + size_t _id; + size_t _generation; + + public: + + WaiterQueue() : _id(0), _generation(0) { + // At least one empty-group exists + _list.push_back( Group(_id++) ); + } + + /** + * Insert the current thread into the current waiter list + * + * @pre At least one empty group exists + * @post At least one empty group exists + */ + bool wait(unsigned long timeout) { + + ThreadImpl* self = ThreadImpl::current(); + Monitor& m = self->getMonitor(); + + Monitor::STATE state; + + Guard g1(_lock); + + // At least one empty-group exists + assert(!_list.empty()); + + // Return w/o waiting if there are no executing tasks + if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1) + return true; + + // Update the waiter list for the active group + _list.back().waiters.push_back(self); + size_t n = _list.back().id; + + m.acquire(); + + { + + Guard g2(g1); + state = timeout == 0 ? m.wait() : m.wait(timeout); + + } + + m.release(); + + // If awoke due to a reason other than the last task in the group 'n' completing, + // then then find the group 'self' is waiting in + GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n)); + if(i != _list.end()) { + + // Remove 'self' from that list if it is still a member + ThreadList::iterator j = std::find(i->waiters.begin(), i->waiters.end(), self); + if(j != i->waiters.end()) + i->waiters.erase(j); + + } + + // At least one empty-group exists + assert(!_list.empty()); + + switch(state) { + case Monitor::SIGNALED: + break; + case Monitor::TIMEDOUT: + return false; + case Monitor::INTERRUPTED: + throw Interrupted_Exception(); + default: + throw Synchronization_Exception(); + } + + return true; + + } + + /** + * Increment the active group count + * + * @pre at least 1 empty group exists + * @post at least 1 non-empty group exists + */ + std::pair increment() { + + Guard g(_lock); + + // At least one empty-group exists + assert(!_list.empty()); + + GroupList::iterator i = --_list.end(); + size_t n = i->id; + + if(i == _list.end()) { + + // A group should never have been removed until + // the final task in that group completed + assert(0); + + } + + i->count++; + + // When the active group is being incremented, insert a new active group + // to replace it if there were waiting threads + if(i == --_list.end() && !i->waiters.empty()) + _list.push_back(Group(_id++)); + + // At least 1 non-empty group exists + assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0); + + return std::make_pair(n, _generation); + + } + + + /** + * Decrease the count for the group with the given id. + * + * @param n group id + * + * @pre At least 1 non-empty group exists + * @post At least 1 empty group exists + */ + void decrement(size_t n) { + + Guard g1(_lock); + + // At least 1 non-empty group exists + assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0); + + // Find the requested group + GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n)); + if(i == _list.end()) { + + // A group should never have been removed until + // the final task in that group completed + assert(0); + + } + + // Decrease the count for tasks in this group, + if(--i->count == 0 && i == _list.begin()) { + + do { + + // When the first group completes, wake all waiters for every + // group, starting from the first until a group that is not + // complete is reached + + /* + // Don't remove the empty active group + if(i == --_list.end() && i->waiters.empty()) + break; + */ + + if( awaken(*i) ) { + + // If all waiters were awakened, remove the group + i = _list.erase(i); + + } else { + + { + + // Otherwise, unlock and yield allowing the waiter + // lists to be updated if other threads are busy + Guard g2(g1); + ThreadImpl::yield(); + + } + + i = _list.begin(); + + } + + } while(i != _list.end() && i->count == 0); + + // Ensure that an active group exists + if(_list.empty()) + _list.push_back( Group(++_id) ); + + } + + // At least one group exists + assert(!_list.empty()); + + } + + /** + */ + size_t generation(bool next = false) { + + Guard g(_lock); + return next ? _generation++ : _generation; + + } + + private: + + /** + * Awaken all the waiters remaining in the given group + * + * @return + * - true if all the waiting threads were successfully awakened. + * - false if there were one or more threads that could not be awakened. + */ + bool awaken(Group& grp) { + + // Go through the waiter list in the given group; + for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) { + + ThreadImpl* impl = *i; + Monitor& m = impl->getMonitor(); + + // Try the monitor lock, if it cant be locked skip to the next waiter + if(m.tryAcquire()) { + + // Notify the monitor & remove from the waiter list so time isn't + // wasted checking it again. + i = grp.waiters.erase(i); + + // Try to wake the waiter, it doesn't matter if this is successful + // or not (only fails when the monitor is already going to stop waiting). + m.notify(); + m.release(); + + } else ++i; + + } + + return grp.waiters.empty(); + + } + + }; + + //! Synchronization point for the Executor + class ExecutorImpl { + + typedef std::deque ThreadList; + + bool _canceled; + FastMutex _lock; + + //! Worker threads + ThreadList _threads; + + WaiterQueue _queue; + + public: + + ExecutorImpl() : _canceled(false) {} + + WaiterQueue& getWaiterQueue() { + return _queue; + } + + void registerThread(size_t generation) { + + // Interrupt slow starting threads + if(getWaiterQueue().generation() != generation) + ThreadImpl::current()->interrupt(); + + // Enqueue for possible future interrupt() + else { + + Guard g(_lock); + _threads.push_back( ThreadImpl::current() ); + + } + + } + + void unregisterThread() { + + Guard g(_lock); + std::remove(_threads.begin(), _threads.end(), ThreadImpl::current() ); + + } + + void cancel() { + + Guard g(_lock); + _canceled = true; + + } + + bool isCanceled() { + + if(_canceled) + return true; + + Guard g(_lock); + return _canceled; + + } + + void interrupt() { + + Guard g(_lock); + + // Interrupt all the registered threads + for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i) + (*i)->interrupt(); + + // Bump the generation up, ensuring slow starting threads get this interrupt + getWaiterQueue().generation( true ); + + } + + }; /* ExecutorImpl */ + + //! Wrap a generation and a group around a task + class Worker : public Runnable { + + CountedPtr< ExecutorImpl > _impl; + Task _task; + + size_t _generation; + size_t _group; + + public: + + Worker(const CountedPtr< ExecutorImpl >& impl, const Task& task) + : _impl(impl), _task(task) { + + std::pair pr( _impl->getWaiterQueue().increment() ); + + _group = pr.first; + _generation = pr.second; + + } + + size_t group() const { + return _group; + } + + size_t generation() const { + return _generation; + } + + void run() { + + // Register this thread once its begun; the generation is used to ensure + // threads that are slow starting are properly interrupted + + _impl->registerThread( generation() ); + + try { + _task->run(); + } catch(...) { + /* consume the exceptions the work propogates */ + } + + _impl->getWaiterQueue().decrement( group() ); + + // Unregister this thread + + _impl->unregisterThread(); + + } + + }; /* Worker */ + + } + + ThreadedExecutor::ThreadedExecutor() : _impl(new ExecutorImpl) {} + + ThreadedExecutor::~ThreadedExecutor() {} + + void ThreadedExecutor::execute(const Task& task) { + + Thread t( new Worker(_impl, task) ); + + } + + void ThreadedExecutor::interrupt() { + _impl->interrupt(); + } + + void ThreadedExecutor::cancel() { + _impl->cancel(); + } + + bool ThreadedExecutor::isCanceled() { + return _impl->isCanceled(); + } + + void ThreadedExecutor::wait() { + _impl->getWaiterQueue().wait(0); + } + + bool ThreadedExecutor::wait(unsigned long timeout) { + return _impl->getWaiterQueue().wait(timeout == 0 ? 1 : timeout); + } + +} diff --git a/src/dep/src/zthread/Time.cxx b/src/dep/src/zthread/Time.cxx new file mode 100644 index 0000000..2409d93 --- /dev/null +++ b/src/dep/src/zthread/Time.cxx @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "zthread/Time.h" +#include "TimeStrategy.h" + + +using namespace ZThread; + +Time::Time() { + + // System startup time + static TimeStrategy firstHelper; + TimeStrategy helper; + + Time then(firstHelper.seconds(), firstHelper.milliseconds()); + Time now(helper.seconds(), helper.milliseconds()); + + now -= then; + + _seconds = now.seconds(); + _milliseconds = now.milliseconds(); + +} + + diff --git a/src/dep/src/zthread/TimeStrategy.h b/src/dep/src/zthread/TimeStrategy.h new file mode 100644 index 0000000..0b9ad1e --- /dev/null +++ b/src/dep/src/zthread/TimeStrategy.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIMESELECT_H__ +#define __ZTTIMESELECT_H__ + +#include "zthread/Config.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +// Select the correct TimeOps implementation based on +// what the complilation environment has defined + +#ifndef HAVE_FTIME + +# if defined(ZT_WIN32) || defined(ZT_WIN9X) + +# if !defined(__MWERKS__) + +# ifndef HAVE_FTIME +# define HAVE_FTIME +# endif + +# elif defined(__MWERKS__) + +# ifndef HAVE_PERFORMANCECOUNTER +# define HAVE_PERFORMANCECOUNTER +# endif + +# endif + +# endif + +#endif + +// Some systems require this to complete the definition of timespec +// which is needed by pthreads. +#if defined(HAVE_SYS_TYPES_H) +# include +#endif + +#if defined(ZT_MACOS) + +# include "macos/UpTimeStrategy.h" + +#elif defined(HAVE_PERFORMANCECOUNTER) + +# include "win32/PerformanceCounterStrategy.h" + +#elif defined(HAVE_FTIME) + +# include "posix/FtimeStrategy.h" + +#else + +# include "posix/GetTimeOfDayStrategy.h" + +#endif + + +#ifndef __ZTTIMESTRATEGY_H__ +#error "No TimeStrategy implementation could be selected" +#endif + +#endif // __ZTTIMESELECT_H__ diff --git a/src/dep/src/zthread/config.h b/src/dep/src/zthread/config.h new file mode 100644 index 0000000..f2eff48 --- /dev/null +++ b/src/dep/src/zthread/config.h @@ -0,0 +1,95 @@ +/* src/config.h. Generated by configure. */ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Defined if is usable */ +/* #undef HAVE_ATOMIC_GCC */ + +/* Defined if is usable */ +/* #undef HAVE_ATOMIC_LINUX */ + +/* _beginthreadex() */ +/* #undef HAVE_BEGINTHREADEX */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* defined when pthreads is available */ +#define HAVE_POSIX_THREADS + +/* Defined if pthread_keycreate() is available */ +/* #undef HAVE_PTHREADKEYCREATE */ + +/* Defined if pthread_key_create() is available */ +#define HAVE_PTHREADKEY_CREATE + +/* Defined if pthread_yield() is available */ +#define HAVE_PTHREAD_YIELD + +/* Defined if -lrt is needed for RT scheduling */ +#define HAVE_SCHED_RT + +/* Defined if sched_yield() is available */ +#define HAVE_SCHED_YIELD + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "ZThread" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Defined if ftime()/_ftime() is usable */ +#define SYSTEM_FTIME ftime + +/* Version number of package */ +#define VERSION "2.3.2" + +/* No interrupt() hooks */ +/* #undef ZTHREAD_DISABLE_INTERRUPT */ + +/* No OS priority support */ +/* #undef ZTHREAD_DISABLE_PRIORITY */ diff --git a/src/dep/src/zthread/linux/AtomicCount.cxx b/src/dep/src/zthread/linux/AtomicCount.cxx new file mode 100644 index 0000000..28c2381 --- /dev/null +++ b/src/dep/src/zthread/linux/AtomicCount.cxx @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNTIMPL_H__ +#define __ZTATOMICCOUNTIMPL_H__ + +#include +#include + +namespace ZThread { + +typedef struct atomic_count_t { + + atomic_t count; + + atomic_count_t() { + atomic_t init = ATOMIC_INIT(0); + count = init; + } + + ~atomic_count_t() { + assert(atomic_read(&count) == 0); + } + +} ATOMIC_COUNT; + + +AtomicCount::AtomicCount() { + + _value = reinterpret_cast(new ATOMIC_COUNT); + +} + +AtomicCount::~AtomicCount() { + + delete reinterpret_cast(_value); + +} + +void AtomicCount::increment() { + + atomic_inc(&reinterpret_cast(_value)->count); + +} + +bool AtomicCount::decrement() { + + return atomic_dec_and_test(&reinterpret_cast(_value)->count); + +} + +}; + +#endif // __ZTATOMICCOUNTIMPL_H__ diff --git a/src/dep/src/zthread/linux/AtomicFastLock.h b/src/dep/src/zthread/linux/AtomicFastLock.h new file mode 100644 index 0000000..b9aa1ba --- /dev/null +++ b/src/dep/src/zthread/linux/AtomicFastLock.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/NonCopyable.h" +#include "../ThreadOps.h" +#include +#include + +#if !defined(NDEBUG) +# include +#endif + +namespace ZThread { + +/** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:27:03-0400> + * @version 2.2.0 + * + * This implementation of a FastLock uses the atomic operations that + * linux provides with its kernel sources. This demonstrates how to implement + * a spinlock with a decrement and test primative. + */ +class FastLock : private NonCopyable { + + atomic_t _value; + +#if !defined(NDEBUG) + pthread_t _owner; +#endif + +public: + + inline FastLock() { + + atomic_t tmp = ATOMIC_INIT(1); + _value = tmp; + + } + + inline ~FastLock() { + + assert(atomic_read(&_value) == 1); + assert(_owner == 0); + + } + + inline void acquire() { + + while(!atomic_dec_and_test(&_value)) { + + atomic_inc(&_value); + ThreadOps::yield(); + + } + +#if !defined(NDEBUG) + _owner = pthread_self(); +#endif + } + + inline void release() { + +#if !defined(NDEBUG) + assert(pthread_equal(_owner, pthread_self()) != 0); +#endif + + atomic_inc(&_value); + _owner = 0; + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + bool wasLocked = atomic_dec_and_test(&_value); + if(!wasLocked) + atomic_inc(&_value); + +#if !defined(NDEBUG) + if(wasLocked) + _owner = pthread_self(); +#endif + + return wasLocked; + + } + +}; /* FastLock */ + + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/linux/FastRecursiveLock.h b/src/dep/src/zthread/linux/FastRecursiveLock.h new file mode 100644 index 0000000..d253652 --- /dev/null +++ b/src/dep/src/zthread/linux/FastRecursiveLock.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "zthread/NonCopyable.h" +#include + +namespace ZThread { + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:27:14-0400> + * @version 2.2.0 + * + * This implementation of a FastRecursiveLock uses the recursive mutex + * that linux pthreads provides. + */ +class FastRecursiveLock : private NonCopyable { + + pthread_mutex_t _mtx; + +public: + + inline FastRecursiveLock() { + + static const pthread_mutexattr_t attr = { PTHREAD_MUTEX_RECURSIVE_NP }; + pthread_mutex_init(&_mtx, &attr); + + } + + inline ~FastRecursiveLock() { + + pthread_mutex_destroy(&_mtx); + + } + + inline void acquire() { + + pthread_mutex_lock(&_mtx); + + } + + inline void release() { + + pthread_mutex_unlock(&_mtx); + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + return (pthread_mutex_trylock(&_mtx) == 0); + + } + +}; /* FastRecursiveLock */ + + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/macos/FastLock.h b/src/dep/src/zthread/macos/FastLock.h new file mode 100644 index 0000000..bae5c48 --- /dev/null +++ b/src/dep/src/zthread/macos/FastLock.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/NonCopyable.h" +#include "zthread/Exceptions.h" + +#include +#include +//#include + +namespace ZThread { + +/** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:25:31-0400> + * @version 2.1.6 + * + */ +class FastLock : private NonCopyable { + + MPCriticalRegionID _mtx; + + public: + + /** + * Create a new FastLock. No safety or state checks are performed. + * + * @exception Initialization_Exception - not thrown + */ + inline FastLock() { + + // Apple TN1071 + static bool init = MPLibraryIsLoaded(); + + if(!init || MPCreateCriticalRegion(&_mtx) != noErr) { + assert(0); + throw Initialization_Exception(); + } + + } + + /** + * Destroy a FastLock. No safety or state checks are performed. + */ + inline ~FastLock() throw () { + + OSStatus status = MPDeleteCriticalRegion(_mtx); + if(status != noErr) + assert(false); + + } + + /** + * Acquire an exclusive lock. No safety or state checks are performed. + * + * @exception Synchronization_Exception - not thrown + */ + inline void acquire() { + + if(MPEnterCriticalRegion(_mtx, kDurationForever) != noErr) + throw Synchronization_Exception(); + + } + + /** + * Try to acquire an exclusive lock. No safety or state checks are performed. + * This function returns immediately regardless of the value of the timeout + * + * @param timeout Unused + * @return bool + * @exception Synchronization_Exception - not thrown + */ + inline bool tryAcquire(unsigned long timeout=0) { + + OSStatus status = + MPEnterCriticalRegion(_mtx, kDurationMillisecond * timeout); + + switch(status) { + case kMPTimeoutErr: + return false; + + case noErr: + return true; + + } + + assert(0); + throw Synchronization_Exception(); + + } + + /** + * Release an exclusive lock. No safety or state checks are performed. + * The caller should have already acquired the lock, and release it + * only once. + * + * @exception Synchronization_Exception - not thrown + */ + inline void release() { + + if(MPExitCriticalRegion(_mtx) != noErr) + throw Synchronization_Exception(); + + } + + +}; /* FastLock */ + + +}; + +#endif + + + diff --git a/src/dep/src/zthread/macos/Monitor.cxx b/src/dep/src/zthread/macos/Monitor.cxx new file mode 100644 index 0000000..ab7806b --- /dev/null +++ b/src/dep/src/zthread/macos/Monitor.cxx @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Monitor.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +using namespace ZThread; + +Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) { + + if(MPCreateSemaphore(1, 0, &_sema) != noErr) { + assert(0); + throw Initialization_Exception(); + } + +} + +Monitor::~Monitor() throw() { + + assert(!_waiting); + + OSStatus status = MPDeleteSemaphore(_sema); + if(status != noErr) + assert(false); + +} + +Monitor::STATE Monitor::wait(unsigned long timeout) { + + // Calcuate the time, taking into account Intertask Signaling Time + // http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/index.html?http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/Functions/Creating_and_ssage_Queues.html + + AbsoluteTime tTarget; + Duration waitDuration = + (timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout); + + if(waitDuration != kDurationForever) + tTarget = AddDurationToAbsolute(waitDuration, UpTime()); + + // Update the owner on first use. The owner will not change, each + // thread waits only on a single Monitor and a Monitor is never + // shared + if(_owner == 0) + _owner = MPCurrentTaskID(); + + STATE state(INVALID); + + // Serialize access to the state of the Monitor + // and test the state to determine if a wait is needed. + _waitLock.acquire(); + + if(pending(ANYTHING)) { + + // Return without waiting when possible + state = next(); + + _waitLock.release(); + return state; + + } + // Unlock the external lock if a wait() is probably needed. + // Access to the state is still serial. + _lock.release(); + + // Wait for a transition in the state that is of interest, this + // allows waits to exclude certain flags (e.g. INTERRUPTED) + // for a single wait() w/o actually discarding those flags - + // they will remain set until a wait interested in those flags + // occurs. + + // Wait, ignoring signals + _waiting = true; + + _waitLock.release(); + + // Update the wait time + if(waitDuration != kDurationForever) + waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime()); + + // Sleep until a signal arrives or a timeout occurs + OSStatus status = MPWaitOnSemaphore(_sema, waitDuration); + + // Reacquire serialized access to the state + _waitLock.acquire(); + + // Awaken only when the event is set or the timeout expired + assert(status == kMPTimeoutErr || status == noErr); + + if(status == kMPTimeoutErr) + push(TIMEDOUT); + + // Get the next available STATE + state = next(); + + _waiting = false; + + // Its possible that a timeout will wake the thread before a signal is + // delivered. Absorb that leftover so the next wait isn't aborted right away + if(status == kMPTimeoutErr && _pending) { + + status = MPWaitOnSemaphore(_sema, kDurationForever); + assert(status == noErr); + + } + + _pending = false; + + // Acquire the internal lock & release the external lock + _waitLock.release(); + + // Reaquire the external lock, keep from deadlocking threads calling + // notify(), interrupt(), etc. + _lock.acquire(); + + return state; + +} + + +bool Monitor::interrupt() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterruptable = !pending(INTERRUPTED); + bool hasWaiter = false; + + // Update the state & wake the waiter if there is one + if(wasInterruptable) { + + push(INTERRUPTED); + + wasInterruptable = false; + + if(_waiting && !_pending) { + + _pending = true; + hasWaiter = true; + + } else + wasInterruptable = !(_owner == MPCurrentTaskID()); + + } + + _waitLock.release(); + + if(hasWaiter && !masked(Monitor::INTERRUPTED)) + MPSignalSemaphore(_sema); + + return wasInterruptable; + +} + +bool Monitor::isInterrupted() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterrupted = pending(INTERRUPTED); + clear(INTERRUPTED); + + _waitLock.release(); + + return wasInterrupted; + +} + + +bool Monitor::notify() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasNotifyable = !pending(INTERRUPTED); + bool hasWaiter = false; + + // Set the flag if theres a waiter + if(wasNotifyable) { + + push(SIGNALED); + + if(_waiting && !_pending) { + + _pending = true; + hasWaiter = true; + + } + + } + + _waitLock.release(); + + if(hasWaiter) + MPSignalSemaphore(_sema); + + return wasNotifyable; + +} + + +bool Monitor::cancel() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterrupted = !pending(INTERRUPTED); + bool hasWaiter = false; + + push(CANCELED); + + // Update the state if theres a waiter + if(wasInterrupted) { + + push(INTERRUPTED); + + if(_waiting && !_pending) { + + _pending = true; + hasWaiter = true; + + } + + } + + _waitLock.release(); + + if(hasWaiter && !masked(Monitor::INTERRUPTED)) + MPSignalSemaphore(_sema); + + return wasInterrupted; + +} + +bool Monitor::isCanceled() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasCanceled = Status::examine(CANCELED); + + if(_owner == MPCurrentTaskID()) + clear(INTERRUPTED); + + _waitLock.release(); + + return wasCanceled; + +} + + + + + + + + + + diff --git a/src/dep/src/zthread/macos/Monitor.h b/src/dep/src/zthread/macos/Monitor.h new file mode 100644 index 0000000..f4312d7 --- /dev/null +++ b/src/dep/src/zthread/macos/Monitor.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITOR_H__ +#define __ZTMONITOR_H__ + +#include "../Status.h" +#include "../FastLock.h" + +namespace ZThread { + +/** + * @class Monitor + * @author Eric Crahen + * @date <2003-07-29T11:24:58-0400> + * @version 2.2.1 + */ +class Monitor : public Status, private NonCopyable { + + //! Serialize access to external objects + FastLock _lock; + + //! Serialize access to internal state + FastLock _waitLock; + + //! Semaphore to control the owning thread + MPSemaphoreID _sema; + + //! Owning thread + MPTaskID _owner; + + //! Waiting flag, to avoid uneccessary signals + volatile bool _waiting; + + //! Waiting flag, to avoid too many signals + volatile bool _pending; + + //! State of the monitor + volatile int _state; + + public: + + //! Create a new monitor. + Monitor(); + + //! Destroy the monitor. + ~Monitor() throw(); + + //! Acquire the external lock for this monitor. + inline void acquire() { + _lock.acquire(); + } + + //! Try to acquire the external lock for this monitor. + inline bool tryAcquire() { + return _lock.tryAcquire(); + } + + //! Release the external lock for this monitor. + inline void release() { + _lock.release(); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * Blocks for an indefinent amount of time. + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + inline STATE wait() { + return wait(0); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * May blocks for an indefinent amount of time. + * + * @param timeout - maximum time to block (milliseconds) or 0 to + * block indefinently + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or TIMEDOUT if the maximum wait time expired. + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + STATE wait(unsigned long timeout); + + /** + * Interrupt this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return INTERRUPTED w/o blocking. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool interrupt(); + + /** + * Notify this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return SIGNALED w/o blocking, if no other + * flag is set. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool notify(); + + /** + * Check the state of this monitor, clearing the INTERRUPTED status if set. + * + * @return bool true if the monitor was INTERRUPTED. + * @post INTERRUPTED flag cleared if the calling thread owns the monitor. + */ + bool isInterrupted(); + + /** + * Mark the Status CANCELED, and INTERRUPT the montor. + * + * @see interrupt() + */ + bool cancel(); + + /** + * Test the CANCELED Status, clearing the INTERRUPTED status if set. + * + * @return bool + */ + bool isCanceled(); + +}; + +}; + +#endif diff --git a/src/dep/src/zthread/macos/TSS.h b/src/dep/src/zthread/macos/TSS.h new file mode 100644 index 0000000..3f9805d --- /dev/null +++ b/src/dep/src/zthread/macos/TSS.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTSS_H__ +#define __ZTTSS_H__ + +#include "zthread/NonCopyable.h" +#include "zthread/Exceptions.h" + +#include +#include +//#include + +namespace ZThread { + + /** + * @class TSS + * @author Eric Crahen + * @date <2003-07-27T14:19:10-0400> + * @version 2.1.6 + * + * An abstraction for dealing with POSIX thread specific storage (tss). + * Provides get/set and creation/destruction. + */ + template + class TSS : private NonCopyable { + + TaskStorageIndex _key; + + public: + + /** + * Create a new object for accessing tss. + */ + TSS() { + + // Apple TN1071 + static bool init = MPLibraryIsLoaded(); + + if(!init || MPAllocateTaskStorageIndex(&_key) != noErr) { + assert(0); + throw Initialization_Exception(); + } + + } + + /** + * Destroy the underlying supoprt for accessing tss with this + * object. + */ + ~TSS() { + + OSStatus status = MPDeallocateTaskStorageIndex(_key); + if(status != noErr) + assert(0); + + } + + /** + * Get the value stored in tss. + * + * @return T + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + T get() const { + return reinterpret_cast(MPGetTaskStorageValue(_key)); + } + + + /** + * Store a value in tss. + * + * @param value T + * @return T old value + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + T set(T value) const { + + T oldValue = get(); + + OSStatus status = + MPSetTaskStorageValue(_key, reinterpret_cast(value)); + + if(status != noErr) { + assert(0); + throw Synchronization_Exception(); + } + + return oldValue; + + } + + }; + +} + +#endif + + diff --git a/src/dep/src/zthread/macos/ThreadOps.cxx b/src/dep/src/zthread/macos/ThreadOps.cxx new file mode 100644 index 0000000..6a1a410 --- /dev/null +++ b/src/dep/src/zthread/macos/ThreadOps.cxx @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +#include "ThreadOps.h" +#include "zthread/Exceptions.h" +#include "zthread/Runnable.h" + +namespace ZThread { + +const ThreadOps ThreadOps::INVALID(0); + +ThreadOps::ThreadOps() : _queue(0), _tid(0) { + + if(MPCreateQueue(&_queue) != noErr) + throw Initialization_Exception(); + +} + +ThreadOps::~ThreadOps() throw() { + + if(_queue != 0) { + + OSStatus status = MPDeleteQueue(_queue); + if(status != noErr) + assert(0); + + } + +} + +bool ThreadOps::join(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid != 0); + + OSStatus status = MPWaitOnQueue(ops->_queue, NULL, NULL, NULL, kDurationForever); + + return status == noErr; + +} + +bool ThreadOps::yield() { + + MPYield(); + return true; + +} + +bool ThreadOps::setPriority(ThreadOps* impl, Priority p) { + return true; +} + +bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) { + return true; +} + + +bool ThreadOps::spawn(Runnable* task) { + + OSStatus status = + MPCreateTask(&_dispatch, task, 0UL, _queue, NULL, NULL, 0UL, &_tid); + + return status == noErr; + +} + +OSStatus ThreadOps::_dispatch(void *arg) { + + Runnable* task = reinterpret_cast(arg); + assert(task); + + // Run the task from the correct context + task->run(); + + // Exit the thread + MPExit(noErr); + return noErr; + +} + +} // namespace ZThread + + diff --git a/src/dep/src/zthread/macos/ThreadOps.h b/src/dep/src/zthread/macos/ThreadOps.h new file mode 100644 index 0000000..c100fcf --- /dev/null +++ b/src/dep/src/zthread/macos/ThreadOps.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADOPS_H__ +#define __ZTTHREADOPS_H__ + +#include "zthread/Priority.h" + +#include +#include +//#include +//#include + +namespace ZThread { + +class Runnable; + +/** + * @class ThreadOps + * @author Eric Crahen + * @date <2003-07-16T23:26:01-0400> + * @version 2.2.0 + * + * This class is an abstraction used to perform various operations on a + * native POSIX thread. + */ +class ThreadOps { + + //! Keep track of the pthreads handle for the native thread + MPQueueID _queue; + MPTaskID _tid; + + ThreadOps(MPTaskID tid) : _queue(0), _tid(tid) { } + + static OSStatus _dispatch(void*); + +public: + + const static ThreadOps INVALID; + + /** + * Create a new ThreadOps to manipulate a native thread. + */ + ThreadOps(); + + ThreadOps(const ThreadOps& ops) : _queue(0), _tid(ops._tid) {} + + ~ThreadOps() throw(); + + inline bool operator==(const ThreadOps& ops) const { + return ops._tid == _tid; + } + + const ThreadOps& operator=(const ThreadOps& ops) { + + assert(_queue == 0); + _tid = ops._tid; + + return *this; + + } + + static ThreadOps self() { + return ThreadOps(MPCurrentTaskID()); + } + + /** + * Activating an instance of ThreadOps will map it onto the currently + * executing thread. + */ + static void activate(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid == 0); + + ops->_tid = MPCurrentTaskID(); + + } + + /** + * Test if this object represents the currently executing + * native thread. + * + * @return bool true if successful + */ + + static bool isCurrent(ThreadOps* ops) { + + assert(ops); + + return MPCurrentTaskID() == ops->_tid; + + } + + /** + * Join a native thread. + * + * @return bool true if successful + */ + static bool join(ThreadOps*); + + /** + * Force the current native thread to yield, letting the scheduler + * give the CPU time to another thread. + * + * @return bool true if successful, false if the operation can't + * be supported. + */ + static bool yield(); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param PRIORITY requested priority + * @return bool false if unsuccessful + */ + static bool setPriority(ThreadOps*, Priority); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param Thread::PRIORITY& current priority + * @return bool false if unsuccessful + */ + static bool getPriority(ThreadOps*, Priority&); + +protected: + + /** + * Spawn a native thread. + * + * @param ThreadImpl* parent thread + * @param ThreadImpl* child thread being started. + * @param Runnable* task being executed. + * + * @return bool true if successful + */ + bool spawn(Runnable*); + +}; + + +} + +#endif // __ZTTHREADOPS_H__ + diff --git a/src/dep/src/zthread/macos/UpTimeStrategy.h b/src/dep/src/zthread/macos/UpTimeStrategy.h new file mode 100644 index 0000000..f2056e1 --- /dev/null +++ b/src/dep/src/zthread/macos/UpTimeStrategy.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIMESTRATEGY_H__ +#define __ZTTIMESTRATEGY_H__ + +#include +//#include + +namespace ZThread { + + +/** + * @class TimeStrategy + * + * Implement a strategy for time operatons based on UpTime + */ +class TimeStrategy { + + unsigned long _ms; + unsigned long _s; + + public: + + TimeStrategy() { + + // Get the absolute time in milliseconds relative to the program startup + static AbsoluteTime sysUpTime(UpTime()); + AbsoluteTime delta = AbsoluteDeltaToNanoseconds(UpTime(), sysUpTime); + + uint64_t now = *reinterpret_cast(&delta) / 1000000; + + _s = now / 1000; + _ms = now % 1000; + + } + + inline unsigned long seconds() const { + return _s; + } + + inline unsigned long milliseconds() const { + return _ms; + } + + unsigned long seconds(unsigned long s) { + + unsigned long z = seconds(); + _s = s; + return z; + + } + + unsigned long milliseconds(unsigned long ms) { + + unsigned long z = milliseconds(); + _ms = ms; + + return z; + + } + +}; + +}; + +#endif // __ZTTIMESTRATEGY_H__ diff --git a/src/dep/src/zthread/posix/ConditionRecursiveLock.h b/src/dep/src/zthread/posix/ConditionRecursiveLock.h new file mode 100644 index 0000000..a46ed35 --- /dev/null +++ b/src/dep/src/zthread/posix/ConditionRecursiveLock.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "zthread/NonCopyable.h" +#include +#include +#include + +namespace ZThread { + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:28:37-0400> + * @version 2.2.0 + * + * This is an implementation of a FastRecursiveLock for any vannila + * POSIX system. It is based on a condition variable and a mutex; + * because of this it is important to not that its waiting properties + * are not the same as other mutex implementations that generally + * based on spin locks. Under high contention, this implementation may + * be preferable to a spin lock, although refactoring the design of + * code that puts a mutex under alot of preasure may be worth investigating. + */ +class FastRecursiveLock : private NonCopyable { + + //! Serialize state + pthread_mutex_t _mtx; + + //! Wait for lock + pthread_cond_t _cond; + + //! Owner + pthread_t _owner; + + //! Count + volatile unsigned int _count; + +public: + + inline FastRecursiveLock() : _owner(0), _count(0) { + + pthread_mutex_init(&_mtx, 0); + if(pthread_cond_init(&_cond, 0) != 0) { + assert(0); + } + + } + + inline ~FastRecursiveLock() { + + pthread_mutex_destroy(&_mtx); + if(pthread_cond_destroy(&_cond) != 0) { + assert(0); + } + + } + + inline void acquire() { + + pthread_t self = pthread_self(); + pthread_mutex_lock(&_mtx); + + // If the caller does not own the lock, wait until there is no owner + if(_owner != 0 && !pthread_equal(_owner, self)) { + + int status = 0; + do { // ignore signals + status = pthread_cond_wait(&_cond, &_mtx); + } while(status == EINTR && _owner == 0); + + } + + _owner = self; + _count++; + + pthread_mutex_unlock(&_mtx); + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + pthread_t self = pthread_self(); + pthread_mutex_lock(&_mtx); + + // If the caller owns the lock, or there is no owner update the count + bool success = (_owner == 0 || pthread_equal(_owner, self)); + if(success) { + + _owner = self; + _count++; + + } + + pthread_mutex_unlock(&_mtx); + + return success; + + } + + inline void release() { + + assert(pthread_equal(_owner, pthread_self())); + + pthread_mutex_lock(&_mtx); + if(--_count == 0) { + + _owner = 0; + pthread_cond_signal(&_cond); + + } + + pthread_mutex_unlock(&_mtx); + + } + + +}; /* FastRecursiveLock */ + + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/posix/FastLock.h b/src/dep/src/zthread/posix/FastLock.h new file mode 100644 index 0000000..89907fd --- /dev/null +++ b/src/dep/src/zthread/posix/FastLock.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/Exceptions.h" +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + +/** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:28:07-0400> + * @version 2.2.8 + * + * This is the smallest and fastest synchronization object in the library. + * It is an implementation of fast mutex, an all or nothing exclusive + * lock. It should be used only where you need speed and are willing + * to sacrifice all the state & safety checking provided by the framework + * for speed. + */ +class FastLock : private NonCopyable { + + pthread_mutex_t _mtx; + + public: + + /** + * Create a new FastLock. No safety or state checks are performed. + * + * @exception Initialization_Exception - not thrown + */ + inline FastLock() { + + if(pthread_mutex_init(&_mtx, 0) != 0) + throw Initialization_Exception(); + + } + + /** + * Destroy a FastLock. No safety or state checks are performed. + */ + inline ~FastLock() { + + if(pthread_mutex_destroy(&_mtx) != 0) { + assert(0); + } + + } + + /** + * Acquire an exclusive lock. No safety or state checks are performed. + * + * @exception Synchronization_Exception - not thrown + */ + inline void acquire() { + + if(pthread_mutex_lock(&_mtx) != 0) + throw Synchronization_Exception(); + + } + + /** + * Try to acquire an exclusive lock. No safety or state checks are performed. + * This function returns immediately regardless of the value of the timeout + * + * @param timeout Unused + * @return bool + * @exception Synchronization_Exception - not thrown + */ + inline bool tryAcquire(unsigned long timeout=0) { + + return (pthread_mutex_trylock(&_mtx) == 0); + + } + + /** + * Release an exclusive lock. No safety or state checks are performed. + * The caller should have already acquired the lock, and release it + * only once. + * + * @exception Synchronization_Exception - not thrown + */ + inline void release() { + + if(pthread_mutex_unlock(&_mtx) != 0) + throw Synchronization_Exception(); + + } + + +}; /* FastLock */ + + +}; + +#endif diff --git a/src/dep/src/zthread/posix/FtimeStrategy.h b/src/dep/src/zthread/posix/FtimeStrategy.h new file mode 100644 index 0000000..3197475 --- /dev/null +++ b/src/dep/src/zthread/posix/FtimeStrategy.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIMESTRATEGY_H__ +#define __ZTTIMESTRATEGY_H__ + +#include + +#if defined(_MSC_VER) + +# include + +# define timeb _timeb +# define ftime _ftime + +#endif + +namespace ZThread { + +/** + * @class TimeStrategy + * + * Implement a strategy for time operatons based on ftime + */ +class TimeStrategy { + + struct timeb _value; + +public: + + TimeStrategy() { + ftime(&_value); + } + + inline unsigned long seconds() const { + return _value.time; + } + + inline unsigned long milliseconds() const { + return _value.millitm; + } + + unsigned long seconds(unsigned long s) { + + unsigned long z = seconds(); + _value.time = s; + + return z; + + } + + unsigned long milliseconds(unsigned long ms) { + + unsigned long z = milliseconds(); + _value.millitm = (unsigned short)ms; + + return z; + + } + +}; + +}; + +#endif // __ZTTIMESTRATEGY_H__ diff --git a/src/dep/src/zthread/posix/GetTimeOfDayStrategy.h b/src/dep/src/zthread/posix/GetTimeOfDayStrategy.h new file mode 100644 index 0000000..8588807 --- /dev/null +++ b/src/dep/src/zthread/posix/GetTimeOfDayStrategy.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIMESTRATEGY_H__ +#define __ZTTIMESTRATEGY_H__ + +#include + +namespace ZThread { + +/** + * @class TimeStrategy + * + * Implement a strategy for time operatons based on gettimeofday + */ +class TimeStrategy { + + struct timeval _value; + +public: + + TimeStrategy() { + gettimeofday(&_value, 0); + } + + inline unsigned long seconds() const { + return _value.tv_sec; + } + + inline unsigned long milliseconds() const { + return _value.tv_usec/1000; + } + + unsigned long seconds(unsigned long s) { + + unsigned long z = seconds(); + _value.tv_sec = s; + + return z; + + } + + unsigned long milliseconds(unsigned long ms) { + + unsigned long z = milliseconds(); + _value.tv_usec = ms*1000; + + return z; + + } + +}; + +}; + +#endif // __ZTTIMESTRATEGY_H__ diff --git a/src/dep/src/zthread/posix/Monitor.cxx b/src/dep/src/zthread/posix/Monitor.cxx new file mode 100644 index 0000000..bb157da --- /dev/null +++ b/src/dep/src/zthread/posix/Monitor.cxx @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Monitor.h" +#include "../Debug.h" +#include "../TimeStrategy.h" + +#include +#include +#include + +namespace ZThread { + +Monitor::Monitor() : _owner(0), _waiting(false) { + + pthread_cond_init(&_waitCond, 0); + pthread_mutex_init(&_waitLock, 0); + +} + +Monitor::~Monitor() { + + assert(!_waiting); + + pthread_cond_destroy(&_waitCond); + pthread_mutex_destroy(&_waitLock); + +} + +Monitor::STATE Monitor::wait(unsigned long ms) { + + // Update the owner on first use. The owner will not change, each + // thread waits only on a single Monitor and a Monitor is never + // shared + if(_owner == 0) + _owner = pthread_self(); + + STATE state(INVALID); + + // Serialize access to the state of the Monitor + // and test the state to determine if a wait is needed. + + pthread_mutex_lock(&_waitLock); + + if(pending(ANYTHING)) { + + // Return without waiting when possible + state = next(); + + pthread_mutex_unlock(&_waitLock); + return state; + + } + + // Unlock the external lock if a wait() is probably needed. + // Access to the state is still serial. + _lock.release(); + + // Wait for a transition in the state that is of interest, this + // allows waits to exclude certain flags (e.g. INTERRUPTED) + // for a single wait() w/o actually discarding those flags - + // they will remain set until a wait interested in those flags + // occurs. + // if(!currentState(interest)) { + + // Wait, ignoring signals + _waiting = true; + int status = 0; + + if(ms == 0) { // Wait forever + + do { // ignore signals unless the state is interesting + status = pthread_cond_wait(&_waitCond, &_waitLock); + } while(status == EINTR && !pending(ANYTHING)); + + // Akwaken only when a state is pending + assert(status == 0); + + } else { + + // Find the target time + TimeStrategy t; + + ms += t.milliseconds(); + + unsigned long s = t.seconds() + (ms / 1000); + ms %= 1000; + + // Convert to a timespec + struct ::timespec timeout; + + timeout.tv_sec = s; + timeout.tv_nsec = ms*1000000; + + // Wait ignoring signals until the state is interesting + do { + + // When a timeout occurs, update the state to reflect that. + status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout); + + } while(status == EINTR && !pending(ANYTHING)); + + // Akwaken only when a state is pending or when the timeout expired + assert(status == 0 || status == ETIMEDOUT); + + if(status == ETIMEDOUT) + push(TIMEDOUT); + + } + + // Get the next available STATE + state = next(); + _waiting = false; + + pthread_mutex_unlock(&_waitLock); + + // Reaquire the external lock, keep from deadlocking threads calling + // notify(), interrupt(), etc. + + _lock.acquire(); + + return state; + +} + + +bool Monitor::interrupt() { + + // Serialize access to the state + pthread_mutex_lock(&_waitLock); + + bool wasInterruptable = !pending(INTERRUPTED); + bool hadWaiter = _waiting; + + if(wasInterruptable) { + + // Update the state & wake the waiter if there is one + push(INTERRUPTED); + + wasInterruptable = false; + + if(hadWaiter && !masked(Monitor::INTERRUPTED)) + pthread_cond_signal(&_waitCond); + else + wasInterruptable = !pthread_equal(_owner, pthread_self()); + + } + + pthread_mutex_unlock(&_waitLock); + + // Only returns true when an interrupted thread is not currently blocked + return wasInterruptable; + +} + +bool Monitor::isInterrupted() { + + // Serialize access to the state + pthread_mutex_lock(&_waitLock); + + bool wasInterrupted = pending(INTERRUPTED); + + clear(INTERRUPTED); + + pthread_mutex_unlock(&_waitLock); + + return wasInterrupted; + +} + +bool Monitor::isCanceled() { + + // Serialize access to the state + pthread_mutex_lock(&_waitLock); + + bool wasCanceled = examine(CANCELED); + + if(pthread_equal(_owner, pthread_self())) + clear(INTERRUPTED); + + pthread_mutex_unlock(&_waitLock); + + return wasCanceled; + +} + +bool Monitor::cancel() { + + // Serialize access to the state + pthread_mutex_lock(&_waitLock); + + bool wasInterrupted = !pending(INTERRUPTED); + bool hadWaiter = _waiting; + + push(CANCELED); + + if(wasInterrupted) { + + // Update the state & wake the waiter if there is one + push(INTERRUPTED); + + if(hadWaiter && !masked(Monitor::INTERRUPTED)) + pthread_cond_signal(&_waitCond); + + } + + pthread_mutex_unlock(&_waitLock); + + return wasInterrupted; + +} + +bool Monitor::notify() { + + // Serialize access to the state + pthread_mutex_lock(&_waitLock); + + bool wasNotifyable = !pending(INTERRUPTED); + + if(wasNotifyable) { + + // Set the flag and wake the waiter if there + // is one + push(SIGNALED); + + if(_waiting) + pthread_cond_signal(&_waitCond); + + } + + pthread_mutex_unlock(&_waitLock); + + return wasNotifyable; + +} + +} // namespace ZThread + diff --git a/src/dep/src/zthread/posix/Monitor.h b/src/dep/src/zthread/posix/Monitor.h new file mode 100644 index 0000000..945c879 --- /dev/null +++ b/src/dep/src/zthread/posix/Monitor.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITOR_H__ +#define __ZTMONITOR_H__ + +#include "../Status.h" +#include "../FastLock.h" + +namespace ZThread { + +/** + * @class Monitor + * @author Eric Crahen + * @date <2003-07-18T08:16:09-0400> + * @version 2.2.8 + */ +class Monitor : public Status, private NonCopyable { + private: + + //! Serialize access to external objects + FastLock _lock; + + //! Condition variable used to block a thread. + pthread_cond_t _waitCond; + + //! Serialize access to the internal state of the monitor + pthread_mutex_t _waitLock; + + //! Owning thread + pthread_t _owner; + + //! Waiting flag, to avoid uneccessary signals + volatile bool _waiting; + + public: + + typedef Status::STATE STATE; + + //! Create a new monitor. + Monitor(); + + //! Destroy the monitor. + ~Monitor(); + + //! Acquire the lock for this monitor. + inline void acquire() { + _lock.acquire(); + } + + //! Acquire the lock for this monitor. + inline bool tryAcquire() { + return _lock.tryAcquire(); + } + + //! Release the lock for this monitor + inline void release() { + _lock.release(); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * Blocks for an indefinent amount of time. + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + inline STATE wait() { + return wait(0); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * May blocks for an indefinent amount of time. + * + * @param timeout - maximum time to block (milliseconds) or 0 to + * block indefinently + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or TIMEDOUT if the maximum wait time expired. + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + STATE wait(unsigned long timeout); + + /** + * Interrupt this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return INTERRUPTED w/o blocking. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool interrupt(); + + /** + * Notify this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return SIGNALED w/o blocking, if no other + * flag is set. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool notify(); + + /** + * Check the state of this monitor, clearing the INTERRUPTED status if set. + * + * @return bool true if the monitor was INTERRUPTED. + * @post INTERRUPTED flag cleared if the calling thread owns the monitor. + */ + bool isInterrupted(); + + /** + * Mark the Status CANCELED, and INTERRUPT the montor. + * + * @see interrupt() + */ + bool cancel(); + + /** + * Test the CANCELED Status, clearing the INTERRUPTED status if set. + * + * @return bool + */ + bool isCanceled(); + +}; + +}; + +#endif diff --git a/src/dep/src/zthread/posix/PriorityOps.h b/src/dep/src/zthread/posix/PriorityOps.h new file mode 100644 index 0000000..92da66a --- /dev/null +++ b/src/dep/src/zthread/posix/PriorityOps.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTPRIORITYOPS_H__ +#define __ZTPRIORITYOPS_H__ + +#include "zthread/Priority.h" +#include "../ThreadOps.h" + +namespace ZThread { + +/** + * @class PriorityOps + * @author Eric Crahen + * @date <2003-07-16T23:30:00-0400> + * @version 2.2.0 + * + * This class is an abstraction used to perform various operations on a + * native POSIX thread. + */ +class PriorityOps { + + +public: + + +}; + + +} // namespace ZThread + +#endif // __ZTPRIORITYOPS_H__ diff --git a/src/dep/src/zthread/posix/TSS.h b/src/dep/src/zthread/posix/TSS.h new file mode 100644 index 0000000..931ff34 --- /dev/null +++ b/src/dep/src/zthread/posix/TSS.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTSS_H__ +#define __ZTTSS_H__ + +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + + /** + * @class TSS + * @author Eric Crahen + * @date <2003-07-27T14:18:37-0400> + * @version 2.3.0 + * + * An abstraction for dealing with POSIX thread specific storage (tss). + * Provides get/set and creation/destruction. + */ + template + class TSS : private NonCopyable { + + pthread_key_t _key; + + public: + + /** + * Create a new object for accessing tss. + */ + TSS() { + + if(pthread_key_create(&_key, 0) != 0) { + assert(0); // Key creation failed + } + + } + + /** + * Destroy the underlying supoprt for accessing tss with this + * object. + */ + ~TSS() { + + pthread_key_delete(_key); + + } + + /** + * Get the value stored in tss. + * + * @return T + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + T get() const { + return reinterpret_cast(pthread_getspecific(_key)); + } + + + /** + * Store a value in tss. + * + * @param value T + * @return T old value + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + T set(T value) const { + + T oldValue = get(); + pthread_setspecific(_key, value); + + return oldValue; + + } + + }; + +} + +#endif + + diff --git a/src/dep/src/zthread/posix/ThreadOps.cxx b/src/dep/src/zthread/posix/ThreadOps.cxx new file mode 100644 index 0000000..e72ef78 --- /dev/null +++ b/src/dep/src/zthread/posix/ThreadOps.cxx @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ThreadOps.h" +#include "zthread/Guard.h" +#include "zthread/Runnable.h" +#include + +#if defined(HAVE_SCHED_YIELD) +# include +#endif + +namespace ZThread { + +const ThreadOps ThreadOps::INVALID(0); + +bool ThreadOps::join(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid != 0); + + int err = 0; + + do { + + err = pthread_join(ops->_tid, NULL); + + } while(err == EINTR); + + return err == 0; + +} + +bool ThreadOps::yield() { + + bool result = false; + +#if defined(HAVE_SCHED_YIELD) + result = sched_yield() == 0; +#endif + + return result; + +} + +bool ThreadOps::setPriority(ThreadOps* impl, Priority p) { + + assert(impl); + + bool result = true; + +#if !defined(ZTHREAD_DISABLE_PRIORITY) + + struct sched_param param; + + switch(p) { + case Low: + param.sched_priority = 0; + break; + case High: + param.sched_priority = 10; + break; + case Medium: + default: + param.sched_priority = 5; + } + + result = pthread_setschedparam(impl->_tid, SCHED_OTHER, ¶m) == 0; + +#endif + + return result; + +} + +bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) { + + assert(impl); + + bool result = true; + +#if !defined(ZTHREAD_DISABLE_PRIORITY) + + struct sched_param param; + int policy = SCHED_OTHER; + + if(result = (pthread_getschedparam(impl->_tid, &policy, ¶m) == 0)) { + + // Convert to one of the PRIORITY values + if(param.sched_priority < 10) + p = Low; + else if(param.sched_priority == 10) + p = Medium; + else + p = High; + + } + +#endif + + return result; + +} + + +bool ThreadOps::spawn(Runnable* task) { + return pthread_create(&_tid, 0, _dispatch, task) == 0; +} + + + +extern "C" void *_dispatch(void *arg) { + + Runnable* task = reinterpret_cast(arg); + assert(task); + + // Run the task from the correct context + task->run(); + + // Exit the thread + pthread_exit((void**)0); + return (void*)0; + +} + +} // namespace ZThread + + diff --git a/src/dep/src/zthread/posix/ThreadOps.h b/src/dep/src/zthread/posix/ThreadOps.h new file mode 100644 index 0000000..be754c2 --- /dev/null +++ b/src/dep/src/zthread/posix/ThreadOps.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADOPS_H__ +#define __ZTTHREADOPS_H__ + + +#include "zthread/Priority.h" +#include +#include + +namespace ZThread { + +class Runnable; + +//! Dispatch function for native pthreads required extern C +//! linkage. +extern "C" void* _dispatch(void*); + +/** + * @class ThreadOps + * @author Eric Crahen + * @date <2003-07-16T23:30:25-0400> + * @version 2.2.8 + * + * This class is an abstraction used to perform various operations on a + * native POSIX thread. + */ +class ThreadOps { + + //! Keep track of the pthreads handle for the native thread + pthread_t _tid; + + ThreadOps(pthread_t tid) : _tid(tid) { } + +public: + + const static ThreadOps INVALID; + + /** + * Create a new ThreadOps to manipulate a native thread. + */ + ThreadOps() : _tid(0) { } + + + inline bool operator==(const ThreadOps& ops) const { + return pthread_equal(_tid, ops._tid); + } + + + static ThreadOps self() { + return ThreadOps(pthread_self()); + } + + /** + * Activating an instance of ThreadOps will map it onto the currently + * executing thread. + */ + static void activate(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid == 0); + + ops->_tid = pthread_self(); + + } + + /** + * Test if this object represents the currently executing + * native thread. + * + * @return bool true if successful + */ + + static bool isCurrent(ThreadOps* ops) { + + assert(ops); + + return pthread_equal(pthread_self(), ops->_tid); + + } + + /** + * Join a native thread. + * + * @return bool true if successful + */ + static bool join(ThreadOps*); + + /** + * Force the current native thread to yield, letting the scheduler + * give the CPU time to another thread. + * + * @return bool true if successful, false if the operation can't + * be supported. + */ + static bool yield(); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param PRIORITY requested priority + * @return bool false if unsuccessful + */ + static bool setPriority(ThreadOps*, Priority); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param Thread::PRIORITY& current priority + * @return bool false if unsuccessful + */ + static bool getPriority(ThreadOps*, Priority&); + +protected: + + /** + * Spawn a native thread. + * + * @param ThreadImpl* parent thread + * @param ThreadImpl* child thread being started. + * @param Runnable* task being executed. + * + * @return bool true if successful + */ + bool spawn(Runnable*); + +}; + + +} + +#endif // __ZTTHREADOPS_H__ diff --git a/src/dep/src/zthread/solaris/FastRecursiveLock.h b/src/dep/src/zthread/solaris/FastRecursiveLock.h new file mode 100644 index 0000000..956e1db --- /dev/null +++ b/src/dep/src/zthread/solaris/FastRecursiveLock.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "zthread/NonCopyable.h" +#include + +namespace ZThread { + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:31:23-0400> + * @version 2.2.0 + * + * This FastRecursiveLock implementation uses pthreads mutex attribute + * functions to create a recursive lock. This implementation is not + * specific to solaris and will work on any system that supports + * pthread_mutexattr_settype(). + */ +class FastRecursiveLock : private NonCopyable { + + pthread_mutex_t _mtx; + + /** + * @class Attribute + * + * Utility class to maintain the attribute as long as it is needed. + */ + class Attribute { + + pthread_mutexattr_t _attr; + + public: + + Attribute() { + + if(pthread_mutexattr_init(&_attr) != 0) { + assert(0); + } + + if(pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_RECURSIVE) != 0) { + assert(0); + } + + } + + ~Attribute() { + + if(pthread_mutexattr_destroy(&_attr) != 0) { + assert(0); + } + + } + + operator pthread_mutexattr_t*() { + return &_attr; + } + + }; + +public: + + inline FastRecursiveLock() { + + static Attribute attr; + pthread_mutex_init(&_mtx, (pthread_mutexattr_t*)attr); + + } + + inline ~FastRecursiveLock() { + + pthread_mutex_destroy(&_mtx); + + } + + inline void acquire() { + + pthread_mutex_lock(&_mtx); + + } + + inline void release() { + + pthread_mutex_unlock(&_mtx); + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + return (pthread_mutex_trylock(&_mtx) == 0); + + } + +}; /* FastRecursiveLock */ + + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/vanilla/DualMutexRecursiveLock.h b/src/dep/src/zthread/vanilla/DualMutexRecursiveLock.h new file mode 100644 index 0000000..ddce7a3 --- /dev/null +++ b/src/dep/src/zthread/vanilla/DualMutexRecursiveLock.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "../FastLock.h" +#include "../ThreadOps.h" +#include + +namespace ZThread { + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:31:09-0400> + * @version 2.2.8 + * + * This is a vanilla FastRecursiveLock implementation for a + * system that doesn't provide recurisve locks. This implementation + * is based on using a pair of mutexes, because of this, it performs + * roughly the same as a spin lock would. + */ +class FastRecursiveLock : private NonCopyable { + + //! Lock for blocking + FastLock _blockingLock; + + //! Serialize state + FastLock _stateLock; + + //! Owner + ThreadOps _owner; + + //! Count + volatile unsigned int _count; + + public: + + inline FastRecursiveLock() : _owner(ThreadOps::INVALID), _count(0) { } + + inline ~FastRecursiveLock() { + + assert(_owner == ThreadOps::INVALID); + assert(_count == 0); + + } + + void acquire() { + + ThreadOps self(ThreadOps::self()); + + // Try to lock the blocking mutex first + bool wasLocked = _blockingLock.tryAcquire(); + if(!wasLocked) { + + // Otherwise, grab the lock for the state + _stateLock.acquire(); + + wasLocked = (_owner == self); + if(wasLocked) + _count++; + + _stateLock.release(); + + if(wasLocked) + return; + + // Try to be cooperative + ThreadOps::yield(); + _blockingLock.acquire(); + + } + + // Serialze access to the state + _stateLock.acquire(); + + // Take ownership + assert(_owner == ThreadOps::INVALID || _owner == self); + + _owner = self; + _count++; + + _stateLock.release(); + + } + + + bool tryAcquire(unsigned long timeout = 0) { + + ThreadOps self(ThreadOps::self()); + + // Try to lock the blocking mutex first + bool wasLocked = _blockingLock.tryAcquire(); + if(!wasLocked) { + + // Otherwise, grab the lock for the state + _stateLock.acquire(); + + wasLocked = (_owner == self); + if(wasLocked) + _count++; + + _stateLock.release(); + + return wasLocked; + + } + + // Serialze access to the state + _stateLock.acquire(); + + // Take ownership + assert(_owner == ThreadOps::INVALID || _owner == self); + + _owner = self; + _count++; + + _stateLock.release(); + + return true; + + } + + + void release() { + + // Assume that release is only used by the owning thread, as it + // should be. + assert(_count != 0); + assert(_owner == ThreadOps::self()); + + _stateLock.acquire(); + + // If the lock was owned and the count has reached 0, give up + // ownership and release the blocking lock + if(--_count == 0) { + + _owner = ThreadOps::INVALID; + _blockingLock.release(); + + } + + _stateLock.release(); + + } + + +}; /* FastRecursiveLock */ + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/vanilla/SimpleAtomicCount.cxx b/src/dep/src/zthread/vanilla/SimpleAtomicCount.cxx new file mode 100644 index 0000000..fc63d14 --- /dev/null +++ b/src/dep/src/zthread/vanilla/SimpleAtomicCount.cxx @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNTIMPL_H__ +#define __ZTATOMICCOUNTIMPL_H__ + +#include "zthread/Guard.h" +#include "../FastLock.h" + +#include + +namespace ZThread { + +typedef struct atomic_count_t { + + FastLock lock; + unsigned long count; + + atomic_count_t() : count(0) {} + +} ATOMIC_COUNT; + +AtomicCount::AtomicCount() { + + ATOMIC_COUNT* c = new ATOMIC_COUNT; + _value = reinterpret_cast(c); + +} + +AtomicCount::~AtomicCount() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + assert(c->count == 0); + + delete c; + +} + +//! Postfix decrement and return the current value +size_t AtomicCount::operator--(int) { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + + Guard g(c->lock); + return c->count--; + +} + +//! Postfix increment and return the current value +size_t AtomicCount::operator++(int) { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + + Guard g(c->lock); + return c->count++; + +} + +//! Prefix decrement and return the current value +size_t AtomicCount::operator--() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + + Guard g(c->lock); + return --c->count; + +} + +//! Prefix increment and return the current value +size_t AtomicCount::operator++() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + + Guard g(c->lock); + return ++c->count; + +} + +}; + +#endif // __ZTATOMICCOUNTIMPL_H__ diff --git a/src/dep/src/zthread/vanilla/SimpleRecursiveLock.h b/src/dep/src/zthread/vanilla/SimpleRecursiveLock.h new file mode 100644 index 0000000..f4f3092 --- /dev/null +++ b/src/dep/src/zthread/vanilla/SimpleRecursiveLock.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "../FastLock.h" +#include "../ThreadOps.h" +#include + +namespace ZThread { + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:30:59-0400> + * @version 2.2.8 + * + * This implementation of a FastRecursiveLock uses the which ever FastLock + * that is selected to create a recursive spin lock. + */ +class FastRecursiveLock : private NonCopyable { + + FastLock _lock; + + ThreadOps _owner; + + volatile unsigned int _count; + +public: + + inline FastRecursiveLock() : _owner(ThreadOps::INVALID), _count(0) {} + + inline ~FastRecursiveLock() { + + assert(_owner == ThreadOps::INVALID); + assert(_count == 0); + + } + + inline void acquire() { + + ThreadOps self(ThreadOps::self()); + bool wasLocked = false; + + do { + + _lock.acquire(); + + // If there is no owner, or the owner is the caller + // update the count + if(_owner == ThreadOps::INVALID || _owner == self) { + + _owner = self; + _count++; + + wasLocked = true; + + } + + _lock.release(); + + } while(!wasLocked); + + assert(_owner == ThreadOps::self()); + + } + + inline void release() { + + assert(_owner == ThreadOps::self()); + + _lock.acquire(); + + if(--_count == 0) + _owner = ThreadOps::INVALID; + + _lock.release(); + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + ThreadOps self(ThreadOps::self()); + bool wasLocked = false; + + _lock.acquire(); + + if(_owner == ThreadOps::INVALID || _owner == self) { + + _owner = self; + _count++; + + wasLocked = true; + + } + + _lock.release(); + + assert(!wasLocked || _owner == ThreadOps::self()); + return wasLocked; + + } + +}; /* FastRecursiveLock */ + + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/win32/AtomicCount.cxx b/src/dep/src/zthread/win32/AtomicCount.cxx new file mode 100644 index 0000000..84cbf8c --- /dev/null +++ b/src/dep/src/zthread/win32/AtomicCount.cxx @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNTIMPL_H__ +#define __ZTATOMICCOUNTIMPL_H__ + +#include +#include + +namespace ZThread { + + +AtomicCount::AtomicCount() { + + _value = reinterpret_cast(new LONG(0)); + +} + +AtomicCount::~AtomicCount() { + + assert(*reinterpret_cast(_value) == 0); + delete reinterpret_cast(_value); + +} + +void AtomicCount::increment() { + + ::InterlockedIncrement(reinterpret_cast(_value)); + +} + +bool AtomicCount::decrement() { + + LONG v = ::InterlockedDecrement(reinterpret_cast(_value)); + return static_cast(v) == 0; + +} + +}; + +#endif // __ZTATOMICCOUNTIMPL_H__ diff --git a/src/dep/src/zthread/win32/AtomicFastLock.h b/src/dep/src/zthread/win32/AtomicFastLock.h new file mode 100644 index 0000000..a714c03 --- /dev/null +++ b/src/dep/src/zthread/win32/AtomicFastLock.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + + +/** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:32:20-0400> + * @version 2.1.6 + * + * This is the smallest and fastest synchronization object in the library. + * It is an implementation of fast mutex, an all or nothing exclusive + * lock. It should be used only where you need speed and are willing + * to sacrifice all the state & safety checking provided by the framework + * for speed. + * + * The current Platform SDK defines: + * + * LONG InterlockedExchange(LPLONG, LONG) + * LONG InterlockedCompareExchange(LPLONG, LONG, LONG, LONG) + * + * If your compiler complains about LPLONG not being implicitly casted to + * a PVOID, then you should get the SDK update from microsoft or use the + * WIN9X implementation of this class. + * + * ---- + * Because Windows 95 and earlier can run on processors prior to the 486, they + * don't all support the CMPXCHG function, and so Windows 95 an earlier dont support + * InterlockedCompareExchange. For this, you should use the win9x implementation + * of this class + */ +class FastLock : private NonCopyable { + +#pragma pack(push, 8) + LONG volatile _lock; +#pragma pack(pop) + + public: + + /** + * Create a new FastLock + */ + inline FastLock() : _lock(0) { } + + + /** + * Destroy FastLock + */ + inline ~FastLock() { assert(_lock == 0); } + + /** + * Lock the fast Lock, no error check. + * + * @exception None + */ + inline void acquire() { + + while (::InterlockedCompareExchange(const_cast(&_lock), 1, 0) != 0) + ::Sleep(0); + + } + + + /** + * Release the fast Lock, no error check. + * + * @exception None + */ + inline void release() { + + ::InterlockedExchange(const_cast(&_lock), (LONG)0); + + } + + /** + * Try to acquire an exclusive lock. No safety or state checks are performed. + * This function returns immediately regardless of the value of the timeout + * + * @param timeout Unused + * @return bool + * @exception Synchronization_Exception - not thrown + */ + inline bool tryAcquire(unsigned long timeout=0) { + + return ::InterlockedCompareExchange(const_cast(&_lock), 1, 0) == 0; + + } + +}; /* FastLock */ + + +}; +#endif diff --git a/src/dep/src/zthread/win32/AtomicFastRecursiveLock.h b/src/dep/src/zthread/win32/AtomicFastRecursiveLock.h new file mode 100644 index 0000000..c6a61b0 --- /dev/null +++ b/src/dep/src/zthread/win32/AtomicFastRecursiveLock.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:32:34-0400> + * @version 2.1.6 + * + * This is the smaller and faster implementation of a RecursiveLock. + * A single thread can acquire the mutex any number of times, but it + * must perform a release for each acquire(). Other threads are blocked + * until a thread has released all of its locks on the mutex. + * + * This particular implementation performs fewer safety checks. Like + * the FastLock implementation, any waiting caused by an acquire() request + * is not interruptable. This is so that the mutex can have the fastest + * response time for a time critical application while still having a good + * degree of reliability. + * + * TryEnterCriticalSection() does not work at all on some systems, so its + * not used. + * + * + * The current Platform SDK defines: + * + * LONG InterlockedExchange(LPLONG, LONG) + * LONG InterlockedCompareExchange(LPLONG, LONG, LONG, LONG) + * + * If your compiler complains about LPLONG not being implicitly casted to + * a PVOID, then you should get the SDK update from microsoft or use the + * WIN9X implementation of this class. + * + * ---- + * Because Windows 95 and earlier can run on processors prior to the 486, they + * don't all support the CMPXCHG function, and so Windows 95 an earlier dont support + * InterlockedCompareExchange. If you define ZT_WIN9X, you'll get a version of the + * FastLock that uses the XCHG instruction + */ +class FastRecursiveLock : private NonCopyable { + +// Add def for mingw32 or other non-ms compiler to align on 64-bit +// boundary +#pragma pack(push, 8) + LONG volatile _lock; +#pragma pack(pop) + LONG _count; + + public: + + /** + * Create a new FastRecursiveLock + */ + inline FastRecursiveLock() : _lock(0), _count(0) { } + + + /** + * Destroy FastLock + */ + inline ~FastRecursiveLock() { + assert(_lock == 0); + } + + /** + * Lock the fast Lock, no error check. + * + * @exception None + */ + inline void acquire() { + + DWORD id = ::GetCurrentThreadId(); + + // Take ownership if the lock is free or owned by the calling thread + do { + + DWORD owner = (DWORD)::InterlockedCompareExchange(const_cast(&_lock), id, 0); + if(owner == 0 || owner == id) + break; + + ::Sleep(0); + + } while(1); + + _count++; + + } + + + /** + * Release the fast Lock, no error check. + * + * @exception None + */ + inline void release() { + + if(--_count == 0) + ::InterlockedExchange(const_cast(&_lock), 0); + + } + + /** + * Try to acquire an exclusive lock. No safety or state checks are performed. + * This function returns immediately regardless of the value of the timeout + * + * @param timeout Unused + * @return bool + * @exception Synchronization_Exception - not thrown + */ + inline bool tryAcquire(unsigned long timeout=0) { + + DWORD id = ::GetCurrentThreadId(); + DWORD owner = (DWORD)::InterlockedCompareExchange(const_cast(&_lock), id, 0); + + if(owner == 0 || owner == id) { + _count++; + return true; + } + + return false; + + } + + +}; /* FastRecursiveLock */ + + +}; +#endif diff --git a/src/dep/src/zthread/win32/FastLock.h b/src/dep/src/zthread/win32/FastLock.h new file mode 100644 index 0000000..2e9fe82 --- /dev/null +++ b/src/dep/src/zthread/win32/FastLock.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/Exceptions.h" +#include "zthread/NonCopyable.h" +#include "../ThreadOps.h" +#include +#include + +namespace ZThread { + + /** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:32:44-0400> + * @version 2.2.11 + * + * This FastLock implementation is based on a Win32 Mutex + * object. This will perform better under high contention, + * but will not be as fast as the spin lock under reasonable + * circumstances. + */ + class FastLock : private NonCopyable { + + HANDLE _hMutex; +#ifndef NDEBUG + volatile bool _locked; +#endif + + public: + + /** + * Create a new FastLock + */ + FastLock() { + +#ifndef NDEBUG + _locked = false; +#endif + + _hMutex = ::CreateMutex(0, 0, 0); + assert(_hMutex != NULL); + if(_hMutex == NULL) + throw Initialization_Exception(); + + } + + + ~FastLock() { + ::CloseHandle(_hMutex); + } + + void acquire() { + + if(::WaitForSingleObject(_hMutex, INFINITE) != WAIT_OBJECT_0) { + assert(0); + throw Synchronization_Exception(); + } + +#ifndef NDEBUG + + // Simulate deadlock to provide consistent behavior. This + // will help avoid errors when porting. Avoiding situations + // where a FastMutex mistakenly behaves as a recursive lock. + + while(_locked) + ThreadOps::yield(); + + _locked = true; + +#endif + + } + + void release() { + +#ifndef NDEBUG + _locked = false; +#endif + + if(::ReleaseMutex(_hMutex) == 0) { + assert(0); + throw Synchronization_Exception(); + } + + } + + + bool tryAcquire(unsigned long timeout = 0) { + + switch(::WaitForSingleObject(_hMutex, timeout)) { + case WAIT_OBJECT_0: + +#ifndef NDEBUG + + // Simulate deadlock to provide consistent behavior. This + // will help avoid errors when porting. Avoiding situations + // where a FastMutex mistakenly behaves as a recursive lock. + + while(_locked) + ThreadOps::yield(); + + _locked = true; + +#endif + + return true; + case WAIT_TIMEOUT: + return false; + default: + break; + } + + assert(0); + throw Synchronization_Exception(); + + } + + }; + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/win32/FastRecursiveLock.h b/src/dep/src/zthread/win32/FastRecursiveLock.h new file mode 100644 index 0000000..e1a6e7c --- /dev/null +++ b/src/dep/src/zthread/win32/FastRecursiveLock.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTRECURSIVELOCK_H__ +#define __ZTFASTRECURSIVELOCK_H__ + +#include "zthread/Exceptions.h" +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + + +/** + * @class FastRecursiveLock + * + * @author Eric Crahen + * @date <2003-07-16T23:32:56-0400> + * @version 2.2.11 + * + * This FastRecursiveLock implementation is based on a Win32 Mutex + * object. This will perform better under high contention, + * but will not be as fast as the spin lock under reasonable + * circumstances. + */ +class FastRecursiveLock : private NonCopyable { + + HANDLE _hMutex; + volatile unsigned int _count; + + public: + + /** + * Create a new FastRecursiveLock + */ + FastRecursiveLock() : _count(0) { + + _hMutex = ::CreateMutex(0, 0, 0); + assert(_hMutex != NULL); + if(_hMutex == NULL) + throw Initialization_Exception(); + + } + + + ~FastRecursiveLock() { + ::CloseHandle(_hMutex); + } + + + void acquire() { + + if(::WaitForSingleObject(_hMutex, INFINITE) != WAIT_OBJECT_0) { + assert(0); + throw Synchronization_Exception(); + } + + } + + void release() { + + if(::ReleaseMutex(_hMutex) == 0) { + assert(0); + throw Synchronization_Exception(); + } + + } + + bool tryAcquire(unsigned long) { + + switch(::WaitForSingleObject(_hMutex, 0)) { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + return false; + default: + break; + } + + assert(0); + throw Synchronization_Exception(); + + } + +}; /* FastRecursiveLock */ + +} // namespace ZThread + +#endif diff --git a/src/dep/src/zthread/win32/Monitor.cxx b/src/dep/src/zthread/win32/Monitor.cxx new file mode 100644 index 0000000..6e69487 --- /dev/null +++ b/src/dep/src/zthread/win32/Monitor.cxx @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "Monitor.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +using namespace ZThread; + +Monitor::Monitor() : _owner(0), _waiting(false) { + + _handle = ::CreateEvent(0, TRUE, FALSE, 0); + if(_handle == NULL) { + assert(0); + } + +} + +Monitor::~Monitor() { + + assert(!_waiting); + + ::CloseHandle(_handle); + +} + +Monitor::STATE Monitor::wait(unsigned long ms) { + + // Update the owner on first use. The owner will not change, each + // thread waits only on a single Monitor and a Monitor is never + // shared + if(_owner == 0) + _owner = ::GetCurrentThreadId(); + + STATE state; //(INVALID); + + // Serialize access to the state of the Monitor + // and test the state to determine if a wait is needed. + _waitLock.acquire(); + + if(pending(ANYTHING)) { + + // Return without waiting when possible + state = next(); + + _waitLock.release(); + return state; + + } + // Unlock the external lock if a wait() is probably needed. + // Access to the state is still serial. + _lock.release(); + + // Wait for a transition in the state that is of interest, this + // allows waits to exclude certain flags (e.g. INTERRUPTED) + // for a single wait() w/o actually discarding those flags - + // they will remain set until a wait interested in those flags + // occurs. + // if(!currentState(interest)) { + + // Wait, ignoring signals + _waiting = true; + + // Block until the event is set. + _waitLock.release(); + + // The event is manual reset so this lack of atmoicity will not + // be an issue + + DWORD dwResult = + ::WaitForSingleObject(_handle, ((ms == 0) ? INFINITE : (DWORD)ms)); + + // Reacquire serialized access to the state + _waitLock.acquire(); + + // Awaken only when the event is set or the timeout expired + assert(dwResult == WAIT_OBJECT_0 || dwResult == WAIT_TIMEOUT); + + if(dwResult == WAIT_TIMEOUT) + push(TIMEDOUT); + + // Get the next available STATE + state = next(); + _waiting = false; + + ::ResetEvent(_handle); + + // Acquire the internal lock & release the external lock + _waitLock.release(); + + // Reaquire the external lock, keep from deadlocking threads calling + // notify(), interrupt(), etc. + _lock.acquire(); + + return state; + +} + + +bool Monitor::interrupt() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterruptable = !pending(INTERRUPTED); + bool hadWaiter = _waiting; + + if(wasInterruptable) { + + // Update the state & wake the waiter if there is one + push(INTERRUPTED); + + wasInterruptable = false; + + if(hadWaiter && !masked(Monitor::INTERRUPTED)) { + + // Blocked on a synchronization object + if(::SetEvent(_handle) == FALSE) { + assert(0); + } + + } else + wasInterruptable = !(_owner == ::GetCurrentThreadId()); + + } + + _waitLock.release(); + + // Only returns true when an interrupted thread is not currently blocked + return wasInterruptable; + +} + +bool Monitor::isInterrupted() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterrupted = pending(INTERRUPTED); + clear(INTERRUPTED); + + _waitLock.release(); + + return wasInterrupted; + +} + + +bool Monitor::notify() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasNotifyable = !pending(INTERRUPTED); + + if(wasNotifyable) { + + // Set the flag and wake the waiter if there + // is one + push(SIGNALED); + + // If there is a waiter then send the signal. + if(_waiting) + if(::SetEvent(_handle) == FALSE) { + assert(0); + } + + } + + _waitLock.release(); + + return wasNotifyable; + +} + + +bool Monitor::cancel() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasInterrupted = !pending(INTERRUPTED); + bool hadWaiter = _waiting; + + push(CANCELED); + + if(wasInterrupted) { + + // Update the state & wake the waiter if there is one + push(INTERRUPTED); + + // If there is a waiter then send the signal. + if(hadWaiter && !masked(Monitor::INTERRUPTED)) + if(::SetEvent(_handle) == FALSE) { + assert(0); + } + + } + + _waitLock.release(); + + return wasInterrupted; + +} + +bool Monitor::isCanceled() { + + // Serialize access to the state + _waitLock.acquire(); + + bool wasCanceled = examine(CANCELED); + + if(_owner == ::GetCurrentThreadId()) + clear(INTERRUPTED); + + _waitLock.release(); + + return wasCanceled; + +} + diff --git a/src/dep/src/zthread/win32/Monitor.h b/src/dep/src/zthread/win32/Monitor.h new file mode 100644 index 0000000..d25fdd8 --- /dev/null +++ b/src/dep/src/zthread/win32/Monitor.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTMONITOR_H__ +#define __ZTMONITOR_H__ + +#include "../Status.h" +#include "../FastLock.h" + +namespace ZThread { + +/** + * @class Monitor + * @author Eric Crahen + * @date <2003-07-16T23:33:10-0400> + * @version 2.2.11 + */ +class Monitor : public Status, private NonCopyable { + + //! Serialize access to external objects + FastLock _lock; + + //! Event used to block thread + HANDLE _handle; + + //! Serialize access to the internal state of the monitor + FastLock _waitLock; + + //! Owning thread + DWORD _owner; + + //! Waiting flag, to avoid uneccessary signals + volatile bool _waiting; + + //! State of the monitor + volatile int _state; + + public: + + //! Create a new monitor. + Monitor(); + + //! Destroy the monitor. + ~Monitor(); + + //! Acquire the external lock for this monitor. + inline void acquire() { + _lock.acquire(); + } + + //! Try to acquire the external lock for this monitor. + inline bool tryAcquire() { + return _lock.tryAcquire(); + } + + //! Release the external lock for this monitor. + inline void release() { + _lock.release(); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * Blocks for an indefinent amount of time. + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + inline STATE wait() { + return wait(0); + } + + /** + * Wait for a state change and atomically unlock the external lock. + * May blocks for an indefinent amount of time. + * + * @param timeout - maximum time to block (milliseconds) or 0 to + * block indefinently + * + * @return INTERRUPTED if the wait was ended by a interrupt() + * or TIMEDOUT if the maximum wait time expired. + * or SIGNALED if the wait was ended by a notify() + * + * @post the external lock is always acquired before this function returns + */ + STATE wait(unsigned long timeout); + + /** + * Interrupt this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return INTERRUPTED w/o blocking. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool interrupt(); + + /** + * Notify this monitor. If there is a thread blocked on this monitor object + * it will be signaled and released. If there is no waiter, a flag is set and + * the next attempt to wait() will return SIGNALED w/o blocking, if no other + * flag is set. + * + * @return false if the thread was previously INTERRUPTED. + */ + bool notify(); + + /** + * Check the state of this monitor, clearing the INTERRUPTED status if set. + * + * @return bool true if the monitor was INTERRUPTED. + * @post INTERRUPTED flag cleared if the calling thread owns the monitor. + */ + bool isInterrupted(); + + /** + * Mark the Status CANCELED, and INTERRUPT the montor. + * + * @see interrupt() + */ + bool cancel(); + + /** + * Test the CANCELED Status, clearing the INTERRUPTED status if set. + * + * @return bool + */ + bool isCanceled(); + +}; + +}; + +#endif diff --git a/src/dep/src/zthread/win32/PerformanceCounterStrategy.h b/src/dep/src/zthread/win32/PerformanceCounterStrategy.h new file mode 100644 index 0000000..95b5268 --- /dev/null +++ b/src/dep/src/zthread/win32/PerformanceCounterStrategy.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTIMESTRATEGY_H__ +#define __ZTTIMESTRATEGY_H__ + +#include +#include + +namespace ZThread { + +/** + * @class PerformanceCounterStrategy + * + * Implement a strategy for time operatons based on + * Windows QueryPerformanceXXX() functions. + * This only (erroneously) considers the lower 32 bits. + */ +class TimeStrategy { + + unsigned long _secs; + unsigned long _millis; + +public: + + TimeStrategy() { + + // Keep track of the relative time the program started + static LARGE_INTEGER i; + static BOOL valid(::QueryPerformanceCounter(&i)); + + assert(valid == TRUE); + + LARGE_INTEGER j; + ::QueryPerformanceCounter(&j); + + j.LowPart -= i.LowPart; + j.LowPart /= frequency(); + + // Mask off the high bits + _millis = (unsigned long)j.LowPart / 1000; + _secs = (unsigned long)j.LowPart - _millis; + + } + + unsigned long seconds() const { + return _secs; + } + + unsigned long milliseconds() const { + return _millis; + } + + unsigned long seconds(unsigned long s) { + + unsigned long z = seconds(); + + _secs = s; + return z; + + } + + unsigned long milliseconds(unsigned long ms) { + + unsigned long z = milliseconds(); + + _millis = ms; + return z; + + } + +private: + + // Get the frequency + static DWORD frequency() { + + static LARGE_INTEGER i; + static BOOL valid(::QueryPerformanceFrequency(&i)); + + assert(valid == TRUE); + return i.LowPart; + + } + +}; + +}; + +#endif // __ZTTIMESTRATEGY_H__ diff --git a/src/dep/src/zthread/win32/TSS.h b/src/dep/src/zthread/win32/TSS.h new file mode 100644 index 0000000..2400830 --- /dev/null +++ b/src/dep/src/zthread/win32/TSS.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTSS_H__ +#define __ZTTSS_H__ + +#include + +namespace ZThread { + + /** + * @class TSS + * @author Eric Crahen + * @date <2003-07-27T14:18:43-0400> + * @version 2.3.0 + * + * An abstraction for dealing with WIN32 thread specific storage (tss). + * Provides get/set and creation/destruction. + */ + template + class TSS { + + DWORD _key; + bool _valid; + + public: + + /** + * Create a new object for accessing tss. The def + */ + TSS() { + + _key = ::TlsAlloc(); + _valid = (_key != 0xFFFFFFFF); + + } + + /** + * Destroy the underlying supoprt for accessing tss with this + * object. + */ + virtual ~TSS() { + + if(_valid) + ::TlsFree(_key); + + } + + /** + * Get the value stored in tss. + * + * @return T + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + inline T get() const { + + if(!_valid) + throw InvalidOp_Exception(); + + return static_cast(::TlsGetValue(_key)); + + } + + /** + * Store a value in tss. + * + * @param value T + * @return T old value + * + * @exception InvalidOp_exception thrown when the tss is not properly initialized + */ + inline T set(T value) const { + + T oldValue = get(); + ::TlsSetValue(_key, value); + + return oldValue; + + } + + + }; + +} + +#endif + + diff --git a/src/dep/src/zthread/win32/ThreadOps.cxx b/src/dep/src/zthread/win32/ThreadOps.cxx new file mode 100644 index 0000000..6e8fb8d --- /dev/null +++ b/src/dep/src/zthread/win32/ThreadOps.cxx @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ThreadOps.h" +#include "zthread/Runnable.h" +#include + +namespace ZThread { + +const ThreadOps ThreadOps::INVALID(0); + +/** + * Detect OS at runtime and attempt to locate the SwitchToThread + * function, which will assist in making the spin lock implementation + * which use ThreadOps::yield() a bit fairer. + */ +class YieldOps { + + typedef BOOL (*Yield)(void); + Yield _fnYield; + +public: + + YieldOps() : _fnYield(NULL) { + + OSVERSIONINFO v; + v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if(::GetVersionEx(&v) && (v.dwPlatformId == VER_PLATFORM_WIN32_NT)) { + + // Uses GetModuleHandle() so the reference count on the dll is + // not affected. There is a warning about race conditions involving + // this function being called as FreeLibrary() completes; however + // nearly all win32 applications load this particular and will keep it + // in memory until the process exits. + HINSTANCE hInst = ::GetModuleHandle("Kernel32.dll"); + if(hInst != NULL) + _fnYield = (Yield)::GetProcAddress(hInst, "SwitchToThread"); + + // REMIND: possibly need to use _T() macro for these strings + } + + } + + bool operator()() { + + // Attempt to yield using the best function available + if(!_fnYield || !_fnYield()) + ::Sleep(0); + + return true; + + } + +}; + +bool ThreadOps::join(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid != 0); + assert(ops->_hThread != NULL); + + if(::WaitForSingleObjectEx(ops->_hThread, INFINITE, FALSE) != WAIT_OBJECT_0) + return false; + + ::CloseHandle(ops->_hThread); + ops->_hThread = NULL; + + return true; + +} + +bool ThreadOps::yield() { + + static YieldOps yielder; + + yielder(); + + return true; + +} + +bool ThreadOps::setPriority(ThreadOps* impl, Priority p) { + + assert(impl); + +#if !defined(ZTHREAD_DISABLE_PRIORITY) + + bool result; + + // Convert + int n; + switch(p) { + case Low: + n = THREAD_PRIORITY_BELOW_NORMAL; + break; + case High: + n = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case Medium: + default: + n = THREAD_PRIORITY_NORMAL; + } + + + result = (::SetThreadPriority(impl->_hThread, n) != THREAD_PRIORITY_ERROR_RETURN); + return result; + +#else + + return true; + +#endif + +} + +bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) { + + assert(impl); + bool result = true; + +#if !defined(ZTHREAD_DISABLE_PRIORITY) + + // Convert to one of the PRIORITY values + switch(::GetThreadPriority(impl->_hThread)) { + case THREAD_PRIORITY_ERROR_RETURN: + result = false; + case THREAD_PRIORITY_BELOW_NORMAL: + p = Low; + break; + case THREAD_PRIORITY_ABOVE_NORMAL: + p = High; + break; + case THREAD_PRIORITY_NORMAL: + default: + p = Medium; + } + +#endif + + return result; + +} + + +bool ThreadOps::spawn(Runnable* task) { + +// Start the thread. +#if defined(HAVE_BEGINTHREADEX) + _hThread = (HANDLE)::_beginthreadex(0, 0, &_dispatch, task, 0, (unsigned int*)&_tid); +#else + _hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&_dispatch, task, 0, (DWORD*)&_tid); +#endif + + return _hThread != NULL; + +} + +unsigned int __stdcall ThreadOps::_dispatch(void *arg) { + + Runnable* task = reinterpret_cast(arg); + assert(task); + + // Run the task from the correct context + task->run(); + + // Exit the thread +#if defined(HAVE_BEGINTHREADEX) + ::_endthreadex(0); +#else + ExitThread(0); +#endif + + return 0; + +} + +} diff --git a/src/dep/src/zthread/win32/ThreadOps.h b/src/dep/src/zthread/win32/ThreadOps.h new file mode 100644 index 0000000..4a3eeac --- /dev/null +++ b/src/dep/src/zthread/win32/ThreadOps.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTTHREADOPS_H__ +#define __ZTTHREADOPS_H__ + +#include "zthread/Priority.h" +#include +#include + +namespace ZThread { + +class Runnable; + +/** + * @class ThreadOps + * @author Eric Crahen + * @date <2003-07-16T23:33:59-0400> + * @version 2.2.8 + * + * This class is an abstraction used to perform various operations on a + * native WIN32 thread. + */ +class ThreadOps { + + //! Dispatch function for native thread + static unsigned int __stdcall _dispatch(void*); + + //! TID while the thread is executing. + HANDLE _hThread; + DWORD _tid; + + ThreadOps(DWORD tid) : _tid(tid) { } + + public: + + const static ThreadOps INVALID; + + /** + * Create a new ThreadOps to represent a native thread. + */ + ThreadOps() : _tid(0), _hThread(NULL) {} + + + inline bool operator==(const ThreadOps& ops) const { + return _tid == ops._tid; + } + + + static ThreadOps self() { + return ThreadOps(::GetCurrentThreadId()); + } + + /** + * Update the native tid for this thread so it matches the current + * thread. + */ + static void activate(ThreadOps* ops) { + + assert(ops); + assert(ops->_tid == 0); + + ops->_tid = ::GetCurrentThreadId(); + + } + + /** + * Test if this object representative of the currently executing + * native thread. + * + * @return bool true if successful + */ + static bool isCurrent(ThreadOps* ops) { + + assert(ops); + + return ops->_tid == ::GetCurrentThreadId(); + + } + + /** + * Join a native thread. + * + * @return bool true if successful + */ + static bool join(ThreadOps*); + + /** + * Force the current native thread to yield, letting the scheduler + * give the CPU time to another thread. + * + * @return bool true if successful + */ + static bool yield(); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param PRIORITY requested priority + * @return bool false if unsuccessful + */ + static bool setPriority(ThreadOps*, Priority); + + /** + * Set the priority for the native thread if supported by the + * system. + * + * @param Thread::PRIORITY& current priority + * @return bool false if unsuccessful + */ + static bool getPriority(ThreadOps*, Priority&); + +protected: + + /** + * Spawn a native thread. + * + * @param ThreadImpl* parent thread + * @param ThreadImpl* child thread being started. + * @param Runnable* task being executed. + * + * @return bool true if successful + */ + bool spawn(Runnable*); + + +}; + + +} + +#endif diff --git a/src/dep/src/zthread/win9x/AtomicCount.cxx b/src/dep/src/zthread/win9x/AtomicCount.cxx new file mode 100644 index 0000000..2bf07dc --- /dev/null +++ b/src/dep/src/zthread/win9x/AtomicCount.cxx @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTATOMICCOUNTIMPL_H__ +#define __ZTATOMICCOUNTIMPL_H__ + +#include +#include + +namespace ZThread { + +typedef struct atomic_count_t { + + CRITICAL_SECTION cs; + size_t count; + + atomic_count_t() : count(0) {} + +} ATOMIC_COUNT; + +AtomicCount::AtomicCount() { + + ATOMIC_COUNT* c = new ATOMIC_COUNT; + _value = reinterpret_cast(c); + ::InitializeCriticalSection(&c->cs); + +} + +AtomicCount::~AtomicCount() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + assert(c->count == 0); + ::DeleteCriticalSection(&c->cs); + delete c; + +} + +//! Postfix decrement and return the current value +size_t AtomicCount::operator--(int) { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + size_t value; + + ::EnterCriticalSection(&c->cs); + value = c->count--; + ::LeaveCriticalSection(&c->cs); + + return value; + +} + +//! Postfix increment and return the current value +size_t AtomicCount::operator++(int) { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + size_t value; + + ::EnterCriticalSection(&c->cs); + value = c->count++; + ::LeaveCriticalSection(&c->cs); + + return value; + +} + +//! Prefix decrement and return the current value +size_t AtomicCount::operator--() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + size_t value; + + ::EnterCriticalSection(&c->cs); + value = --c->count; + ::LeaveCriticalSection(&c->cs); + + return value; + +} + +//! Prefix increment and return the current value +size_t AtomicCount::operator++() { + + ATOMIC_COUNT* c = reinterpret_cast(_value); + size_t value; + + ::EnterCriticalSection(&c->cs); + value = ++c->count; + ::LeaveCriticalSection(&c->cs); + + return value; + +} + +}; + +#endif // __ZTATOMICCOUNTIMPL_H__ diff --git a/src/dep/src/zthread/win9x/AtomicFastLock.h b/src/dep/src/zthread/win9x/AtomicFastLock.h new file mode 100644 index 0000000..5b50a9c --- /dev/null +++ b/src/dep/src/zthread/win9x/AtomicFastLock.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2005, Eric Crahen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ZTFASTLOCK_H__ +#define __ZTFASTLOCK_H__ + +#include "zthread/NonCopyable.h" +#include +#include + +namespace ZThread { + + +/** + * @class FastLock + * + * @author Eric Crahen + * @date <2003-07-16T23:31:51-0400> + * @version 2.2.0 + * + * This uses a custom spin lock based on the older swap & compare approach + * using the XCHG instruction. You should only use this is you *absolutely* need + * to use an older system, like Windows 95. If you can, use the Win32 version. + * + * Because Windows 95 and earlier can run on processors prior to the 486, they + * don't all support the CMPXCHG function, and so Windows 95 an earlier dont support + * InterlockedCompareExchange. + * + * This is asm inlined for microsoft visual c, it needs to be changed in order to + * compile with gcc, or another win32 compiler - but more likely than not you'll + * be using the Win32 version on those compilers and this won't be a problem. + */ +class FastLock : private NonCopyable { + +// Add def for mingw32 or other non-ms compiler to align on 32-bit boundary +#pragma pack(push, 4) + unsigned char volatile _lock; +#pragma pack(pop) + + public: + + /** + * Create a new FastLock + */ + inline FastLock() : _lock(0) { } + + + inline ~FastLock() { + assert(_lock == 0); + } + + inline void acquire() { + + DWORD dw = (DWORD)&_lock; + + _asm { // swap & compare + spin_lock: + + mov al, 1 + mov esi, dw + xchg [esi], al + and al,al + jz spin_locked + } + + ::Sleep(0); + + _asm { + jmp spin_lock + spin_locked: + } + + } + + inline void release() { + + DWORD dw = (DWORD)&_lock; + + _asm { + mov al, 0 + mov esi, dw + xchg [esi], al + } + + + } + + inline bool tryAcquire(unsigned long timeout=0) { + + volatile DWORD dw = (DWORD)&_lock; + volatile DWORD result; + + _asm { + + mov al, 1 + mov esi, dw + xchg [esi], al + and al,al + mov esi, result + xchg [esi], al + } + + return result == 0; + + } + +}; /* Fast Lock */ + +} // namespace ZThread + +#endif diff --git a/src/shared.vcproj b/src/shared.vcproj new file mode 100644 index 0000000..af6f1ec --- /dev/null +++ b/src/shared.vcproj @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/shared/DebugStuff.h b/src/shared/DebugStuff.h new file mode 100644 index 0000000..9d2f17a --- /dev/null +++ b/src/shared/DebugStuff.h @@ -0,0 +1,19 @@ +#ifndef _DEBUGSTUFF_H +#define _DEBUGSTUFF_H + + +#ifdef _DEBUG + #define DEB(code) code; + #define DEBUG_APPENDIX " - DEBUG" + #define CODEDEB(code) fprintf(stderr,"[[ %s ]]\n",#code); code; +#else + #define DEB(code) + #define DEBUG_APPENDIX + #define CODEDEB(code) code; +#endif + +#define ASSERT( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i ASSERTION FAILED:\n %s\n", __FILE__, __LINE__, #assertion ); throw "Assertion Failed"; + + + +#endif \ No newline at end of file diff --git a/src/shared/Network/Base64.cpp b/src/shared/Network/Base64.cpp new file mode 100644 index 0000000..fc17d66 --- /dev/null +++ b/src/shared/Network/Base64.cpp @@ -0,0 +1,256 @@ +/** + ** File ......... Base64.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 "Base64.h" + +char const *Base64::bstr = +"ABCDEFGHIJKLMNOPQ" +"RSTUVWXYZabcdefgh" +"ijklmnopqrstuvwxy" +"z0123456789+/"; + +char const Base64::rstr[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 +}; + +Base64::Base64() +{ +// for (int i = 0; i < 64; i++) +// rstr[(int)bstr[i]] = i; +} + + +void Base64::encode(FILE *fil, std::string& output, bool add_crlf) +{ + size_t remain; + size_t i = 0; + size_t o = 0; + char input[4]; + + output = ""; + remain = fread(input,1,3,fil); + while (remain > 0) + { + if (add_crlf && o && o % 76 == 0) + output += "\n"; + switch (remain) + { + case 1: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) ]; + output += "=="; + break; + case 2: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) ]; + output += "="; + break; + default: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ]; + output += bstr[ (input[i + 2] & 0x3f) ]; + } + o += 4; +// + remain = fread(input,1,3,fil); + } +} + + +void Base64::encode(const std::string& str_in, std::string& str_out, bool add_crlf) +{ + encode(str_in.c_str(), str_in.size(), str_out, add_crlf); +} + + +void Base64::encode(const char* input,size_t l,std::string& output, bool add_crlf) +{ + size_t i = 0; + size_t o = 0; + + output = ""; + while (i < l) + { + size_t remain = l - i; + if (add_crlf && o && o % 76 == 0) + output += "\n"; + switch (remain) + { + case 1: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) ]; + output += "=="; + break; + case 2: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) ]; + output += "="; + break; + default: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ]; + output += bstr[ (input[i + 2] & 0x3f) ]; + } + o += 4; + i += 3; + } +} + + +void Base64::encode(unsigned char* input,size_t l,std::string& output,bool add_crlf) +{ + size_t i = 0; + size_t o = 0; + + output = ""; + while (i < l) + { + size_t remain = l - i; + if (add_crlf && o && o % 76 == 0) + output += "\n"; + switch (remain) + { + case 1: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) ]; + output += "=="; + break; + case 2: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) ]; + output += "="; + break; + default: + output += bstr[ ((input[i] >> 2) & 0x3f) ]; + output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ]; + output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ]; + output += bstr[ (input[i + 2] & 0x3f) ]; + } + o += 4; + i += 3; + } +} + + +void Base64::decode(const std::string& input,std::string& output) +{ + size_t i = 0; + size_t l = input.size(); + + output = ""; + while (i < l) + { + while (i < l && (input[i] == 13 || input[i] == 10)) + i++; + if (i < l) + { + char b1 = (char)((rstr[(int)input[i]] << 2 & 0xfc) + + (rstr[(int)input[i + 1]] >> 4 & 0x03)); + output += b1; + if (input[i + 2] != '=') + { + char b2 = (char)((rstr[(int)input[i + 1]] << 4 & 0xf0) + + (rstr[(int)input[i + 2]] >> 2 & 0x0f)); + output += b2; + } + if (input[i + 3] != '=') + { + char b3 = (char)((rstr[(int)input[i + 2]] << 6 & 0xc0) + + rstr[(int)input[i + 3]]); + output += b3; + } + i += 4; + } + } +} + + +void Base64::decode(const std::string& input, unsigned char *output, size_t& sz) +{ + size_t i = 0; + size_t l = input.size(); + size_t j = 0; + + while (i < l) + { + while (i < l && (input[i] == 13 || input[i] == 10)) + i++; + if (i < l) + { + unsigned char b1 = (unsigned char)((rstr[(int)input[i]] << 2 & 0xfc) + + (rstr[(int)input[i + 1]] >> 4 & 0x03)); + if (output) + { + output[j] = b1; + } + j++; + if (input[i + 2] != '=') + { + unsigned char b2 = (unsigned char)((rstr[(int)input[i + 1]] << 4 & 0xf0) + + (rstr[(int)input[i + 2]] >> 2 & 0x0f)); + if (output) + { + output[j] = b2; + } + j++; + } + if (input[i + 3] != '=') + { + unsigned char b3 = (unsigned char)((rstr[(int)input[i + 2]] << 6 & 0xc0) + + rstr[(int)input[i + 3]]); + if (output) + { + output[j] = b3; + } + j++; + } + i += 4; + } + } + sz = j; +} + + +size_t Base64::decode_length(const std::string& str64) +{ + if (!str64.size() || str64.size() % 4) + return 0; + size_t l = 3 * (str64.size() / 4 - 1) + 1; + if (str64[str64.size() - 2] != '=') + l++; + if (str64[str64.size() - 1] != '=') + l++; + return l; +} diff --git a/src/shared/Network/Base64.h b/src/shared/Network/Base64.h new file mode 100644 index 0000000..d42378a --- /dev/null +++ b/src/shared/Network/Base64.h @@ -0,0 +1,50 @@ +/** + ** File ......... Base64.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _BASE64_H +#define _BASE64_H + +#include +#include + +class Base64 +{ + public: + Base64(); + + void encode(FILE *, std::string& , bool add_crlf = true); + void encode(const std::string&, std::string& , bool add_crlf = true); + void encode(const char *, size_t, std::string& , bool add_crlf = true); + void encode(unsigned char *, size_t, std::string& , bool add_crlf = true); + + void decode(const std::string&, std::string& ); + void decode(const std::string&, unsigned char *, size_t&); + + size_t decode_length(const std::string& ); + + private: + Base64(const Base64& ) {} + Base64& operator=(const Base64& ) { return *this; } + static char const *bstr; + static char const rstr[128]; +}; +#endif // _BASE64_H diff --git a/src/shared/Network/CircularBuffer.cpp b/src/shared/Network/CircularBuffer.cpp new file mode 100644 index 0000000..91b30ef --- /dev/null +++ b/src/shared/Network/CircularBuffer.cpp @@ -0,0 +1,151 @@ +/** + ** File ......... CircularBuffer.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#endif +#include +#include + +#include "Socket.h" +#include "SocketHandler.h" +#include "CircularBuffer.h" + +#ifdef _DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +CircularBuffer::CircularBuffer(Socket& owner,size_t size) +:m_owner(owner) +,buf(new char[size]) +,m_max(size) +,m_q(0) +,m_b(0) +,m_t(0) +,m_count(0) +{ +} + + +CircularBuffer::~CircularBuffer() +{ + delete[] buf; +} + + +bool CircularBuffer::Write(const char *s,size_t l) +{ + if (m_q + l > m_max) + { + m_owner.Handler().LogError(&m_owner, "CircularBuffer::Write", -1, "write buffer overflow"); + return false; // overflow + } + m_count += (unsigned long)l; + if (m_t + l > m_max) // block crosses circular border + { + size_t l1 = m_max - m_t; // size left until circular border crossing + memcpy(buf + m_t, s, l1); + memcpy(buf, s + l1, l - l1); + m_t = l - l1; + m_q += l; + } + else + { + memcpy(buf + m_t, s, l); + m_t += l; + if (m_t >= m_max) + m_t -= m_max; + m_q += l; + } + return true; +} + + +bool CircularBuffer::Read(char *s,size_t l) +{ + if (l > m_q) + { + m_owner.Handler().LogError(&m_owner, s ? "CircularBuffer::Read" : "CircularBuffer::Write", -1, "attempt to read beyond buffer"); + return false; // not enough chars + } + if (m_b + l > m_max) // block crosses circular border + { + size_t l1 = m_max - m_b; + if (s) + { + memcpy(s, buf + m_b, l1); + memcpy(s + l1, buf, l - l1); + } + m_b = l - l1; + m_q -= l; + } + else + { + if (s) + { + memcpy(s, buf + m_b, l); + } + m_b += l; + if (m_b >= m_max) + m_b -= m_max; + m_q -= l; + } + if (!m_q) + { + m_b = m_t = 0; + } + return true; +} + + +bool CircularBuffer::SoftRead(char *s, size_t l) +{ + if (l > m_q) + { + return false; + } + if (m_b + l > m_max) // block crosses circular border + { + size_t l1 = m_max - m_b; + if (s) + { + memcpy(s, buf + m_b, l1); + memcpy(s + l1, buf, l - l1); + } + } + else + { + if (s) + { + memcpy(s, buf + m_b, l); + } + } + return true; +} + + +bool CircularBuffer::Remove(size_t l) +{ + return Read(NULL, l); +} diff --git a/src/shared/Network/CircularBuffer.h b/src/shared/Network/CircularBuffer.h new file mode 100644 index 0000000..b0c6e53 --- /dev/null +++ b/src/shared/Network/CircularBuffer.h @@ -0,0 +1,67 @@ +/** + ** File ......... CircularBuffer.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _CIRCULARBUFFER_H +#define _CIRCULARBUFFER_H + +class Socket; + +class CircularBuffer +{ + public: + CircularBuffer(Socket& owner,size_t size); + ~CircularBuffer(); + +/** append l bytes from p to buffer */ + bool Write(const char *p,size_t l); +/** copy l bytes from buffer to dest */ + bool Read(char *dest,size_t l); +/** copy l bytes from buffer to dest, dont touch buffer pointers */ + bool SoftRead(char *dest, size_t l); +/** skip l bytes from buffer */ + bool Remove(size_t l); + +/** total buffer length */ + size_t GetLength() { return m_q; } +/** pointer to circular buffer beginning */ + char *GetStart() { return buf + m_b; } +/** return number of bytes from circular buffer beginning to buffer physical end */ + size_t GetL() { return (m_b + m_q > m_max) ? m_max - m_b : m_q; } +/** return free space in buffer, number of bytes until buffer overrun */ + size_t Space() { return m_max - m_q; } + +/** return total number of bytes written to this buffer, ever */ + unsigned long ByteCounter() { return m_count; } + + private: + Socket& GetOwner() const { return m_owner; } + CircularBuffer(const CircularBuffer& s) : m_owner( s.GetOwner() ) {} + CircularBuffer& operator=(const CircularBuffer& ) { return *this; } + Socket& m_owner; + char *buf; + size_t m_max; + size_t m_q; + size_t m_b; + size_t m_t; + unsigned long m_count; +}; +#endif // _CIRCULARBUFFER_H diff --git a/src/shared/Network/ListenSocket.h b/src/shared/Network/ListenSocket.h new file mode 100644 index 0000000..b1133a3 --- /dev/null +++ b/src/shared/Network/ListenSocket.h @@ -0,0 +1,354 @@ +/** + ** File ......... ListenSocket.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _LISTENSOCKET_H +#define _LISTENSOCKET_H + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "Socket.h" +#include "SocketHandler.h" +#include "StdLog.h" + +template +class ListenSocket : public Socket +{ + public: + ListenSocket(SocketHandler& h) : Socket(h), m_port(0), m_depth(0), m_creator(NULL) + ,m_bHasCreate(false) + { + m_creator = new X(h); + Socket *tmp = m_creator -> Create(); +//if (tmp && dynamic_cast(tmp)) + if (tmp && (X *)(tmp)) + { + m_bHasCreate = true; + } + if (tmp) + { + delete tmp; + } + } + ~ListenSocket() + { + delete m_creator; + } + +/** bind() to port 0 - a random port */ + int Bind() + { + int depth = 3; // think of maybe increasing this value if needed + ipaddr_t l = 0; + struct sockaddr_in sa; + SOCKET s; + + if ( (s = CreateSocket4(SOCK_STREAM)) == INVALID_SOCKET) + { + return -1; + } + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(0); // choose any port + memcpy(&sa.sin_addr, &l, 4); + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } + if (listen(s, depth) == -1) + { + Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } +// Find out what port was choosen + int sockaddr_length = sizeof(sockaddr); + getsockname(s, (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length); + m_port = ntohs(sa.sin_port); + m_depth = depth; + Attach(s); + return 0; + } + +/** bind to port with optional listen queue length (depth) */ + int Bind(port_t port, int depth = 3) + { + ipaddr_t l = 0; + struct sockaddr_in sa; + SOCKET s; + + if ( (s = CreateSocket4(SOCK_STREAM)) == INVALID_SOCKET) + { + return -1; + } + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port ); + memcpy(&sa.sin_addr, &l, 4); + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } + if (listen(s, depth) == -1) + { + Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } + m_port = port; + m_depth = depth; + Attach(s); + return 0; + } + +/** bind to port on a specified address */ + int Bind(const std::string& adapter, port_t port, int depth = 3) + { + ipaddr_t l = 0; + ipaddr_t tmp; + if (u2ip(adapter, tmp)) + { + l = tmp; + } + struct sockaddr_in sa; + SOCKET s; + + if ( (s = CreateSocket4(SOCK_STREAM)) == INVALID_SOCKET) + { + return -1; + } + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port ); + memcpy(&sa.sin_addr, &l, 4); + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } + if (listen(s, depth) == -1) + { + Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return -1; + } + m_port = port; + m_depth = depth; + Attach(s); + return 0; + } + +/** ipv6 bind to port with optional listen queue length (depth) */ +#ifdef IPPROTO_IPV6 + int Bind6(port_t port, int depth = 3) + { + struct sockaddr_in6 sa; + SOCKET s; + + if ( (s = CreateSocket6(SOCK_STREAM)) != INVALID_SOCKET) + { + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( port ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; +// sa.sin6_addr is all 0 + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) != -1) + { + if (listen(s, depth) != -1) + { + m_port = port; + m_depth = depth; + Attach(s); + return 0; + } + else + { + Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL); + } + } + else + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + } + closesocket(s); + } + return -1; + } +#endif + +/** ipv6 bind to port on a specified address */ +#ifdef IPPROTO_IPV6 + int Bind6(const std::string& address, port_t port, int depth = 3) + { + struct sockaddr_in6 sa; + SOCKET s; + + if ( (s = CreateSocket6(SOCK_STREAM)) != INVALID_SOCKET) + { + struct in6_addr a; + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( port ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; +// sa.sin6_addr is all 0 + if (u2ip(address, a)) + { + sa.sin6_addr = a; + } + if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) != -1) + { + if (listen(s, depth) != -1) + { + m_port = port; + m_depth = depth; + Attach(s); + return 0; + } + else + { + Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL); + } + } + else + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + } + closesocket(s); + } + return -1; + } +#endif + + port_t GetPort() + { + return m_port; + } + + int GetDepth() + { + return m_depth; + } + + void OnRead() + { + socklen_t len; + struct sockaddr *saptr; + socklen_t *lenptr = &len; + SOCKET a_s; + +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + struct sockaddr_in6 sa; + + saptr = (struct sockaddr *)&sa; + *lenptr = sizeof(struct sockaddr_in6); + a_s = accept(GetSocket(), saptr, lenptr); + if (a_s == INVALID_SOCKET) + { + Handler().LogError(this, "accept", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return; + } + Socket *tmp; + if (m_bHasCreate) + tmp = m_creator -> Create(); + else + tmp = new X(Handler()); + tmp -> SetIpv6(); + tmp -> SetParent(this); + tmp -> Attach(a_s); + tmp -> SetNonblocking(true); + tmp -> SetRemoteAddress( (struct sockaddr *)saptr, len); + tmp -> Init(); + Handler().Add(tmp); + tmp -> SetDeleteByHandler(true); + if (Handler().OkToAccept()) + { + if (tmp -> IsSSL()) // SSL Enabled socket + tmp -> OnSSLAccept(); + else + tmp -> OnAccept(); + } + else + { + Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_FATAL); + tmp -> SetCloseAndDelete(); + } + return; + } +#endif + struct sockaddr_in sa; + + saptr = (struct sockaddr *)&sa; + *lenptr = sizeof(struct sockaddr_in); + a_s = accept(GetSocket(), saptr, lenptr); + if (a_s == INVALID_SOCKET) + { + Handler().LogError(this, "accept", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return; + } + Socket *tmp; + if (m_bHasCreate) + tmp = m_creator -> Create(); + else + tmp = new X(Handler()); + tmp -> SetParent(this); + tmp -> Attach(a_s); + tmp -> SetNonblocking(true); + tmp -> SetRemoteAddress( (struct sockaddr *)saptr, len); + tmp -> Init(); + Handler().Add(tmp); + tmp -> SetDeleteByHandler(true); + if (Handler().OkToAccept()) + { + if (tmp -> IsSSL()) // SSL Enabled socket + tmp -> OnSSLAccept(); + else + tmp -> OnAccept(); + } + else + { + Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_FATAL); + tmp -> SetCloseAndDelete(); + } + } + + protected: + ListenSocket(const ListenSocket& ) {} + private: + ListenSocket& operator=(const ListenSocket& ) { return *this; } + port_t m_port; + int m_depth; + Socket *m_creator; + bool m_bHasCreate; +}; +#endif // _LISTENSOCKET_H diff --git a/src/shared/Network/Parse.cpp b/src/shared/Network/Parse.cpp new file mode 100644 index 0000000..3ecbece --- /dev/null +++ b/src/shared/Network/Parse.cpp @@ -0,0 +1,351 @@ +/** + ** Parse.cpp - parse a string + ** + ** Written: 1999-Feb-10 grymse@alhem.net + **/ + +/* +Copyright (C) 1999-2005 Anders Hedstrom + +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 +#include +#include + +#include "Parse.h" + +#ifdef _DEBUG +#define DEB(x) +#else +#define DEB(x) +#endif + +/* implementation of class Parse */ + +Parse::Parse() +:pa_the_str("") +,pa_splits("") +,pa_ord("") +,pa_the_ptr(0) +,pa_breakchar(0) +,pa_enable(0) +,pa_disable(0) +,pa_nospace(0) +,pa_quote(false) +{ +} + + +Parse::Parse(const std::string&s) +:pa_the_str(s) +,pa_splits("") +,pa_ord("") +,pa_the_ptr(0) +,pa_breakchar(0) +,pa_enable(0) +,pa_disable(0) +,pa_nospace(0) +,pa_quote(false) +{ +} + + +Parse::Parse(const std::string&s,const std::string&sp) +:pa_the_str(s) +,pa_splits(sp) +,pa_ord("") +,pa_the_ptr(0) +,pa_breakchar(0) +,pa_enable(0) +,pa_disable(0) +,pa_nospace(0) +,pa_quote(false) +{ +} + + +Parse::Parse(const std::string&s,const std::string&sp,short nospace) +:pa_the_str(s) +,pa_splits(sp) +,pa_ord("") +,pa_the_ptr(0) +,pa_breakchar(0) +,pa_enable(0) +,pa_disable(0) +,pa_nospace(1) +,pa_quote(false) +{ +} + + +Parse::~Parse() +{ +} + + +#define C ((pa_the_ptr + +/***************************************************/ +/* interface of class Parse */ + +//! Splits a string whatever way you want + +class Parse +{ + public: + Parse(); + Parse(const std::string&); + Parse(const std::string&,const std::string&); + Parse(const std::string&,const std::string&,short); + ~Parse(); + short issplit(char); + void getsplit(void); + void getsplit(std::string&); + std::string getword(void); + void getword(std::string&); + void getword(std::string&,std::string&,int); + std::string getrest(); + void getrest(std::string&); + long getvalue(void); + void setbreak(char); + int getwordlen(void); + int getrestlen(void); + void enablebreak(char c) + { + pa_enable = c; + } + void disablebreak(char c) + { + pa_disable = c; + } + void getline(void); + void getline(std::string&); + size_t getptr(void) { return pa_the_ptr; } + void EnableQuote(bool b) { pa_quote = b; } + + private: + std::string pa_the_str; + std::string pa_splits; + std::string pa_ord; + size_t pa_the_ptr; + char pa_breakchar; + char pa_enable; + char pa_disable; + short pa_nospace; + bool pa_quote; +}; +#endif // _PARSE_H diff --git a/src/shared/Network/PoolSocket.cpp b/src/shared/Network/PoolSocket.cpp new file mode 100644 index 0000000..ea5d231 --- /dev/null +++ b/src/shared/Network/PoolSocket.cpp @@ -0,0 +1,51 @@ +/** + ** File ......... PoolSocket.cpp + ** Published .... 2004-11-14 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#endif +#include +#include "SocketHandler.h" +#include "PoolSocket.h" + +#define DEB(x) + +PoolSocket::PoolSocket(SocketHandler& h,Socket *src) +:Socket(h) +{ + CopyConnection( src ); + DEB(printf("PoolSocket()\n");) + SetIsClient(); +} + + +PoolSocket::~PoolSocket() +{ + DEB(printf("~PoolSocket()\n");) +} + + +void PoolSocket::OnRead() +{ + Handler().LogError(this, "OnRead", 0, "data on hibernating socket", LOG_LEVEL_FATAL); + SetCloseAndDelete(); +} diff --git a/src/shared/Network/PoolSocket.h b/src/shared/Network/PoolSocket.h new file mode 100644 index 0000000..7de8ac9 --- /dev/null +++ b/src/shared/Network/PoolSocket.h @@ -0,0 +1,48 @@ +/** + ** File ......... PoolSocket.h + ** Published .... 2004-11-14 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _POOLSOCKET_H +#define _POOLSOCKET_H + +#include "Socket.h" + +class SocketHandler; + +class PoolSocket : public Socket +{ + public: + PoolSocket(SocketHandler& h,Socket *src); + ~PoolSocket(); + + void OnRead(); + + private: +// copy constructor + PoolSocket(const PoolSocket& s) : Socket(s) + { + } + PoolSocket& operator=(const PoolSocket& ) // assignment operator + { + return *this; + } +}; +#endif // _POOLSOCKET_H diff --git a/src/shared/Network/ResolvServer.cpp b/src/shared/Network/ResolvServer.cpp new file mode 100644 index 0000000..fb3cee0 --- /dev/null +++ b/src/shared/Network/ResolvServer.cpp @@ -0,0 +1,69 @@ +/** + ** File ......... ResolvServer.cpp + ** Published .... 2005-03-24 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 +#ifdef _WIN32 +#pragma warning(disable:4786) +#endif +#include "StdoutLog.h" +#include "SocketHandler.h" +#include "ListenSocket.h" +#include "ResolvSocket.h" +#include "ResolvServer.h" + +ResolvServer::ResolvServer(port_t port) +:Thread() +,m_quit(false) +,m_port(port) +{ +} + + +ResolvServer::~ResolvServer() +{ +} + + +void ResolvServer::Run() +{ +// StdoutLog log; + SocketHandler h; + ListenSocket l(h); + + if (l.Bind("127.0.0.1", m_port)) + { + return; + } + h.Add(&l); + + while (!m_quit && IsRunning() ) + { + h.Select(1,0); + } + SetRunning(false); +} + + +void ResolvServer::Quit() +{ + m_quit = true; +} diff --git a/src/shared/Network/ResolvServer.h b/src/shared/Network/ResolvServer.h new file mode 100644 index 0000000..e1c9dcd --- /dev/null +++ b/src/shared/Network/ResolvServer.h @@ -0,0 +1,50 @@ +/** + ** File ......... ResolvServer.h + ** Published .... 2005-03-24 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _RESOLVSERVER_H +#define _RESOLVSERVER_H + +#include "Thread.h" + +class ResolvServer : public Thread +{ + public: + ResolvServer(port_t); + ~ResolvServer(); + + void Run(); + void Quit(); + + private: + ResolvServer(const ResolvServer& ) // copy constructor + { + } +// assignment operator + ResolvServer& operator=(const ResolvServer& ) + { + return *this; + } + + bool m_quit; + port_t m_port; +}; +#endif // _RESOLVSERVER_H diff --git a/src/shared/Network/ResolvSocket.cpp b/src/shared/Network/ResolvSocket.cpp new file mode 100644 index 0000000..e8da29a --- /dev/null +++ b/src/shared/Network/ResolvSocket.cpp @@ -0,0 +1,192 @@ +/** + ** File ......... ResolvSocket.cpp + ** Published .... 2005-03-24 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 +#ifdef _WIN32 +#pragma warning(disable:4786) +#endif +/* +#if defined(_WIN32) || defined(__CYGWIN__) +#pragma warning(disable:4786) +#define FD_SETSIZE 1024 +#include +#else +#include +#endif +*/ +#include "ResolvSocket.h" +#include "Utility.h" +#include "Parse.h" + +ResolvSocket::ResolvSocket(SocketHandler& h,Socket *parent) +:TcpSocket(h) +,m_bServer(false) +,m_parent(parent) +{ + SetLineProtocol(); +} + + +ResolvSocket::~ResolvSocket() +{ +} + + +void ResolvSocket::OnLine(const std::string& line) +{ + Parse pa(line, ":"); + if (m_bServer) + { + m_query = pa.getword(); + m_data = pa.getrest(); + if (!Detach()) // detach failed? + { + SetCloseAndDelete(); + } + return; + } + std::string key = pa.getword(); + std::string value = pa.getrest(); + + if (key == "A" && m_parent) + { + ipaddr_t l; + u2ip(value, l); // ip2ipaddr_t + m_parent -> Resolved(m_resolv_id, l, m_resolv_port); + m_parent = NULL; // always use first ip in case there are several + } +} + + +void ResolvSocket::OnDetached() +{ +#ifndef _WIN32 + if (m_query == "getaddrinfo") + { + struct addrinfo hints; + struct addrinfo *res; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags |= AI_CANONNAME; + int n = getaddrinfo(m_data.c_str(), NULL, &hints, &res); + if (!n) + { +/* + struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; + }; + +*/ + while (res) + { + Send("Flags: " + Utility::l2string(res -> ai_flags) + "\n"); + Send("Family: " + Utility::l2string(res -> ai_family) + "\n"); + Send("Socktype: " + Utility::l2string(res -> ai_socktype) + "\n"); + Send("Protocol: " + Utility::l2string(res -> ai_protocol) + "\n"); + Send("Addrlen: " + Utility::l2string(res -> ai_addrlen) + "\n"); +// base64-encoded sockaddr + Send("Canonname: "); + Send( res -> ai_canonname ); + Send("\n"); + Send("\n"); +// + res = res -> ai_next; + } + freeaddrinfo(res); + } + else + { + std::string error = "Error: "; + error += gai_strerror(n); + Send( error + "\n" ); + } + } + else +#endif // _WIN32 + if (m_query == "gethostbyname") + { + struct hostent *h = gethostbyname(m_data.c_str()); + if (h) + { + char slask[1000]; + sprintf(slask, "Name: %s\n", h -> h_name); + Send( slask ); + size_t i = 0; + while (h -> h_aliases[i]) + { + sprintf(slask, "Alias: %s\n", h -> h_aliases[i]); + Send( slask ); + i++; + } + sprintf(slask, "AddrType: %d\n", h -> h_addrtype); + Send( slask ); + sprintf(slask, "Length: %d\n", h -> h_length); + Send( slask ); + i = 0; + while (h -> h_addr_list[i]) + { +// let's assume 4 byte IPv4 addresses + char ip[40]; + *ip = 0; + for (int j = 0; j < 4; j++) + { + if (*ip) + strcat(ip,"."); + sprintf(ip + strlen(ip),"%u",(unsigned char)h -> h_addr_list[i][j]); + } + sprintf(slask, "A: %s\n", ip); + Send( slask ); + i++; + } + } + else + { + Send("Failed\n"); + } + Send( "\n" ); + } + else + if (m_query == "gethostbyaddr") + { + Send("Not Implemented\n\n"); + } + else + { + std::string msg = "Unknown query type: " + m_query; + Handler().LogError(this, "OnDetached", 0, msg); + Send("Unknown\n\n"); + } + SetCloseAndDelete(); +} + + +void ResolvSocket::OnConnect() +{ + std::string msg = "gethostbyname " + m_resolv_host + "\n"; + Send( msg ); +} diff --git a/src/shared/Network/ResolvSocket.h b/src/shared/Network/ResolvSocket.h new file mode 100644 index 0000000..51de0f3 --- /dev/null +++ b/src/shared/Network/ResolvSocket.h @@ -0,0 +1,63 @@ +/** + ** File ......... ResolvSocket.h + ** Published .... 2005-03-24 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _RESOLVSOCKET_H +#define _RESOLVSOCKET_H + +#include "SocketHandler.h" +#include "TcpSocket.h" + +class ResolvSocket : public TcpSocket +{ + public: + ResolvSocket(SocketHandler&,Socket *parent = NULL); + ~ResolvSocket(); + + void OnAccept() { m_bServer = true; } + void OnLine(const std::string& ); + void OnDetached(); + + void SetId(int x) { m_resolv_id = x; } + void SetHost(const std::string& x) { m_resolv_host = x; } + void SetPort(port_t x) { m_resolv_port = x; } + void OnConnect(); + + private: +// copy constructor + ResolvSocket(const ResolvSocket& s) : TcpSocket(s) + { + } +// assignment operator + ResolvSocket& operator=(const ResolvSocket& ) + { + return *this; + } + + std::string m_query; + std::string m_data; + bool m_bServer; + Socket *m_parent; + int m_resolv_id; + std::string m_resolv_host; + port_t m_resolv_port; +}; +#endif // _RESOLVSOCKET_H diff --git a/src/shared/Network/Socket.cpp b/src/shared/Network/Socket.cpp new file mode 100644 index 0000000..5adbbb3 --- /dev/null +++ b/src/shared/Network/Socket.cpp @@ -0,0 +1,953 @@ +/** + ** File ......... Socket.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#include +#else +#include +#endif +#include +#include +#include +#include "Parse.h" +#include "SocketHandler.h" +#include "SocketThread.h" +#include "Utility.h" + +#include "Socket.h" + +#ifdef _DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +// statics +#ifdef _WIN32 +WSAInitializer Socket::m_winsock_init; +#endif + +Socket::Socket(SocketHandler& h) +:m_handler(h) +,m_socket( INVALID_SOCKET ) +,m_bDel(false) +,m_bClose(false) +,m_bConnecting(false) +,m_tCreate(time(NULL)) +,m_line_protocol(false) +,m_ssl_connecting(false) +//, m_tActive(time(NULL)) +//, m_timeout(0) +,m_detach(false) +,m_detached(false) +,m_pThread(NULL) +,m_ipv6(false) +,m_sa_len(0) +,m_parent(NULL) +,m_socket_type(0) +,m_bClient(false) +,m_bRetain(false) +,m_bLost(false) +,m_call_on_connect(false) +,m_opt_reuse(true) +,m_opt_keepalive(true) +,m_bSocks4(false) +,m_socks4_host(h.GetSocks4Host()) +,m_socks4_port(h.GetSocks4Port()) +,m_socks4_userid(h.GetSocks4Userid()) +,m_connect_timeout(5) +,m_b_enable_ssl(false) +,m_b_ssl(false) +,m_b_ssl_server(false) +,m_b_disable_read(false) +{ +} + + +Socket::~Socket() +{ + if (m_socket != INVALID_SOCKET && !m_bRetain) + { + Close(); + } + if (m_pThread) + { + delete m_pThread; + } +} + + +void Socket::Init() +{ +} + + +void Socket::OnRead() +{ +} + + +void Socket::OnWrite() +{ +} + + +void Socket::OnException() +{ +// errno valid here? + int err; + socklen_t errlen = sizeof(err); +#ifdef _WIN32 + getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); +#else + getsockopt(m_socket, SOL_SOCKET, SO_ERROR, &err, &errlen); +#endif + Handler().LogError(this, "exception on select", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(); +} + + +void Socket::OnDelete() +{ +} + + +void Socket::OnConnect() +{ +} + + +bool Socket::CheckConnect() +{ + int err; + socklen_t errlen = sizeof(err); + bool r = true; +#ifdef _WIN32 + getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); +#else + getsockopt(m_socket, SOL_SOCKET, SO_ERROR, &err, &errlen); +#endif + if (err) + { + Handler().LogError(this, "connect failed", err, StrError(err), LOG_LEVEL_FATAL); + r = false; + } + SetConnecting(false); +// %! add to read fd_set here + if (r) // ok + { + Set(!IsDisableRead(), false); + } + return r; +} + + +void Socket::OnAccept() +{ +} + + +int Socket::Close() +{ + if (m_socket == INVALID_SOCKET) // this could happen + { + Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING); + return 0; + } + int n; + SetNonblocking(true); + if (shutdown(m_socket, SHUT_RDWR) == -1) + { +// failed... + Handler().LogError(this, "shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR); + } +// + char tmp[100]; + if ((n = recv(m_socket,tmp,100,0)) == -1) + { +// Handler().LogError(this, "read() after shutdown", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + else + { + if (n) + Handler().LogError(this, "read() after shutdown", n, "bytes read", LOG_LEVEL_WARNING); + } + if ((n = closesocket(m_socket)) == -1) + { +// failed... + Handler().LogError(this, "close", Errno, StrError(Errno), LOG_LEVEL_ERROR); + } + m_socket = INVALID_SOCKET; + return n; +} + + +SOCKET Socket::CreateSocket4(int type, const std::string& protocol) +{ + struct protoent *p = NULL; + int optval; + SOCKET s; + + m_socket_type = type; + m_socket_protocol = protocol; + if (protocol.size()) + { + p = getprotobyname( protocol.c_str() ); + if (!p) + { + Handler().LogError(this, "getprotobyname", Errno, StrError(Errno), LOG_LEVEL_FATAL); + return INVALID_SOCKET; + } + } + int protno = p ? p -> p_proto : 0; + + s = socket(AF_INET, type, protno); + if (s == INVALID_SOCKET) + { + Handler().LogError(this, "socket", Errno, StrError(Errno), LOG_LEVEL_FATAL); + return INVALID_SOCKET; + } + OnOptions(AF_INET, type, protno, s); + if (type == SOCK_STREAM) + { + optval = m_opt_reuse ? 1 : 0; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) + { + Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_REUSEADDR)", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return INVALID_SOCKET; + } + + optval = m_opt_keepalive ? 1 : 0; + if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) == -1) + { + Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_KEEPALIVE)", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return INVALID_SOCKET; + } + optval = 1; + setsockopt(s, 0x06, TCP_NODELAY, (char *)&optval,sizeof(optval)); + } + + return s; +} + + +#ifdef IPPROTO_IPV6 +SOCKET Socket::CreateSocket6(int type, const std::string& protocol) +{ + struct protoent *p = NULL; + int optval; + SOCKET s; + + m_socket_type = type; + m_socket_protocol = protocol; + if (protocol.size()) + { + p = getprotobyname( protocol.c_str() ); + if (!p) + { + Handler().LogError(this, "getprotobyname", Errno, StrError(Errno), LOG_LEVEL_FATAL); + return INVALID_SOCKET; + } + } + int protno = p ? p -> p_proto : 0; + + s = socket(AF_INET6, type, protno); + if (s == INVALID_SOCKET) + { + Handler().LogError(this, "socket", Errno, StrError(Errno), LOG_LEVEL_FATAL); + return INVALID_SOCKET; + } + OnOptions(AF_INET6, type, protno, s); + if (type == SOCK_STREAM) + { + optval = m_opt_reuse ? 1 : 0; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) + { + Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_REUSEADDR)", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return INVALID_SOCKET; + } + + optval = m_opt_keepalive ? 1 : 0; + if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) == -1) + { + Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_KEEPALIVE)", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return INVALID_SOCKET; + } + } + m_ipv6 = true; + return s; +} +#endif + +bool Socket::isip(const std::string& str) +{ + if (m_ipv6) + { + size_t qc = 0; + size_t qd = 0; + for (size_t i = 0; i < str.size(); i++) + { + qc += (str[i] == ':') ? 1 : 0; + qd += (str[i] == '.') ? 1 : 0; + } + if (qc > 7) + { + return false; + } + if (qd && qd != 3) + { + return false; + } + Parse pa(str,":."); + std::string tmp = pa.getword(); + while (tmp.size()) + { + if (tmp.size() > 4) + { + return false; + } + for (size_t i = 0; i < tmp.size(); i++) + { + if (tmp[i] < '0' || (tmp[i] > '9' && tmp[i] < 'A') || + (tmp[i] > 'F' && tmp[i] < 'a') || tmp[i] > 'f') + { + return false; + } + } +// + tmp = pa.getword(); + } + return true; + } + for (size_t i = 0; i < str.size(); i++) + if (!isdigit(str[i]) && str[i] != '.') + return false; + return true; +} + + +bool Socket::u2ip(const std::string& str, ipaddr_t& l) +{ + if (m_ipv6) + { + Handler().LogError(this, "u2ip", 0, "converting to ipv4 on ipv6 socket", LOG_LEVEL_ERROR); + return false; + } + if (isip(str)) + { + Parse pa((char *)str.c_str(), "."); + union + { + struct + { + unsigned char b1; + unsigned char b2; + unsigned char b3; + unsigned char b4; + } a; + ipaddr_t l; + } u; + u.a.b1 = static_cast(pa.getvalue()); + u.a.b2 = static_cast(pa.getvalue()); + u.a.b3 = static_cast(pa.getvalue()); + u.a.b4 = static_cast(pa.getvalue()); + l = u.l; + return true; + } + else + { + struct hostent *he = gethostbyname( str.c_str() ); + if (!he) + { + Handler().LogError(this, "gethostbyname", Errno, StrError(Errno), LOG_LEVEL_WARNING); + return false; + } + memcpy(&l, he -> h_addr, 4); + return true; + } + return false; +} + + +#ifdef IPPROTO_IPV6 +bool Socket::u2ip(const std::string& str, struct in6_addr& l) +{ + if (!m_ipv6) + { + Handler().LogError(this, "u2ip", 0, "converting to ipv6 on ipv4 socket", LOG_LEVEL_ERROR); + return false; + } + if (isip(str)) + { + std::list vec; + size_t x = 0; + char s[100]; + for (size_t i = 0; i <= str.size(); i++) + { + if (i == str.size() || str[i] == ':') + { + strncpy(s, str.substr(x,i - x).c_str(), i - x); + s[i - x] = 0; +// + if (strstr(s,".")) // x.x.x.x + { + Parse pa(s,"."); + char slask[100]; + unsigned long b0 = static_cast(pa.getvalue()); + unsigned long b1 = static_cast(pa.getvalue()); + unsigned long b2 = static_cast(pa.getvalue()); + unsigned long b3 = static_cast(pa.getvalue()); + sprintf(slask,"%lx",b0 * 256 + b1); + vec.push_back(slask); + sprintf(slask,"%lx",b2 * 256 + b3); + vec.push_back(slask); + } + else + { + vec.push_back(s); + } +// + x = i + 1; + } + } + size_t sz = vec.size(); // number of byte pairs + size_t i = 0; // index in in6_addr.in6_u.u6_addr16[] ( 0 .. 7 ) + for (std::list::iterator it = vec.begin(); it != vec.end(); it++) + { + std::string bytepair = *it; + if (bytepair.size()) + { + l.s6_addr16[i++] = htons(Utility::hex2unsigned(bytepair)); + } + else + { + l.s6_addr16[i++] = 0; + while (sz++ < 8) + { + l.s6_addr16[i++] = 0; + } + } + } + return true; + } + else + { +#ifdef SOLARIS + int errnum = 0; + struct hostent *he = getipnodebyname( str.c_str(), AF_INET6, 0, &errnum ); +#else + struct hostent *he = gethostbyname2( str.c_str(), AF_INET6 ); +#endif + if (!he) + { +#ifdef SOLARIS + Handler().LogError(this, "getipnodebyname", errnum, "failed, see error code"); +#else + Handler().LogError(this, "gethostbyname2", Errno, StrError(Errno), LOG_LEVEL_WARNING); +#endif + return false; + } + memcpy(&l,he -> h_addr_list[0],he -> h_length); +#ifdef SOLARIS + free(he); +#endif + return true; + } + return false; +} +#endif + +void Socket::l2ip(const ipaddr_t ip, std::string& str) +{ + if (m_ipv6) + { + Handler().LogError(this, "l2ip", 0, "converting to ipv4 on ipv6 socket", LOG_LEVEL_ERROR); + str = ""; + return; + } + union + { + struct + { + unsigned char b1; + unsigned char b2; + unsigned char b3; + unsigned char b4; + } a; + ipaddr_t l; + } u; + u.l = ip; + char tmp[100]; + sprintf(tmp, "%u.%u.%u.%u", u.a.b1, u.a.b2, u.a.b3, u.a.b4); + str = tmp; +} + + +#ifdef IPPROTO_IPV6 +void Socket::l2ip(const struct in6_addr& ip, std::string& str,bool mixed) +{ + if (!m_ipv6) + { + Handler().LogError(this, "l2ip", 0, "converting to ipv6 on ipv4 socket", LOG_LEVEL_ERROR); + str = ""; + return; + } + char slask[100]; + *slask = 0; + unsigned int prev = 0; + if (mixed) + { + unsigned int x; + for (size_t i = 0; i < 6; i++) + { + x = ntohs(ip.s6_addr16[i]); + if (*slask && (x || prev)) + strcat(slask,":"); + if (x) + { + sprintf(slask + strlen(slask),"%X", x); + } + prev = x; + } + x = ntohs(ip.s6_addr16[6]); + sprintf(slask + strlen(slask),":%u.%u",x / 256,x & 255); + x = ntohs(ip.s6_addr16[7]); + sprintf(slask + strlen(slask),".%u.%u",x / 256,x & 255); + } + else + { + for (size_t i = 0; i < 8; i++) + { + unsigned int x = ntohs(ip.s6_addr16[i]); + if (*slask && (x || prev)) + strcat(slask,":"); + if (x) + { + sprintf(slask + strlen(slask),"%X", x); + } + prev = x; + } + } + str = slask; +} +#endif + +void Socket::Attach(SOCKET s) +{ + m_socket = s; +} + + +SOCKET Socket::GetSocket() +{ + return m_socket; +} + + +void Socket::SetDeleteByHandler(bool x) +{ + m_bDel = x; +} + + +bool Socket::DeleteByHandler() +{ + return m_bDel; +} + + +void Socket::SetCloseAndDelete(bool x) +{ + m_bClose = x; +} + + +bool Socket::CloseAndDelete() +{ + return m_bClose; +} + + +void Socket::SetConnecting(bool x) +{ + m_bConnecting = x; + m_tConnect = time(NULL); +} + + +bool Socket::Connecting() +{ + return m_bConnecting; +} + + +void Socket::SetRemoteAddress(struct sockaddr* sa, socklen_t l) +{ + memcpy(&m_sa, sa, l); + m_sa_len = l; +} + + +void Socket::GetRemoteSocketAddress(struct sockaddr& sa,socklen_t& sa_len) +{ + memcpy(&sa, &m_sa, m_sa_len); + sa_len = m_sa_len; +} + + +SocketHandler& Socket::Handler() const +{ + return m_handler; +} + + +ipaddr_t Socket::GetRemoteIP4() +{ + ipaddr_t l = 0; + struct sockaddr_in* saptr = (struct sockaddr_in*)&m_sa; + if (m_ipv6) + { + Handler().LogError(this, "GetRemoteIP4", 0, "get ipv4 address for ipv6 socket", LOG_LEVEL_WARNING); + } + memcpy(&l, &saptr -> sin_addr, 4); + return l; +} + + +#ifdef IPPROTO_IPV6 +struct in6_addr Socket::GetRemoteIP6() +{ + struct sockaddr_in6 *p = (struct sockaddr_in6 *)&m_sa; + if (!m_ipv6) + { + Handler().LogError(this, "GetRemoteIP6", 0, "get ipv6 address for ipv4 socket", LOG_LEVEL_WARNING); + } + return p -> sin6_addr; +} +#endif + +port_t Socket::GetRemotePort() +{ +#ifdef IPPROTO_IPV6 + if (m_ipv6) + { + struct sockaddr_in6 *p = (struct sockaddr_in6 *)&m_sa; + return ntohs(p -> sin6_port); + } +#endif + struct sockaddr_in* saptr = (struct sockaddr_in*)&m_sa; + return ntohs(saptr -> sin_port); +} + + +std::string Socket::GetRemoteAddress() +{ + std::string str; +#ifdef IPPROTO_IPV6 + if (m_ipv6) + { + l2ip(GetRemoteIP6(), str); + return str; + } +#endif + l2ip(GetRemoteIP4(), str); + return str; +} + + +std::string Socket::GetRemoteHostname() +{ + std::string str; +#ifdef IPPROTO_IPV6 + if (m_ipv6) + { + Handler().LogError(this, "GetRemoteHostname", 0, "not implemented for ipv6", LOG_LEVEL_WARNING); + return GetRemoteAddress(); + } +#endif + long l = GetRemoteIP4(); +//#ifdef LINUX +// struct hostent *he = gethostbyaddr(&l, sizeof(long), AF_INET); +//#else // _WIN32, MACOSX and SOLARIS + struct hostent *he = gethostbyaddr( (char *)&l, sizeof(long), AF_INET); +//#endif + if (!he) + { + return GetRemoteAddress(); + } + str = he -> h_name; + return str; +} + + +bool Socket::SetNonblocking(bool bNb) +{ +#ifdef _WIN32 + unsigned long l = bNb ? 1 : 0; + int n = ioctlsocket(m_socket, FIONBIO, &l); + if (n != 0) + { + Handler().LogError(this, "ioctlsocket(FIONBIO)", Errno, ""); + return false; + } + return true; +#else + if (bNb) + { + if (fcntl(m_socket, F_SETFL, O_NONBLOCK) == -1) + { + Handler().LogError(this, "fcntl(F_SETFL, O_NONBLOCK)", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return false; + } + } + else + { + if (fcntl(m_socket, F_SETFL, 0) == -1) + { + Handler().LogError(this, "fcntl(F_SETFL, 0)", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return false; + } + } + return true; +#endif +} + + +bool Socket::SetNonblocking(bool bNb, SOCKET s) +{ +#ifdef _WIN32 + unsigned long l = bNb ? 1 : 0; + int n = ioctlsocket(s, FIONBIO, &l); + if (n != 0) + { + Handler().LogError(this, "ioctlsocket(FIONBIO)", Errno, ""); + return false; + } + return true; +#else + if (bNb) + { + if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) + { + Handler().LogError(this, "fcntl(F_SETFL, O_NONBLOCK)", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return false; + } + } + else + { + if (fcntl(s, F_SETFL, 0) == -1) + { + Handler().LogError(this, "fcntl(F_SETFL, 0)", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return false; + } + } + return true; +#endif +} + + +void Socket::Set(bool bRead, bool bWrite, bool bException) +{ + m_handler.Set(m_socket, bRead, bWrite, bException); +} + + +time_t Socket::GetConnectTime() +{ + return time(NULL) - m_tConnect; +} + + +bool Socket::Ready() +{ + if (m_socket != INVALID_SOCKET && !Connecting() && !CloseAndDelete()) + return true; + return false; +} + + +bool Socket::Detach() +{ + if (!DeleteByHandler()) + return false; + if (m_pThread) + return false; + if (m_detached) + return false; + m_detach = true; + return true; +} + + +void Socket::DetachSocket() +{ + m_pThread = new SocketThread(*this); + m_pThread -> SetRelease(true); +} + + +void Socket::OnLine(const std::string& ) +{ +} + + +void Socket::OnSSLInitDone() +{ +} + + +bool Socket::SSLCheckConnect() +{ + return false; +} + + +void Socket::SetSSLConnecting(bool x) +{ + m_ssl_connecting = x; +} + + +bool Socket::SSLConnecting() +{ + return m_ssl_connecting; +} + + +void Socket::SetLineProtocol(bool x) +{ + m_line_protocol = x; +} + + +bool Socket::LineProtocol() +{ + return m_line_protocol; +} + + +void Socket::ReadLine() +{ +} + + +void Socket::OnConnectFailed() +{ +} + + +Socket::Socket(const Socket& s) : m_handler(s.Handler()) +{ +} + + +Socket *Socket::GetParent() +{ + return m_parent; +} + + +void Socket::SetParent(Socket *x) +{ + m_parent = x; +} + + +port_t Socket::GetPort() +{ + Handler().LogError(this, "GetPort", 0, "GetPort only implemented for ListenSocket", LOG_LEVEL_WARNING); + return 0; +} + + +void Socket::CopyConnection(Socket *sock) +{ + Attach( sock -> GetSocket() ); + SetSocketType( sock -> GetSocketType() ); + SetSocketProtocol( sock -> GetSocketProtocol() ); + SetClientRemoteAddr( sock -> GetClientRemoteAddr() ); + SetClientRemotePort( sock -> GetClientRemotePort() ); + + struct sockaddr sa; + socklen_t sa_len; + sock -> GetRemoteSocketAddress(sa, sa_len); + SetRemoteAddress(&sa, sa_len); +} + + +void Socket::OnOptions(int family,int type,int protocol,SOCKET s) +{ +/* + Handler().LogError(this, "OnOptions", family, "Address Family", LOG_LEVEL_INFO); + Handler().LogError(this, "OnOptions", type, "Type", LOG_LEVEL_INFO); + Handler().LogError(this, "OnOptions", protocol, "Protocol", LOG_LEVEL_INFO); +*/ + SetReuse(true); + SetKeepalive(true); +} + + +int Socket::Resolve(const std::string& host,port_t port) +{ + return Handler().Resolve(this, host, port); +} + + +void Socket::OnSocks4Connect() +{ + Handler().LogError(this, "OnSocks4Connect", 0, "Use with TcpSocket only"); +} + + +void Socket::OnSocks4ConnectFailed() +{ + Handler().LogError(this, "OnSocks4ConnectFailed", 0, "Use with TcpSocket only"); +} + + +bool Socket::OnSocks4Read() +{ + Handler().LogError(this, "OnSocks4Read", 0, "Use with TcpSocket only"); + return true; +} + + +void Socket::SetSocks4Host(const std::string& host) +{ + u2ip(host, m_socks4_host); +} + + +/* +void Socket::OnWriteComplete() +{ +} +*/ + +void Socket::Resolved(int,ipaddr_t,port_t) +{ +} diff --git a/src/shared/Network/Socket.h b/src/shared/Network/Socket.h new file mode 100644 index 0000000..79340bd --- /dev/null +++ b/src/shared/Network/Socket.h @@ -0,0 +1,299 @@ +/** + ** File ......... Socket.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _SOCKETBASE_H +#define _SOCKETBASE_H + +#include +#include +#include + +#include "socket_include.h" +#include + +#ifndef _WIN32 +#include +#else +#define TCP_NODELAY 0x0001 +#endif + +class SocketHandler; +class SocketThread; + +// typedef std::list string_v; + +class Socket +{ + friend class SocketHandler; + public: +/** "Default" constructor */ + Socket(SocketHandler&); + virtual ~Socket(); + +/** Socket class instantiation method. Used when a "non-standard" constructor + * needs to be used for the socket class. Note: the socket class still needs + * the "default" constructor with one SocketHandler& as input parameter. + */ + virtual Socket *Create() { return NULL; } +/** Init: CTcpSocket uses this to create its ICrypt member variable. + * The ICrypt member variable is created by a virtual method, therefore + * it can't be called directly from the CTcpSocket constructor. + * Also used to determine if incoming HTTP connection is normal (port 80) + * or ssl (port 443). + */ + virtual void Init(); + + void Attach(SOCKET s); + SOCKET GetSocket(); + virtual int Close(); + SOCKET CreateSocket4(int type,const std::string& protocol = ""); + SOCKET CreateSocket6(int type,const std::string& protocol = ""); + void Set(bool bRead,bool bWrite,bool bException = true); + bool Ready(); + +/** Called when there is something to be read from the file descriptor. */ + virtual void OnRead(); +/** Called when there is room for another write on the file descriptor. */ + virtual void OnWrite(); +/** Called on socket exception. */ + virtual void OnException(); +/** Called before a socket class is deleted by the SocketHandler. */ + virtual void OnDelete(); +/** Called when a connection has completed. */ + virtual void OnConnect(); +/** Called when an incoming connection has been completed. */ + virtual void OnAccept(); +/** Called when a complete line has been read and the socket is in + * line protocol mode. */ + virtual void OnLine(const std::string& ); +/** Used internally by SSLSocket. */ + virtual void OnSSLInitDone(); +/** Called on connect timeout (5s). */ + virtual void OnConnectFailed(); +/** Called when a socket is created, to set socket options. */ + virtual void OnOptions(int family,int type,int protocol,SOCKET); +/** Socks4 client support internal use. @see TcpSocket */ + virtual void OnSocks4Connect(); +/** Socks4 client support internal use. @see TcpSocket */ + virtual void OnSocks4ConnectFailed(); +/** Socks4 client support internal use. @see TcpSocket */ + virtual bool OnSocks4Read(); +/** Called when the last write caused the tcp output buffer to + * become empty. */ +// virtual void OnWriteComplete(); +/** SSL client/server support - internal use. @see TcpSocket */ + virtual void OnSSLConnect() {} +/** SSL client/server support - internal use. @see TcpSocket */ + virtual void OnSSLAccept() {} + + virtual bool CheckConnect(); + virtual void ReadLine(); +/** OLD SSL support. */ + virtual bool SSLCheckConnect(); +/** new SSL support */ + virtual bool SSLNegotiate() { return false; } + + void SetSSLConnecting(bool = true); + bool SSLConnecting(); +/** Enable the OnLine callback. Do not create your own OnRead + * callback when using this. */ + void SetLineProtocol(bool = true); + bool LineProtocol(); + void SetDeleteByHandler(bool = true); + bool DeleteByHandler(); + void SetCloseAndDelete(bool = true); + bool CloseAndDelete(); + void SetConnecting(bool = true); + bool Connecting(); + time_t GetConnectTime(); + +/** ipv4 and ipv6 */ + bool isip(const std::string&); +/** ipv4 */ + bool u2ip(const std::string&, ipaddr_t&); +/** ipv6 */ +#ifdef IPPROTO_IPV6 + bool u2ip(const std::string&, struct in6_addr&); +#endif +/** ipv4 */ + void l2ip(const ipaddr_t,std::string& ); +/** ipv6 */ +#ifdef IPPROTO_IPV6 + void l2ip(const struct in6_addr&,std::string& ,bool mixed = false); +#endif + +/** ipv4 and ipv6 */ + void SetRemoteAddress(struct sockaddr* sa,socklen_t); + void GetRemoteSocketAddress(struct sockaddr& sa,socklen_t& sa_len); +/** ipv4 */ + ipaddr_t GetRemoteIP4(); +/** ipv6 */ +#ifdef IPPROTO_IPV6 + struct in6_addr GetRemoteIP6(); +#endif +/** ipv4 and ipv6 */ + port_t GetRemotePort(); +/** ipv4 and ipv6 */ + std::string GetRemoteAddress(); +/** ipv4 and ipv6(not implemented) */ + std::string GetRemoteHostname(); + + SocketHandler& Handler() const; + bool SetNonblocking(bool); + bool SetNonblocking(bool, SOCKET); + + time_t Uptime() { return time(NULL) - m_tCreate; } + +/* + void SetTimeout(time_t x) { m_timeout = x; } + time_t Timeout() { return m_timeout; } + void Touch() { m_tActive = time(NULL); } + time_t Inactive() { return time(NULL) - m_tActive; } +*/ + virtual void OnDetached() // Threading + { + } + void SetDetach(bool x = true) { m_detach = x; } + bool IsDetach() { return m_detach; } + void SetDetached(bool x = true) { m_detached = x; } + bool IsDetached() { return m_detached; } + bool Detach(); + + void SetIpv6(bool x = true) { m_ipv6 = x; } + bool IsIpv6() { return m_ipv6; } + +/** Returns pointer to ListenSocket that created this instance + * on an incoming connections. */ + Socket *GetParent(); +/** Used by ListenSocket to set parent pointer of newly created + * socket instance. */ + void SetParent(Socket *); +/** Get listening port from ListenSocket<>. */ + virtual port_t GetPort(); + +// pooling + void SetIsClient() { m_bClient = true; } + void SetSocketType(int x) { m_socket_type = x; } + int GetSocketType() { return m_socket_type; } + void SetSocketProtocol(const std::string& x) { m_socket_protocol = x; } + const std::string& GetSocketProtocol() { return m_socket_protocol; } + void SetClientRemoteAddr(ipaddr_t a) { m_client_remote_addr = a; } + ipaddr_t& GetClientRemoteAddr() { return m_client_remote_addr; } + void SetClientRemotePort(port_t p) { m_client_remote_port = p; } + port_t GetClientRemotePort() { return m_client_remote_port; } + void SetRetain() { if (m_bClient) m_bRetain = true; } + bool Retain() { return m_bRetain; } + void SetLost() { m_bLost = true; } + bool Lost() { return m_bLost; } + void SetCallOnConnect(bool x = true) { m_call_on_connect = x; } + bool CallOnConnect() { return m_call_on_connect; } + +// copy connection parameters from sock + void CopyConnection(Socket *sock); + + void SetReuse(bool x) { m_opt_reuse = x; } + void SetKeepalive(bool x) { m_opt_keepalive = x; } + +// dns + int Resolve(const std::string& host,port_t port); + virtual void Resolved(int id,ipaddr_t,port_t); + +/** socket still in socks4 negotiation mode */ + bool Socks4() { return m_bSocks4; } + void SetSocks4(bool x = true) { m_bSocks4 = x; } + + void SetSocks4Host(ipaddr_t a) { m_socks4_host = a; } + void SetSocks4Host(const std::string& ); + void SetSocks4Port(port_t p) { m_socks4_port = p; } + void SetSocks4Userid(const std::string& x) { m_socks4_userid = x; } + ipaddr_t GetSocks4Host() { return m_socks4_host; } + port_t GetSocks4Port() { return m_socks4_port; } + const std::string& GetSocks4Userid() { return m_socks4_userid; } + + void SetConnectTimeout(int x) { m_connect_timeout = x; } + int GetConnectTimeout() { return m_connect_timeout; } + +/** SSL Enabled */ + bool IsSSL() { return m_b_enable_ssl; } + void EnableSSL(bool x = true) { m_b_enable_ssl = x; } +/** Still negotiating ssl connection */ + bool IsSSLNegotiate() { return m_b_ssl; } + void SetSSLNegotiate(bool x = true) { m_b_ssl = x; } +/** OnAccept called with SSL Enabled */ + bool IsSSLServer() { return m_b_ssl_server; } + void SetSSLServer(bool x = true) { m_b_ssl_server = x; } + + void DisableRead(bool x = true) { m_b_disable_read = x; } + bool IsDisableRead() { return m_b_disable_read; } + + protected: + Socket(const Socket& ); // do not allow use of copy constructor + void DetachSocket(); // protected, friend class SocketHandler; + + private: +/** default constructor not available */ + Socket() : m_handler(Handler()) {} +#ifdef _WIN32 + static WSAInitializer m_winsock_init; +#endif + Socket& operator=(const Socket& ) { return *this; } +// + SocketHandler& m_handler; + SOCKET m_socket; + bool m_bDel; + bool m_bClose; + bool m_bConnecting; + time_t m_tConnect; + time_t m_tCreate; + bool m_line_protocol; + bool m_ssl_connecting; +// time_t m_tActive; +// time_t m_timeout; + bool m_detach; + bool m_detached; + SocketThread *m_pThread; + bool m_ipv6; + struct sockaddr m_sa; // remote, from accept + socklen_t m_sa_len; + Socket *m_parent; +// pooling, ipv4 + int m_socket_type; + std::string m_socket_protocol; + bool m_bClient; // only client connections are pooled + ipaddr_t m_client_remote_addr; + port_t m_client_remote_port; + bool m_bRetain; // keep connection on close + bool m_bLost; // connection lost + bool m_call_on_connect; + bool m_opt_reuse; + bool m_opt_keepalive; + bool m_bSocks4; // socks4 negotiation mode (TcpSocket) + ipaddr_t m_socks4_host; + port_t m_socks4_port; + std::string m_socks4_userid; + int m_connect_timeout; + bool m_b_enable_ssl; + bool m_b_ssl; // ssl negotiation mode (TcpSocket) + bool m_b_ssl_server; + bool m_b_disable_read; +}; +#endif // _SOCKETBASE_H diff --git a/src/shared/Network/SocketHandler.cpp b/src/shared/Network/SocketHandler.cpp new file mode 100644 index 0000000..7f5c904 --- /dev/null +++ b/src/shared/Network/SocketHandler.cpp @@ -0,0 +1,603 @@ +/** + ** File ......... SocketHandler.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 +#ifdef _WIN32 +#pragma warning(disable:4786) +#include +#else +#include +#endif + +#include "TcpSocket.h" +#include "StdLog.h" +#include "SocketHandler.h" +#include "UdpSocket.h" +#include "PoolSocket.h" +#include "ResolvSocket.h" +#include "ResolvServer.h" + +#ifdef _DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +SocketHandler::SocketHandler(StdLog *p) +:m_stdlog(p) +,m_maxsock(0) +,m_host("") +,m_ip(0) +,m_preverror(-1) +,m_slave(false) +,m_local_resolved(false) +,m_socks4_host(0) +,m_socks4_port(0) +,m_bTryDirect(false) +,m_resolv_id(0) +,m_resolver(NULL) +{ + FD_ZERO(&m_rfds); + FD_ZERO(&m_wfds); + FD_ZERO(&m_efds); +} + + +SocketHandler::~SocketHandler() +{ + if (m_resolver) + m_resolver -> Quit(); + if (!m_slave) + { + for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) + { + Socket *p = (*it).second; + p -> Close(); +// p -> OnDelete(); // hey, I turn this back on. what's the worst that could happen??!! +// MinionSocket breaks, calling MinderHandler methods in OnDelete - +// MinderHandler is already gone when that happens... + if (p -> DeleteByHandler()) + { + delete p; + } + } + } + if (m_resolver) + delete m_resolver; +} + + +void SocketHandler::ResolveLocal() +{ + char h[256]; + +// get local hostname and translate into ip-address + *h = 0; + gethostname(h,255); + { + Socket zl(*this); + if (zl.u2ip(h, m_ip)) + { + zl.l2ip(m_ip, m_addr); + } + } +#ifdef IPPROTO_IPV6 + memset(&m_local_ip6, 0, sizeof(m_local_ip6)); + { + Socket zl(*this); + zl.SetIpv6(); + if (zl.u2ip(h, m_local_ip6)) + { + zl.l2ip(m_local_ip6, m_local_addr6); + } + } +#endif + m_host = h; + m_local_resolved = true; +} + + +void SocketHandler::Add(Socket *p) +{ + if (p -> GetSocket() == INVALID_SOCKET) + { + LogError(p, "Add", -1, "Invalid socket", LOG_LEVEL_FATAL); + return; + } + DEB( printf("%s: add socket %d\n",m_slave ? "slave" : "master",p -> GetSocket());) + m_add[p -> GetSocket()] = p; +} + + +void SocketHandler::Get(SOCKET s,bool& r,bool& w,bool& e) +{ + if (s >= 0) + { + r = FD_ISSET(s, &m_rfds) ? true : false; + w = FD_ISSET(s, &m_wfds) ? true : false; + e = FD_ISSET(s, &m_efds) ? true : false; + } +} + + +void SocketHandler::Set(SOCKET s,bool bRead,bool bWrite,bool bException) +{ + if (s >= 0) + { + if (bRead) + { + if (!FD_ISSET(s, &m_rfds)) + { + FD_SET(s, &m_rfds); + } + } + else + { + FD_CLR(s, &m_rfds); + } + if (bWrite) + { + if (!FD_ISSET(s, &m_wfds)) + { + FD_SET(s, &m_wfds); + } + } + else + { + FD_CLR(s, &m_wfds); + } + if (bException) + { + if (!FD_ISSET(s, &m_efds)) + { + FD_SET(s, &m_efds); + } + } + else + { + FD_CLR(s, &m_efds); + } + } +} + + +int SocketHandler::Select(long sec,long usec) +{ + struct timeval tv; + int n; + + while (m_add.size() && m_sockets.size() < FD_SETSIZE ) + { + socket_m::iterator it = m_add.begin(); + SOCKET s = (*it).first; + Socket *p = (*it).second; +// call Open before Add'ing a socket... + if (p -> Connecting()) + { + Set(s,false,true); + } + else + { + if (p -> IsDisableRead()) + Set(s, false, false); + else + Set(s,true,false); + } + m_maxsock = (s > m_maxsock) ? s : m_maxsock; + m_sockets[s] = p; + m_add.erase(it); + } + +#ifdef __APPLE_CC__ + fd_set rfds; + fd_set wfds; + fd_set efds; + FD_COPY(&m_rfds, &rfds); + FD_COPY(&m_wfds, &wfds); + FD_COPY(&m_efds, &efds); +#else + fd_set rfds = m_rfds; + fd_set wfds = m_wfds; + fd_set efds = m_efds; +#endif + + tv.tv_sec = sec; + tv.tv_usec = usec; + + n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,&tv); + if (n == -1) + { + LogError(NULL, "select", Errno, StrError(Errno)); +#ifdef _WIN32 + DEB( + int errcode = Errno; + if (errcode != m_preverror) + { + printf(" select() errcode = %d\n",errcode); + m_preverror = errcode; + for (size_t i = 0; i <= m_maxsock; i++) + { + if (FD_ISSET(i, &m_rfds)) + printf("%4d: Read\n",i); + if (FD_ISSET(i, &m_wfds)) + printf("%4d: Write\n",i); + if (FD_ISSET(i, &m_efds)) + printf("%4d: Exception\n",i); + } + } + ) // DEB +#else + DEB( printf("slave: %s\n",m_slave ? "YES" : "NO"); + exit(-1);) + #endif + } + else +// if (n > 0) + { + for (socket_m::iterator it2 = m_sockets.begin(); it2 != m_sockets.end(); it2++) + { + SOCKET i = (*it2).first; + Socket *p = (*it2).second; + if (p) + { + if (p -> CallOnConnect() && p -> Ready() ) + { + if (p -> IsSSL()) // SSL Enabled socket + p -> OnSSLConnect(); + else + if (p -> Socks4()) + p -> OnSocks4Connect(); + else + p -> OnConnect(); + p -> SetCallOnConnect( false ); + } +// new SSL negotiate method + if (p -> IsSSLNegotiate()) + { + p -> SSLNegotiate(); + } + else +// old SSL method... + if (p -> SSLConnecting()) + { + if (p -> SSLCheckConnect()) + { + p -> OnSSLInitDone(); + } + } + else + if (n > 0) + { + if (FD_ISSET(i, &rfds)) + { + TcpSocket *tcp = (TcpSocket *)(p); +//TcpSocket *tcp = dynamic_cast(p); +// LockWrite (save total output buffer size) +// Sockets with write lock won't call OnWrite in SendBuf +// That will happen in UnlockWrite, if necessary + p -> OnRead(); + bool need_more = false; + while (tcp && p -> Socks4() && tcp -> GetInputLength() && !need_more && !p -> CloseAndDelete()) + { + need_more = p -> OnSocks4Read(); + } + if (!p -> Socks4()) + { + if (p -> LineProtocol()) + { + p -> ReadLine(); + } +// p -> Touch(); + } +// UnlockWrite (call OnWrite if saved size == 0 && total output buffer size > 0) + } + if (FD_ISSET(i, &wfds)) + { + if (p -> Connecting()) + { + if (p -> CheckConnect()) + { + if (p -> IsSSL()) // SSL Enabled socket + p -> OnSSLConnect(); + else + if (p -> Socks4()) + p -> OnSocks4Connect(); + else + p -> OnConnect(); + } + else + { +// failed + if (p -> Socks4()) + { + p -> OnSocks4ConnectFailed(); + } + else + { +// LogError(p, "connect failed", Errno, StrError(Errno), LOG_LEVEL_FATAL); + p -> SetCloseAndDelete( true ); + p -> OnConnectFailed(); + } + } +// p -> Touch(); + } + else + { + p -> OnWrite(); +// p -> Touch(); + } + } + if (FD_ISSET(i, &efds)) + { + p -> OnException(); + } + } + } // if (p) + } // for + } + + bool repeat; + do + { + repeat = false; + for (socket_m::iterator it3 = m_sockets.begin(); it3 != m_sockets.end(); it3++) + { +// SOCKET s = (*it3).first; + Socket *p = (*it3).second; + if (p) + { + if (!m_slave && p -> IsDetach()) + { + Set(p -> GetSocket(), false, false, false); + p -> DetachSocket(); + m_sockets.erase(it3); + repeat = true; + break; + } +/* + if (p && p -> Timeout() && p -> Inactive() > p -> Timeout()) + { + p -> SetCloseAndDelete(); + } +*/ + if (p && p -> Connecting() && p -> GetConnectTime() > p -> GetConnectTimeout() ) + { + LogError(p, "connect", -1, "connect timeout", LOG_LEVEL_FATAL); + if (p -> Socks4()) + { + p -> OnSocks4ConnectFailed(); +// retry direct connection + } + else + { + p -> SetCloseAndDelete(true); + p -> OnConnectFailed(); + } + } + if (p && p -> CloseAndDelete() ) + { +//DEB(printf("%s: calling Close for socket %d\n",m_slave ? "slave" : "master",s);) + if (p -> Retain() && !p -> Lost()) + { + PoolSocket *p2 = new PoolSocket(*this, p); + p2 -> SetDeleteByHandler(); + Add(p2); +//printf("Adding PoolSocket...\n"); + } + else + { + Set(p -> GetSocket(),false,false,false); + p -> Close(); + } + p -> OnDelete(); + if (p -> DeleteByHandler()) + { + delete p; + } + m_sockets.erase(it3); + repeat = true; + break; + } + } // if (p) + } + if (repeat) + { + m_maxsock = 0; + for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) + { + SOCKET s = (*it).first; + m_maxsock = s > m_maxsock ? s : m_maxsock; + } + for (socket_m::iterator it3 = m_add.begin(); it3 != m_add.end(); it3++) + { + SOCKET s = (*it3).first; + m_maxsock = s > m_maxsock ? s : m_maxsock; + } + } + } while (repeat); + return n; +} + + +const std::string& SocketHandler::GetLocalHostname() +{ + if (!m_local_resolved) + LogError(NULL, "GetLocalHostname", 0, "local address not resolved"); + return m_host; +} + + +ipaddr_t SocketHandler::GetLocalIP() +{ + if (!m_local_resolved) + LogError(NULL, "GetLocalHostname", 0, "local address not resolved"); + return m_ip; +} + + +const std::string& SocketHandler::GetLocalAddress() +{ + if (!m_local_resolved) + LogError(NULL, "GetLocalHostname", 0, "local address not resolved"); + return m_addr; +} + + +bool SocketHandler::Valid(Socket *p0) +{ + for (socket_m::iterator it3 = m_sockets.begin(); it3 != m_sockets.end(); it3++) + { + Socket *p = (*it3).second; + if (p0 == p) + return true; + } + return false; +} + + +void SocketHandler::RegStdLog(StdLog *x) +{ + m_stdlog = x; +} + + +bool SocketHandler::OkToAccept() +{ + return true; +} + + +size_t SocketHandler::GetCount() +{ + return m_sockets.size(); +} + + +void SocketHandler::SetSlave(bool x) +{ + m_slave = x; +} + + +void SocketHandler::LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t) +{ + if (m_stdlog) + { + m_stdlog -> error(this, p, user_text, err, sys_err, t); + } +} + + +#ifdef IPPROTO_IPV6 +const struct in6_addr& SocketHandler::GetLocalIP6() +{ + if (!m_local_resolved) + LogError(NULL, "GetLocalHostname", 0, "local address not resolved"); + return m_local_ip6; +} +#endif + +const std::string& SocketHandler::GetLocalAddress6() +{ + if (!m_local_resolved) + LogError(NULL, "GetLocalHostname", 0, "local address not resolved"); + return m_local_addr6; +} + + +PoolSocket *SocketHandler::FindConnection(int type,const std::string& protocol,ipaddr_t a,port_t port) +{ + for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end() && m_sockets.size(); it++) + { + PoolSocket *pools = (PoolSocket *)((*it).second); +//PoolSocket *pools = dynamic_cast((*it).second); + if (pools) + { + if (pools -> GetSocketType() == type && + pools -> GetSocketProtocol() == protocol && + pools -> GetClientRemoteAddr() == a && + pools -> GetClientRemotePort() == port) + { + DEB(printf("FindConnection() successful\n");) + m_sockets.erase(it); + pools -> SetRetain(); // avoid Close in Socket destructor + return pools; // Caller is responsible that this socket is deleted + } + } + } + DEB(printf("FindConnection() NOT successful\n");) + return NULL; +} + + +void SocketHandler::SetSocks4Host(ipaddr_t a) +{ + m_socks4_host = a; +} + + +void SocketHandler::SetSocks4Host(const std::string& host) +{ + Socket s(*this); + s.u2ip(host, m_socks4_host); +} + + +void SocketHandler::SetSocks4Port(port_t port) +{ + m_socks4_port = port; +} + + +void SocketHandler::SetSocks4Userid(const std::string& id) +{ + m_socks4_userid = id; +} + + +int SocketHandler::Resolve(Socket *p,const std::string& host,port_t port) +{ +// check cache + ResolvSocket *resolv = new ResolvSocket(*this, p); + resolv -> SetId(++m_resolv_id); + resolv -> SetHost(host); + resolv -> SetPort(port); + resolv -> SetDeleteByHandler(); + ipaddr_t local; + resolv -> u2ip("127.0.0.1", local); + if (!resolv -> Open(local, m_resolver_port)) + { + LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL); + } + Add(resolv); + return m_resolv_id; +} + + +void SocketHandler::EnableResolver(port_t port) +{ + if (!m_resolver) + { + m_resolver_port = port; + m_resolver = new ResolvServer(port); + } +} diff --git a/src/shared/Network/SocketHandler.h b/src/shared/Network/SocketHandler.h new file mode 100644 index 0000000..a0df2e2 --- /dev/null +++ b/src/shared/Network/SocketHandler.h @@ -0,0 +1,123 @@ +/** + ** File ......... SocketHandler.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _SOCKETHANDLER_H +#define _SOCKETHANDLER_H + +#include +#include + +#include "socket_include.h" +#include "StdLog.h" + +class Socket; +class PoolSocket; +class ResolvServer; + +class SocketHandler +{ +/** Map type for holding file descriptors/socket object pointers. */ + typedef std::map socket_m; + + public: + SocketHandler(StdLog * = NULL); + virtual ~SocketHandler(); + +/** Register StdLog object for error callback. */ + void RegStdLog(StdLog *); + void LogError(Socket *,const std::string&,int,const std::string&,loglevel_t = LOG_LEVEL_WARNING); + + void Add(Socket *); +/** Set read/write/exception file descriptor sets (fd_set). */ + void Set(SOCKET s,bool bRead,bool bWrite,bool bException = true); + int Select(long sec,long usec); + bool Valid(Socket *); +/** Override and return false to deny all incoming connections. */ + virtual bool OkToAccept(); +/** Get status of read/write/exception file descriptor set for a socket. */ + void Get(SOCKET s,bool& r,bool& w,bool& e); + +/** ResolveLocal (hostname) - call once before calling any GetLocal method. */ + void ResolveLocal(); + + const std::string& GetLocalHostname(); + ipaddr_t GetLocalIP(); + const std::string& GetLocalAddress(); + const struct in6_addr& GetLocalIP6(); + const std::string& GetLocalAddress6(); + +/** Return number of sockets handled by this handler. */ + size_t GetCount(); +/** Indicates that the handler runs under SocketThread. */ + void SetSlave(bool x = true); +/** Find available open connection (used by connection pool). */ + PoolSocket *FindConnection(int type,const std::string& protocol,ipaddr_t,port_t); + +/** Enable transparent Socks4 client support. */ + void SetSocks4Host(ipaddr_t); + void SetSocks4Host(const std::string& ); + void SetSocks4Port(port_t); + void SetSocks4Userid(const std::string& ); + void SetSocks4TryDirect(bool x = true) { m_bTryDirect = x; } + ipaddr_t GetSocks4Host() { return m_socks4_host; } + port_t GetSocks4Port() { return m_socks4_port; } + const std::string& GetSocks4Userid() { return m_socks4_userid; } + bool Socks4TryDirect() { return m_bTryDirect; } + +/** Enable asynchronous DNS. */ + void EnableResolver(port_t port = 16667); + bool ResolverEnabled() { return m_resolver ? true : false; } + int Resolve(Socket *,const std::string& host,port_t); + port_t GetResolverPort() { return m_resolver_port; } + + socket_m m_sockets; + protected: + + socket_m m_add; + + private: + SocketHandler(const SocketHandler& ) {} + SocketHandler& operator=(const SocketHandler& ) { return *this; } + StdLog *m_stdlog; + SOCKET m_maxsock; + std::string m_host; // local + ipaddr_t m_ip; // local + std::string m_addr; // local + fd_set m_rfds; + fd_set m_wfds; + fd_set m_efds; + int m_preverror; + bool m_slave; +#ifdef IPPROTO_IPV6 + struct in6_addr m_local_ip6; +#endif + std::string m_local_addr6; + bool m_local_resolved; + ipaddr_t m_socks4_host; + port_t m_socks4_port; + std::string m_socks4_userid; + bool m_bTryDirect; + int m_resolv_id; + ResolvServer *m_resolver; + port_t m_resolver_port; +}; +#endif // _SOCKETHANDLER_H diff --git a/src/shared/Network/SocketThread.cpp b/src/shared/Network/SocketThread.cpp new file mode 100644 index 0000000..3b33f64 --- /dev/null +++ b/src/shared/Network/SocketThread.cpp @@ -0,0 +1,64 @@ +/** + ** File ......... SocketThread.cpp + ** Published .... 2004-05-05 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#endif +#include "SocketHandler.h" +#include "SocketThread.h" + +//#define DEB(x) x; fflush(stdout); +#define DEB(x) + +SocketThread::SocketThread(Socket& p) +:Thread(false) +,m_socket(p) +{ +// Creator will release + DEB( printf("SocketThread()\n");) +} + + +SocketThread::~SocketThread() +{ + DEB( printf("~SocketThread()\n");) +} + + +void SocketThread::Run() +{ + SocketHandler h; + h.SetSlave(); + h.Add(&m_socket); + DEB( printf("slave: OnDetached()\n");) + m_socket.OnDetached(); + DEB( printf("slave: first select\n");) + h.Select(1,0); + while (h.GetCount()) //m_socket.Ready() && IsRunning()) + { + DEB( printf("slave: select\n");) + h.Select(1,0); + } +// m_socket now deleted oops + DEB( printf("slave: SetDetach( false )\n");) +// m_socket.SetDetach(false); +} diff --git a/src/shared/Network/SocketThread.h b/src/shared/Network/SocketThread.h new file mode 100644 index 0000000..b142ae4 --- /dev/null +++ b/src/shared/Network/SocketThread.h @@ -0,0 +1,43 @@ +/** + ** File ......... SocketThread.h + ** Published .... 2004-05-05 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _SOCKETTHREAD_H +#define _SOCKETTHREAD_H + +#include "Thread.h" +#include "Socket.h" + +class SocketThread : public Thread +{ + public: + SocketThread(Socket& p); + ~SocketThread(); + + void Run(); + + private: + Socket& GetSocket() const { return m_socket; } + SocketThread(const SocketThread& s) : m_socket(s.GetSocket()) {} + SocketThread& operator=(const SocketThread& ) { return *this; } + Socket& m_socket; +}; +#endif // _SOCKETTHREAD_H diff --git a/src/shared/Network/StdLog.h b/src/shared/Network/StdLog.h new file mode 100644 index 0000000..a0576b0 --- /dev/null +++ b/src/shared/Network/StdLog.h @@ -0,0 +1,48 @@ +/** + ** File ......... StdLog.h + ** Published .... 2004-06-01 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _STDLOG_H +#define _STDLOG_H + +#include + +typedef enum +{ + LOG_LEVEL_WARNING = 0, + LOG_LEVEL_ERROR, + LOG_LEVEL_FATAL, + LOG_LEVEL_INFO +} loglevel_t; + +class SocketHandler; +class Socket; + +class StdLog +{ + public: + virtual void error(SocketHandler *,Socket *, + const std::string& user_text, + int err, + const std::string& sys_err, + loglevel_t = LOG_LEVEL_WARNING) = 0; +}; +#endif // _STDLOG_H diff --git a/src/shared/Network/StdoutLog.cpp b/src/shared/Network/StdoutLog.cpp new file mode 100644 index 0000000..7601d6a --- /dev/null +++ b/src/shared/Network/StdoutLog.cpp @@ -0,0 +1,60 @@ +/** + ** File ......... StdoutLog.cpp + ** Published .... 2004-06-01 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#endif +#include +#include +#include "SocketHandler.h" +#include "Socket.h" +#include "StdoutLog.h" + +void StdoutLog::error(SocketHandler *,Socket *,const std::string& call,int err,const std::string& sys_err,loglevel_t lvl) +{ + time_t t = time(NULL); + struct tm *tp = localtime(&t); + std::string level; + + switch (lvl) + { + case LOG_LEVEL_WARNING: + level = "Warning"; + break; + case LOG_LEVEL_ERROR: + level = "Error"; + break; + case LOG_LEVEL_FATAL: + level = "Fatal"; + break; + case LOG_LEVEL_INFO: + level = "Info"; + break; + } + + printf("%d-%02d-%02d %02d:%02d:%02d :: %s: %d %s (%s)\n", + tp -> tm_year + 1900, + tp -> tm_mon + 1, + tp -> tm_mday, + tp -> tm_hour,tp -> tm_min,tp -> tm_sec, + call.c_str(),err,sys_err.c_str(),level.c_str()); +} diff --git a/src/shared/Network/StdoutLog.h b/src/shared/Network/StdoutLog.h new file mode 100644 index 0000000..85198cb --- /dev/null +++ b/src/shared/Network/StdoutLog.h @@ -0,0 +1,33 @@ +/** + ** File ......... StdoutLog.h + ** Published .... 2004-06-01 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _STDOUTLOG_H +#define _STDOUTLOG_H + +#include "StdLog.h" + +class StdoutLog : public StdLog +{ + public: + void error(SocketHandler *,Socket *,const std::string& call,int err,const std::string& sys_err,loglevel_t); +}; +#endif // _STDOUTLOG_H diff --git a/src/shared/Network/TcpSocket.cpp b/src/shared/Network/TcpSocket.cpp new file mode 100644 index 0000000..0b2940b --- /dev/null +++ b/src/shared/Network/TcpSocket.cpp @@ -0,0 +1,1025 @@ +/** + ** File ......... TcpSocket.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 "Platform/Define.h" + +#ifdef _WIN32 +#pragma warning(disable:4786) +#define strcasecmp stricmp +#include +#else +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_OPENSSL +#include +#endif + +#include "SocketHandler.h" +#include "TcpSocket.h" +#include "PoolSocket.h" + +#ifdef _DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#ifdef HAVE_OPENSSL +BIO *TcpSocket::bio_err = NULL; +std::string TcpSocket::m_password; +#endif + +// thanks, q +#ifdef _WIN32 +#pragma warning(disable:4355) +#endif +TcpSocket::TcpSocket(SocketHandler& h) : Socket(h) +,ibuf(*this, TCP_BUFSIZE_READ) +//,obuf(*this, 32768) +,obuf(*this, 131070) +,m_line("") +,m_socks4_state(0) +,m_resolver_id(0) +#ifdef HAVE_OPENSSL +,m_context(NULL) +,m_ssl(NULL) +,m_sbio(NULL) +#endif +{ +} + + +#ifdef _WIN32 +#pragma warning(default:4355) +#endif + +#ifdef _WIN32 +#pragma warning(disable:4355) +#endif +TcpSocket::TcpSocket(SocketHandler& h,size_t isize,size_t osize) : Socket(h) +,ibuf(*this, isize) +,obuf(*this, osize) +,m_line("") +,m_socks4_state(0) +,m_resolver_id(0) +#ifdef HAVE_OPENSSL +,m_context(NULL) +,m_ssl(NULL) +,m_sbio(NULL) +#endif +{ +} + + +#ifdef _WIN32 +#pragma warning(default:4355) +#endif + +#if COMPILER == COMPILER_MICROSOFT +#define vsnprintf _vsnprintf +#endif + +TcpSocket::~TcpSocket() +{ +#ifdef HAVE_OPENSSL + if (m_ssl) + { + DEB( printf("SSL_free()\n");) + SSL_free(m_ssl); + } + if (m_context) + { + DEB( printf("SSL_CTX_free()\n");) + SSL_CTX_free(m_context); + } +#endif +} + + +bool TcpSocket::Open(ipaddr_t ip,port_t port,bool skip_socks) +{ + SetConnecting(false); + SetSocks4(false); +// check for pooling + PoolSocket *pools = Handler().FindConnection(SOCK_STREAM, "tcp", ip, port); + if (pools) + { + CopyConnection( pools ); + delete pools; + + SetIsClient(); + SetCallOnConnect(); // SocketHandler must call OnConnect + DEB(printf("Reusing connection\n");) + return true; + } +// if not, create new connection + SOCKET s = CreateSocket4(SOCK_STREAM, "tcp"); + if (s == INVALID_SOCKET) + { + return false; + } +// socket must be nonblocking for async connect + if (!SetNonblocking(true, s)) + { + closesocket(s); + return false; + } + SetIsClient(); // client because we connect + SetClientRemoteAddr(ip); + SetClientRemotePort(port); + struct sockaddr_in sa; +// size of sockaddr struct + socklen_t sa_len = sizeof(sa); + if (!skip_socks && GetSocks4Host() && GetSocks4Port()) + { + memset(&sa, 0, sa_len); + sa.sin_family = AF_INET; + sa.sin_port = htons(GetSocks4Port()); + ipaddr_t a = GetSocks4Host(); + memcpy(&sa.sin_addr, &a, 4); + { + char slask[100]; + sprintf(slask,"Connecting to socks4 server @ %08x:%d",GetSocks4Host(),GetSocks4Port()); + Handler().LogError(this, "Open", 0, slask, LOG_LEVEL_INFO); + } + SetSocks4(); + } + else + { +// setup sockaddr struct + memset(&sa,0,sa_len); + sa.sin_family = AF_INET; // hp -> h_addrtype; + sa.sin_port = htons( port ); + memcpy(&sa.sin_addr,&ip,4); + } +// try connect + int n = connect(s, (struct sockaddr *)&sa, sa_len); + if (n == -1) + { +// check error code that means a connect is in progress +#ifdef _WIN32 + if (Errno == WSAEWOULDBLOCK) +#else + if (Errno == EINPROGRESS) +#endif + { + SetConnecting( true ); // this flag will control fd_set's + } + else +// retry + if (Socks4() && Handler().Socks4TryDirect() ) + { + closesocket(s); + return Open(ip, port, true); + } + else + { + Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return false; + } + } + else + { + SetCallOnConnect(); // SocketHandler must call OnConnect + } + SetRemoteAddress( (struct sockaddr *)&sa,sa_len); + Attach(s); + +// 'true' means connected or connecting(not yet connected) +// 'false' means something failed + return true; //!Connecting(); +} + + +bool TcpSocket::Open(const std::string &host,port_t port) +{ + if (!Handler().ResolverEnabled() || isip(host) ) + { + ipaddr_t l; + if (!u2ip(host,l)) + { + return false; + } + return Open(l, port); + } +// resolve using async resolver thread + m_resolver_id = Resolve(host, port); + return true; +} + + +void TcpSocket::Resolved(int id,ipaddr_t a,port_t port) +{ + if (id == m_resolver_id) + { + if (a && port) + { + Open(a, port); + if (!Handler().Valid(this)) + { + Handler().Add(this); + } + return; + } + else + { + Handler().LogError(this, "Resolved", 0, "Resolver failed", LOG_LEVEL_FATAL); + } + } + else + { + Handler().LogError(this, "Resolved", id, "Resolver returned wrong job id", LOG_LEVEL_FATAL); + } + SetCloseAndDelete(); +} + + +// halfbaked IPV6 code +#ifdef IPPROTO_IPV6 +bool TcpSocket::Open6(const std::string &host,port_t port) +{ +// check for pooling + +// if not, create new connection + SOCKET s = CreateSocket6(SOCK_STREAM, "tcp"); + if (s == INVALID_SOCKET) + { + return false; + } + struct in6_addr a; + if (u2ip(host,a)) + { + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( port ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; + sa.sin6_addr = a; + + if (!SetNonblocking(true, s)) + { + closesocket(s); + return false; + } + int n = connect(s, (struct sockaddr *)&sa, sa_len); + if (n == -1) + { +#ifdef _WIN32 + if (Errno != WSAEWOULDBLOCK) +#else + if (Errno != EINPROGRESS) +#endif + { + Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL); + closesocket(s); + return false; + } + else + { + SetConnecting(true); + } + } + else + { + SetCallOnConnect(); // SocketHandler must call OnConnect + } + SetRemoteAddress((struct sockaddr *)&sa,sa_len); + Attach(s); + return true; //!Connecting(); + } + return false; // u2ip failed +} +#endif + +void TcpSocket::OnRead() +{ + if (IsSSL()) + { +#ifdef HAVE_OPENSSL + DEB( printf("TcpSocket(SSL)::OnRead()\n");) + if (!Ready()) + return; + char buf[TCP_BUFSIZE_READ]; + int n = SSL_read(m_ssl, buf, TCP_BUFSIZE_READ); + if (n == -1) + { + n = SSL_get_error(m_ssl, n); + switch (n) + { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_ZERO_RETURN: + DEB( printf("SSL_read() returns zero - closing socket\n");) + SetCloseAndDelete(true); + break; + default: + DEB( printf("SSL read problem, errcode = %d\n",n);) + SetCloseAndDelete(true); // %! + } + } + else + if (!n) + { + SetCloseAndDelete(true); + DEB( printf("read() returns 0\n");) + } + else + { + DEB( printf("TcpSocket(SSL) OnRead read %d bytes\n",n);) + if (!ibuf.Write(buf,n)) + { +// overflow + DEB( printf(" *** overflow ibuf Write\n");) + } + } + return; +#endif // HAVE_OPENSSL + } +// DEB(printf("TcpSocket::OnRead()\n");) + int n = (int)ibuf.Space(); + char buf[TCP_BUFSIZE_READ]; +// if (!n) +// return; // bad + n = TCP_BUFSIZE_READ; // %! patch away + n = recv(GetSocket(),buf,(n < TCP_BUFSIZE_READ) ? n : TCP_BUFSIZE_READ,MSG_NOSIGNAL); + if (n == -1) + { + Handler().LogError(this, "read", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(true); // %! + SetLost(); + } + else + if (!n) + { + Handler().LogError(this, "read", 0, "read returns 0", LOG_LEVEL_FATAL); + SetCloseAndDelete(true); + SetLost(); + } + else + { + OnRawData(buf,n); + if (!ibuf.Write(buf,n)) + { +// overflow + Handler().LogError(this, "read", 0, "ibuf overflow", LOG_LEVEL_WARNING); + } + } +} + + +void TcpSocket::OnWrite() +{ + if (IsSSL()) + { +#ifdef HAVE_OPENSSL +/* + if (!Handler().Valid(this)) + return; + if (!Ready()) + return; +*/ + DEB( printf("TcpSocket(SSL)::OnWrite()\n");) +// TODO: check MES buffer + int n = SSL_write(m_ssl,obuf.GetStart(),obuf.GetL()); + DEB( printf("OnWrite: %d bytes sent\n",n);) + if (n == -1) + { +// check code + SetCloseAndDelete(true); + DEB( perror("write() error");) + } + else + if (!n) + { + SetCloseAndDelete(true); + DEB( printf("write() returns 0\n");) + } + else + { + DEB( printf(" %d bytes written\n",n);) + obuf.Remove(n); + } + { + bool br; + bool bw; + bool bx; + Handler().Get(GetSocket(), br, bw, bx); + if (obuf.GetLength()) + Set(br, true); + else + Set(br, false); + } + return; +#endif // HAVE_OPENSSL + } +/* + assert(GetSocket() != INVALID_SOCKET); + if (obuf.GetL() <= 0) + { +printf("OnWrite abort because: nothing to write\n"); + Set(true, false); + return; + } + assert(obuf.GetL() > 0); + if (!Handler().Valid(this)) + { +printf("OnWrite abort because: not valid\n"); +return; +} +if (!Ready()) +{ +printf("OnWrite abort because: not ready\n"); +return; +} +*/ + int n = send(GetSocket(),obuf.GetStart(),(int)obuf.GetL(),MSG_NOSIGNAL); +/* +When writing onto a connection-oriented socket that has been shut down (by the local +or the remote end) SIGPIPE is sent to the writing process and EPIPE is returned. The +signal is not sent when the write call specified the MSG_NOSIGNAL flag. +*/ + if (n == -1) + { +// normal error codes: +// WSAEWOULDBLOCK +// EAGAIN or EWOULDBLOCK +#ifdef _WIN32 + if (Errno != WSAEWOULDBLOCK) +#else + if (Errno != EWOULDBLOCK) +#endif + { + Handler().LogError(this, "write", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(true); // %! + SetLost(); + } + } + else + if (!n) + { +// SetCloseAndDelete(true); + } + else + { + obuf.Remove(n); + } +// check m_mes + while (obuf.Space() && m_mes.size()) + { + ucharp_v::iterator it = m_mes.begin(); + MES *p = *it; //m_mes[0]; + if (obuf.Space() > p -> left()) + { + obuf.Write(p -> curbuf(),p -> left()); + delete p; +//printf("\n m_mes erase()\n"); + m_mes.erase(m_mes.begin()); + } + else + { + size_t sz = obuf.Space(); + obuf.Write(p -> curbuf(),sz); + p -> ptr += sz; + } + } + { + bool br; + bool bw; + bool bx; + Handler().Get(GetSocket(), br, bw, bx); + if (obuf.GetLength()) + Set(br, true); + else + { + Set(br, false); +// OnWriteComplete(); + } + } +} + + +void TcpSocket::Send(const std::string &str) +{ + SendBuf(str.c_str(),str.size()); +} + + +void TcpSocket::SendBuf(const char *buf,size_t len) +{ + int n = (int)obuf.GetLength(); + if (!Ready()) + { +// warning + Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); +// if (m_socket != INVALID_SOCKET && !Connecting() && !CloseAndDelete()) +// Handler().LogError(this, "SendBuf: Data to Write", len, static_cast(buf).substr(0,len).c_str(), LOG_LEVEL_INFO); + if (GetSocket() == INVALID_SOCKET) + Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO); + if (Connecting()) + Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO); + if (CloseAndDelete()) + Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO); + return; + } +//DEB( printf("trying to send %d bytes; buf before = %d bytes\n",len,n);) + if (m_mes.size() || len > obuf.Space()) + { + MES *p = new MES(buf,len); + m_mes.push_back(p); + } + if (m_mes.size()) + { + while (obuf.Space() && m_mes.size()) + { + ucharp_v::iterator it = m_mes.begin(); + MES *p = *it; //m_mes[0]; + if (obuf.Space() > p -> left()) + { + obuf.Write(p -> curbuf(),p -> left()); + delete p; + m_mes.erase(m_mes.begin()); + } + else + { + size_t sz = obuf.Space(); + obuf.Write(p -> curbuf(),sz); + p -> ptr += sz; + } + } + } + else + { + if (!obuf.Write(buf,len)) + { + Handler().LogError(this, "SendBuf", -1, "Send overflow" ); +// overflow + } + } + if (!n) + { + OnWrite(); + } +} + + +void TcpSocket::OnLine(const std::string& ) +{ +} + + +void TcpSocket::ReadLine() +{ + if (ibuf.GetLength()) + { + size_t x = 0; + size_t n = ibuf.GetLength(); + char tmp[TCP_BUFSIZE_READ + 1]; + + n = (n >= TCP_BUFSIZE_READ) ? TCP_BUFSIZE_READ : n; + ibuf.Read(tmp,n); + tmp[n] = 0; + + for (size_t i = 0; i < n; i++) + { + while (tmp[i] == 13 || tmp[i] == 10) + { + char c = tmp[i]; + tmp[i] = 0; + if (tmp[x]) + { + m_line += (tmp + x); + } + OnLine( m_line ); + i++; + if (i < n && (tmp[i] == 13 || tmp[i] == 10) && tmp[i] != c) + { + i++; + } + x = i; + m_line = ""; + } + } + if (tmp[x]) + { + m_line += (tmp + x); + } + } +} + + +#ifdef _WIN32 +#pragma warning(disable:4355) +#endif +TcpSocket::TcpSocket(const TcpSocket& s) +:Socket(s) +,ibuf(*this,0) +,obuf(*this,0) +{ +} + + +#ifdef _WIN32 +#pragma warning(default:4355) +#endif + +void TcpSocket::OnSocks4Connect() +{ + char request[1000]; + request[0] = 4; // socks v4 + request[1] = 1; // command code: CONNECT +// send port in network byte order + unsigned short port = htons(GetClientRemotePort()); + memcpy(request + 2, &port, 2); +// ipaddr_t is already in network byte order + memcpy(request + 4, &GetClientRemoteAddr(), 4); + strcpy(request + 8, GetSocks4Userid().c_str()); + size_t length = GetSocks4Userid().size() + 8 + 1; + SendBuf(request, length); + m_socks4_state = 0; +} + + +void TcpSocket::OnSocks4ConnectFailed() +{ + Handler().LogError(this,"OnSocks4ConnectFailed",0,"connection to socks4 server failed, trying direct connection",LOG_LEVEL_WARNING); + if (!Handler().Socks4TryDirect()) + { + SetCloseAndDelete(); + OnConnectFailed(); // just in case + } + else + { + closesocket(GetSocket()); +// open directly + Open(GetClientRemoteAddr(), GetClientRemotePort(), true); + } +} + + +bool TcpSocket::OnSocks4Read() +{ + switch (m_socks4_state) + { + case 0: + ibuf.Read(&m_socks4_vn, 1); + m_socks4_state = 1; + break; + case 1: + ibuf.Read(&m_socks4_cd, 1); + m_socks4_state = 2; + break; + case 2: + if (GetInputLength() > 1) + { + ibuf.Read( (char *)&m_socks4_dstport, 2); + m_socks4_state = 3; + } + else + { + return true; + } + break; + case 3: + if (GetInputLength() > 3) + { + ibuf.Read( (char *)&m_socks4_dstip, 4); + SetSocks4(false); + + switch (m_socks4_cd) + { + case 90: + OnConnect(); + break; + case 91: + case 92: + case 93: + Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server reports connect failed",LOG_LEVEL_FATAL); + SetCloseAndDelete(); + OnConnectFailed(); + break; + default: + Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server unrecognized response",LOG_LEVEL_FATAL); + SetCloseAndDelete(); + break; + } + } + else + { + return true; + } + break; + } + return false; +} + + +void TcpSocket::Sendf(char const *format, ...) +{ + va_list ap; + va_start(ap, format); + char slask[5000]; + vsnprintf(slask, 5000, format, ap); + va_end(ap); + Send( slask ); +} + + +void TcpSocket::OnSSLConnect() +{ +#ifdef HAVE_OPENSSL + DEB( printf("TcpSocket(SSL)::OnConnect()\n");) + SetNonblocking(true); + { + if (m_context) + { + DEB( printf("SSL Context already initialized - closing socket\n");) + SetCloseAndDelete(true); + return; + } + DEB( printf("InitSSLClient()\n");) + InitSSLClient(); + } + if (m_context) + { +/* Connect the SSL socket */ + m_ssl = SSL_new(m_context); + if (!m_ssl) + { + DEB( printf(" m_ssl is NULL\n");) + } + m_sbio = BIO_new_socket(GetSocket(), BIO_NOCLOSE); + if (!m_sbio) + { + DEB( printf(" m_sbio is NULL\n");) + } + SSL_set_bio(m_ssl, m_sbio, m_sbio); + if (!SSLNegotiate()) + SetSSLNegotiate(); + } + else + { + SetCloseAndDelete(); + } +#endif +} + + +void TcpSocket::OnSSLAccept() +{ +#ifdef HAVE_OPENSSL + DEB( printf("TcpSocket(SSL)::OnAccept()\n");) + SetNonblocking(true); + { + if (m_context) + { + DEB( printf("SSL Context already initialized - closing socket\n");) + SetCloseAndDelete(true); + return; + } + InitSSLServer(); + SetSSLServer(); + } + if (m_context) + { + m_ssl = SSL_new(m_context); + if (!m_ssl) + { + DEB( printf(" m_ssl is NULL\n");) + } + m_sbio = BIO_new_socket(GetSocket(), BIO_NOCLOSE); + if (!m_sbio) + { + DEB( printf(" m_sbio is NULL\n");) + } + SSL_set_bio(m_ssl, m_sbio, m_sbio); + if (!SSLNegotiate()) + SetSSLNegotiate(); + } +#endif +} + + +bool TcpSocket::SSLNegotiate() +{ +#ifdef HAVE_OPENSSL + if (!IsSSLServer()) // client + { + DEB( printf("TcpSocket::SSLNegotiate() is_client\n");) + int r = SSL_connect(m_ssl); + DEB( printf(" SSLNegotiate is_client, SSL_connect returns %d\n",r);) + if (r > 0) + { + SetSSLNegotiate(false); +// TODO: resurrect certificate check... client +// CheckCertificateChain( "");//ServerHOST); + SetNonblocking(false); + DEB( printf("TcpSocket::SSLNegotiate() init OK\n");) + OnConnect(); + return true; + } + else + if (!r) + { + SetSSLNegotiate(false); + SetCloseAndDelete(); + } + else + { + r = SSL_get_error(m_ssl, r); + if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) + { + DEB( printf("SSL_connect() failed - closing socket, return code: %d\n",r);) + SetSSLNegotiate(false); + SetCloseAndDelete(true); + } + } + } + else // server + { + DEB( printf("TcpSocket::SSLNegotiate() is_server\n");) + int r = SSL_accept(m_ssl); + DEB( printf(" SSLNegotiate is_server, SSL_accept returns %d\n",r);) + if (r > 0) + { + SetSSLNegotiate(false); +// TODO: resurrect certificate check... server +// CheckCertificateChain( "");//ClientHOST); + SetNonblocking(false); + DEB( printf("TcpSocket::SSLNegotiate() init OK\n");) + OnAccept(); + return true; + } + else + if (!r) + { + SetSSLNegotiate(false); + SetCloseAndDelete(); + } + else + { + r = SSL_get_error(m_ssl, r); + if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) + { + DEB( printf("SSL_accept() failed - closing socket, return code: %d\n",r);) + SetSSLNegotiate(false); + SetCloseAndDelete(true); + } + } + } +#endif // HAVE_OPENSSL + return false; +} + + +void TcpSocket::InitSSLClient() +{ +#ifdef HAVE_OPENSSL +// InitializeContext(); + InitializeContext(SSLv23_method()); +#endif +} + + +void TcpSocket::InitSSLServer() +{ +} + + +#ifdef HAVE_OPENSSL +void TcpSocket::InitializeContext(SSL_METHOD *meth_in) +{ + SSL_METHOD *meth; + + if (!bio_err) + { +/* An error write context */ + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + +/* Global system initialization*/ + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + } + +/* Create our context*/ + meth = meth_in ? meth_in : SSLv3_method(); + m_context = SSL_CTX_new(meth); + +/* Load the CAs we trust*/ +/* + if (!(SSL_CTX_load_verify_locations(m_context, CA_LIST, 0))) + { +DEB( printf("Couldn't read CA list\n");) + } + SSL_CTX_set_verify_depth(m_context, 1); + SSL_CTX_set_verify(m_context, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb); +*/ + +/* Load randomness */ + if (!(RAND_load_file(RANDOM, 1024*1024))) + { + DEB( printf("Couldn't load randomness\n");) + } + +} + + +void TcpSocket::InitializeContext(const std::string& keyfile,const std::string& password,SSL_METHOD *meth_in) +{ + SSL_METHOD *meth; + + if (!bio_err) + { +/* An error write context */ + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + +/* Global system initialization*/ + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + } + +/* Create our context*/ + meth = meth_in ? meth_in : SSLv3_method(); + m_context = SSL_CTX_new(meth); + +/* Load our keys and certificates*/ + if (!(SSL_CTX_use_certificate_file(m_context, keyfile.c_str(), SSL_FILETYPE_PEM))) + { + DEB( printf("Couldn't read certificate file\n");) + } + + m_password = password; + SSL_CTX_set_default_passwd_cb(m_context, password_cb); + if (!(SSL_CTX_use_PrivateKey_file(m_context, keyfile.c_str(), SSL_FILETYPE_PEM))) + { + DEB( printf("Couldn't read key file\n");) + } + +/* Load the CAs we trust*/ +/* + if (!(SSL_CTX_load_verify_locations(m_context, CA_LIST, 0))) + { +DEB( printf("Couldn't read CA list\n");) + } + SSL_CTX_set_verify_depth(m_context, 1); + SSL_CTX_set_verify(m_context, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb); +*/ + +/* Load randomness */ + if (!(RAND_load_file(RANDOM, 1024*1024))) + { + DEB( printf("Couldn't load randomness\n");) + } + +} + + +// static +int TcpSocket::password_cb(char *buf,int num,int rwflag,void *userdata) +{ + if ( (size_t)num < m_password.size() + 1) + { + return 0; + } + strcpy(buf,m_password.c_str()); + return m_password.size(); +} +#endif // HAVE_OPENSSL + +int TcpSocket::Close() +{ +#ifdef HAVE_OPENSSL + if (IsSSL()) + SSL_shutdown(m_ssl); +#endif + return Socket::Close(); +} diff --git a/src/shared/Network/TcpSocket.h b/src/shared/Network/TcpSocket.h new file mode 100644 index 0000000..1da96bf --- /dev/null +++ b/src/shared/Network/TcpSocket.h @@ -0,0 +1,136 @@ +/** + ** File ......... TcpSocket.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _TCPSOCKET_H +#define _TCPSOCKET_H + +#include "Socket.h" +#include "CircularBuffer.h" +#ifdef HAVE_OPENSSL +#include +#ifdef _WIN32 +// TODO: systray.exe?? +#define RANDOM "systray.exe" +#else +#define RANDOM "/dev/urandom" +#endif +#endif + +#define TCP_BUFSIZE_READ 131070 + +class TcpSocket : public Socket +{ + struct MES + { + MES( const char *buf_in,size_t len_in) + :buf(new char[len_in]) + ,len(len_in) + ,ptr(0) + { + memcpy(buf,buf_in,len); + } + ~MES() { delete[] buf; } + size_t left() { return len - ptr; } + char *curbuf() { return buf + ptr; } + char *buf; + size_t len; + size_t ptr; + }; + typedef std::list ucharp_v; + + public: + TcpSocket(SocketHandler& ); + TcpSocket(SocketHandler& ,size_t isize,size_t osize); + ~TcpSocket(); + +/** If you want your socket to connect to a server, + always call Open before Add'ing a socket to the sockethandler. + If not, the connection attempt will not be monitored by the + socket handler... */ + bool Open(ipaddr_t,port_t,bool skip_socks = false); + bool Open(const std::string &host,port_t port); + bool Open6(const std::string& host,port_t port); + int Close(); + + void Send(const std::string &); + void Sendf(char const *format, ...); + + virtual void SendBuf(const char *,size_t); + virtual void OnRawData(const char *,size_t) {} + + size_t GetInputLength() { return ibuf.GetLength(); } + size_t GetOutputLength() { return obuf.GetLength(); } + + void ReadLine(); + virtual void OnLine(const std::string& ); + + unsigned long GetBytesReceived() { return ibuf.ByteCounter(); } + unsigned long GetBytesSent() { return obuf.ByteCounter(); } + + void OnSocks4Connect(); + void OnSocks4ConnectFailed(); +/** returns 'need_more' */ + bool OnSocks4Read(); + + void Resolved(int id,ipaddr_t a,port_t port); + +// SSL + void OnSSLConnect(); + void OnSSLAccept(); + virtual void InitSSLClient(); + virtual void InitSSLServer(); + + protected: + TcpSocket(const TcpSocket& s); + void OnRead(); + void OnWrite(); +// SSL +#ifdef HAVE_OPENSSL + void InitializeContext(SSL_METHOD * = NULL); + void InitializeContext(const std::string& keyfile,const std::string& password,SSL_METHOD * = NULL); + static int password_cb(char *buf,int num,int rwflag,void *userdata); +#endif + bool SSLNegotiate(); +// + CircularBuffer ibuf; + CircularBuffer obuf; + std::string m_line; + ucharp_v m_mes; // overflow protection + + private: + TcpSocket& operator=(const TcpSocket& ) { return *this; } + int m_socks4_state; + char m_socks4_vn; + char m_socks4_cd; + unsigned short m_socks4_dstport; + unsigned long m_socks4_dstip; + int m_resolver_id; +// SSL +#ifdef HAVE_OPENSSL + SSL_CTX *m_context; + SSL *m_ssl; + BIO *m_sbio; + static BIO *bio_err; + static std::string m_password; +#endif +}; +#endif // _TCPSOCKET_H diff --git a/src/shared/Network/Thread.cpp b/src/shared/Network/Thread.cpp new file mode 100644 index 0000000..dbde865 --- /dev/null +++ b/src/shared/Network/Thread.cpp @@ -0,0 +1,128 @@ +/** + ** File ......... Thread.cpp + ** Published .... 2004-10-30 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 +#ifdef _WIN32 +#include "socket_include.h" +#else +#include +#endif + +#include "Thread.h" + +#ifndef __GNUC__ + +// UQ1: warning C4311: 'type cast' : pointer truncation +#pragma warning(disable:4311) + +#endif + +Thread::Thread(bool release) +:m_thread(0) +,m_running(true) +,m_release(false) +{ +#ifdef _WIN32 + m_thread = ::CreateThread(NULL, 0, StartThread, this, 0, &m_dwThreadId); +#else + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + if (pthread_create(&m_thread,&attr,StartThread,this) == -1) + { + perror("Thread: create failed"); + SetRunning(false); + } +// pthread_attr_destroy(&attr); +#endif + m_release = release; +} + + +Thread::~Thread() +{ +// while (m_running || m_thread) + if (m_running) + { + SetRunning(false); + SetRelease(true); + +#ifdef _WIN32 + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; + select(0,NULL,NULL,NULL,&tv); + ::CloseHandle(m_thread); +#else + sleep(1); +#endif + } +} + + +threadfunc_t STDPREFIX Thread::StartThread(threadparam_t zz) +{ + Thread *pclThread = (Thread *)zz; + + while (pclThread -> m_running && !pclThread -> m_release) + { +#ifdef _WIN32 + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; + select(0,NULL,NULL,NULL,&tv); +#else + sleep(1); +#endif + } + if (pclThread -> m_running) + { + pclThread -> Run(); + } + pclThread -> SetRunning(false); // if return + return (threadfunc_t)zz; +} + + +bool Thread::IsRunning() +{ + return m_running; +} + + +void Thread::SetRunning(bool x) +{ + m_running = x; +} + + +bool Thread::IsReleased() +{ + return m_release; +} + + +void Thread::SetRelease(bool x) +{ + m_release = x; +} diff --git a/src/shared/Network/Thread.h b/src/shared/Network/Thread.h new file mode 100644 index 0000000..22f756c --- /dev/null +++ b/src/shared/Network/Thread.h @@ -0,0 +1,66 @@ +/** + ** File ......... Thread.h + ** Published .... 2004-10-30 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _THREAD_H +#define _THREAD_H + +#ifdef _WIN32 +// to be +typedef DWORD threadfunc_t; +typedef LPVOID threadparam_t; +#define STDPREFIX WINAPI +#else +#include + +typedef void * threadfunc_t; +typedef void * threadparam_t; +#define STDPREFIX +#endif + +class Thread +{ + public: + Thread(bool release = true); + virtual ~Thread(); + + static threadfunc_t STDPREFIX StartThread(threadparam_t); + + virtual void Run() = 0; + + bool IsRunning(); + void SetRunning(bool x); + bool IsReleased(); + void SetRelease(bool x); + + private: + Thread(const Thread& ) {} + Thread& operator=(const Thread& ) { return *this; } +#ifdef _WIN32 + HANDLE m_thread; + DWORD m_dwThreadId; +#else + pthread_t m_thread; +#endif + bool m_running; + bool m_release; +}; +#endif // _THREAD_H diff --git a/src/shared/Network/UdpSocket.cpp b/src/shared/Network/UdpSocket.cpp new file mode 100644 index 0000000..9dd6612 --- /dev/null +++ b/src/shared/Network/UdpSocket.cpp @@ -0,0 +1,640 @@ +/** + ** File ......... UdpSocket.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _WIN32 +#pragma warning(disable:4786) +#include +#else +#include +#endif +#include +#include + +#include "StdLog.h" +#include "SocketHandler.h" +#include "UdpSocket.h" +// include this to see strange sights +//#include + +#ifdef _DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +UdpSocket::UdpSocket(SocketHandler& h,int ibufsz) : Socket(h) +,m_connected(false) +,m_ibuf(new char[ibufsz]) +,m_ibufsz(ibufsz) +{ +} + + +UdpSocket::~UdpSocket() +{ + delete[] m_ibuf; +} + + +SOCKET UdpSocket::Bind(port_t &port,int range) +{ + SOCKET s = GetSocket(); + if (s == INVALID_SOCKET) + { + s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return s; + } + Attach(s); + } + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + ipaddr_t l = 0; + + memset(&sa,0,sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port ); + memmove(&sa.sin_addr,&l,4); + + int n = bind(s, (struct sockaddr *)&sa, sa_len); + int tries = range; + while (n == -1 && tries--) + { + sa.sin_port = htons( ++port ); + n = bind(s, (struct sockaddr *)&sa, sa_len); + } + if (n == -1) + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(); + Close(); + return INVALID_SOCKET; + } + return s; +} + + +#ifdef IPPROTO_IPV6 +SOCKET UdpSocket::Bind6(port_t &port,int range) +{ + SOCKET s = GetSocket(); + if (s == INVALID_SOCKET) + { + s = CreateSocket6(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return s; + } + Attach(s); + } + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( port ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; +// sa.sin6_addr is all 0's + + int n = bind(s, (struct sockaddr *)&sa, sa_len); + int tries = range; + while (n == -1 && tries--) + { + sa.sin6_port = htons( ++port ); + n = bind(s, (struct sockaddr *)&sa, sa_len); + } + if (n == -1) + { + Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(); + Close(); + return INVALID_SOCKET; + } + return s; +} +#endif + +/** if you wish to use Send, first Open a connection */ +bool UdpSocket::Open(ipaddr_t l,port_t port) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return false; + } + Attach(s); + } + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port ); + memmove(&sa.sin_addr,&l,4); + + if (connect(GetSocket(), (struct sockaddr *)&sa, sa_len) == -1) + { + Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(); + return false; + } + m_connected = true; + return true; +} + + +bool UdpSocket::Open(const std::string& host,port_t port) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return false; + } + Attach(s); + } + ipaddr_t a; + if (u2ip(host, a)) + { + return Open(a, port); + } + return false; +} + + +#ifdef IPPROTO_IPV6 +bool UdpSocket::Open6(struct in6_addr& a,port_t port) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket6(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return false; + } + Attach(s); + } + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( port ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; + sa.sin6_addr = a; + + if (connect(GetSocket(), (struct sockaddr *)&sa, sa_len) == -1) + { + Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL); + SetCloseAndDelete(); + return false; + } + m_connected = true; + return true; +} + + +bool UdpSocket::Open6(const std::string& host,port_t port) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket6(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return false; + } + Attach(s); + } + struct in6_addr a; + if (u2ip(host, a)) + { + return Open6(a, port); + } + return false; +} +#endif + +void UdpSocket::CreateConnection() +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return; + } + Attach(s); + } +} + + +#ifdef IPPROTO_IPV6 +void UdpSocket::CreateConnection6() +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket6(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return; + } + Attach(s); + } +} +#endif // IPPROTO_IPV6 + +/** send to specified address */ +void UdpSocket::SendToBuf(const std::string& h,port_t p,const char *data,int len,int flags) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return; + } + Attach(s); + } + ipaddr_t a; + if (u2ip(h,a)) + { + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( p ); + memmove(&sa.sin_addr,&a,4); + + if (sendto(GetSocket(),data,len,flags,(struct sockaddr *)&sa,sa_len) == -1) + { + Handler().LogError(this,"sendto",Errno,StrError(Errno),LOG_LEVEL_ERROR); + } + } +} + + +/** send to specified address */ +void UdpSocket::SendToBuf(ipaddr_t a,port_t p,const char *data,int len,int flags) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket4(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return; + } + Attach(s); + } + { + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( p ); + memmove(&sa.sin_addr,&a,4); + + if (sendto(GetSocket(),data,len,flags,(struct sockaddr *)&sa,sa_len) == -1) + { + Handler().LogError(this,"sendto",Errno,StrError(Errno),LOG_LEVEL_ERROR); + } + } +} + + +#ifdef IPPROTO_IPV6 +void UdpSocket::SendToBuf6(const std::string& h,port_t p,const char *data,int len,int flags) +{ + if (GetSocket() == INVALID_SOCKET) + { + SOCKET s = CreateSocket6(SOCK_DGRAM, "udp"); + if (s == INVALID_SOCKET) + { + return; + } + Attach(s); + } + struct in6_addr a; + if (u2ip(h,a)) + { + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + memset(&sa,0,sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( p ); + sa.sin6_flowinfo = 0; + sa.sin6_scope_id = 0; + sa.sin6_addr = a; + + if (sendto(GetSocket(),data,len,flags,(struct sockaddr *)&sa,sa_len) == -1) + { + Handler().LogError(this,"sendto",Errno,StrError(Errno),LOG_LEVEL_ERROR); + } + } +} +#endif + +void UdpSocket::SendTo(const std::string& a,port_t p,const std::string& str,int flags) +{ + SendToBuf(a,p,str.c_str(),(int)str.size(),flags); +} + + +void UdpSocket::SendTo(ipaddr_t a,port_t p,const std::string& str,int flags) +{ + SendToBuf(a,p,str.c_str(),(int)str.size(),flags); +} + + +#ifdef IPPROTO_IPV6 +void UdpSocket::SendTo6(const std::string& a,port_t p,const std::string& str,int flags) +{ + SendToBuf6(a,p,str.c_str(),(int)str.size(),flags); +} +#endif + +/** send to connected address */ +void UdpSocket::SendBuf(const char *data,int len,int flags) +{ + if (!m_connected) + { + Handler().LogError(this,"SendBuf",0,"not connected",LOG_LEVEL_ERROR); + return; + } + if (send(GetSocket(),data,len,flags) == -1) + { + Handler().LogError(this,"send",Errno,StrError(Errno),LOG_LEVEL_ERROR); + } +} + + +void UdpSocket::Send(const std::string& str,int flags) +{ + SendBuf(str.c_str(),(int)str.size(),flags); +} + + +void UdpSocket::OnRead() +{ +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len); + if (n == -1) + { + Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return; + } + if (sa_len != sizeof(sa)) + { + Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING); + } + this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len); + return; + } +#endif + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len); + if (n == -1) + { + Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR); + return; + } + if (sa_len != sizeof(sa)) + { + Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING); + } + this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len); +} + + +void UdpSocket::SetBroadcast(bool b) +{ + int one = 1; + int zero = 0; + + if (b) + { + if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)) == -1) + { + Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } + else + { + if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &zero, sizeof(zero)) == -1) + { + Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } +} + + +bool UdpSocket::IsBroadcast() +{ + int is_broadcast = 0; + socklen_t size; + if (getsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&is_broadcast, &size) == -1) + { + Handler().LogError(this, "IsBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + return is_broadcast != 0; +} + + +void UdpSocket::SetMulticastTTL(int ttl) +{ + if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(int)) == -1) + { + Handler().LogError(this, "SetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } +} + + +int UdpSocket::GetMulticastTTL() +{ + int ttl = 0; + socklen_t size = sizeof(int); + if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, &size) == -1) + { + Handler().LogError(this, "GetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + return ttl; +} + + +void UdpSocket::SetMulticastLoop(bool x) +{ +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + int val = x ? 1 : 0; + if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1) + { + Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } +#endif + int val = x ? 1 : 0; + if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1) + { + Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } +} + + +bool UdpSocket::IsMulticastLoop() +{ +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + int is_loop = 0; + socklen_t size = sizeof(int); + if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&is_loop, &size) == -1) + { + Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + return is_loop ? true : false; + } +#endif + int is_loop = 0; + socklen_t size = sizeof(int); + if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&is_loop, &size) == -1) + { + Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + return is_loop ? true : false; +} + + +void UdpSocket::AddMulticastMembership(const std::string& group,const std::string& local_if,int if_index) +{ +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + struct ipv6_mreq x; + struct in6_addr addr; + if (u2ip( group, addr )) + { + x.ipv6mr_multiaddr = addr; + x.ipv6mr_interface = if_index; + if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1) + { + Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } + return; + } +#endif + struct ip_mreq x; // ip_mreqn + ipaddr_t addr; + if (u2ip( group, addr )) + { + memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr)); + u2ip( local_if, addr); + memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr)); +// x.imr_ifindex = if_index; + if (setsockopt(GetSocket(), SOL_IP, IP_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1) + { + Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } +} + + +void UdpSocket::DropMulticastMembership(const std::string& group,const std::string& local_if,int if_index) +{ +#ifdef IPPROTO_IPV6 + if (IsIpv6()) + { + struct ipv6_mreq x; + struct in6_addr addr; + if (u2ip( group, addr )) + { + x.ipv6mr_multiaddr = addr; + x.ipv6mr_interface = if_index; + if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1) + { + Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } + return; + } +#endif + struct ip_mreq x; // ip_mreqn + ipaddr_t addr; + if (u2ip( group, addr )) + { + memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr)); + u2ip( local_if, addr); + memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr)); +// x.imr_ifindex = if_index; + if (setsockopt(GetSocket(), SOL_IP, IP_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1) + { + Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + } +} + + +#ifdef IPPROTO_IPV6 +void UdpSocket::SetMulticastHops(int hops) +{ + if (!IsIpv6()) + { + Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR); + return; + } + if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, sizeof(int)) == -1) + { + Handler().LogError(this, "SetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } +} + + +int UdpSocket::GetMulticastHops() +{ + if (!IsIpv6()) + { + Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR); + return -1; + } + int hops = 0; + socklen_t size = sizeof(int); + if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, &size) == -1) + { + Handler().LogError(this, "GetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING); + } + return hops; +} +#endif // IPPROTO_IPV6 diff --git a/src/shared/Network/UdpSocket.h b/src/shared/Network/UdpSocket.h new file mode 100644 index 0000000..53f5056 --- /dev/null +++ b/src/shared/Network/UdpSocket.h @@ -0,0 +1,90 @@ +/** + ** File ......... UdpSocket.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _UDPSOCKET_H +#define _UDPSOCKET_H + +#include "Socket.h" + +class UdpSocket : public Socket +{ + public: + UdpSocket(SocketHandler& ,int ibufsz = 16384); + ~UdpSocket(); + +/** new callback */ + virtual void OnRawData(const char *,size_t,struct sockaddr *,socklen_t) {} + +/** to receive incoming data, call Bind to setup an incoming port */ + SOCKET Bind(port_t& port,int range); + SOCKET Bind6(port_t& port,int range); + +/** if you wish to use Send, first Open a connection */ + bool Open(ipaddr_t,port_t); + bool Open(const std::string& host,port_t port); + bool Open6(struct in6_addr&,port_t); + bool Open6(const std::string& host,port_t port); + +/** create before using sendto methods */ + void CreateConnection(); + void CreateConnection6(); // ipv6 + +/** send to specified address */ + void SendToBuf(const std::string& ,port_t,const char *data,int len,int flags = 0); + void SendToBuf(ipaddr_t,port_t,const char *data,int len,int flags = 0); + void SendToBuf6(const std::string& ,port_t,const char *data,int len,int flags = 0); + void SendTo(const std::string&,port_t,const std::string&,int flags = 0); + void SendTo(ipaddr_t,port_t,const std::string&,int flags = 0); + void SendTo6(const std::string&,port_t,const std::string&,int flags = 0); + +/** send to connected address */ + void SendBuf(const char *data,int,int flags = 0); + void Send(const std::string& ,int flags = 0); + +/** broadcast */ + void SetBroadcast(bool b = true); + bool IsBroadcast(); + +/** multicast */ + void SetMulticastTTL(int ttl = 1); + int GetMulticastTTL(); + void SetMulticastLoop(bool = true); + bool IsMulticastLoop(); + void AddMulticastMembership(const std::string& group,const std::string& intf = "0.0.0.0",int if_index = 0); + void DropMulticastMembership(const std::string& group,const std::string& intf = "0.0.0.0",int if_index = 0); +/** multicast, ipv6 */ + void SetMulticastHops(int = -1); + int GetMulticastHops(); + + protected: + UdpSocket(const UdpSocket& s) : Socket(s) {} + void OnRead(); + +// int recvfrom(int s, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen); +// int sendto(int s, const void *msg, int len, int flags, const struct sockaddr *to, socklen_t tolen); + private: + UdpSocket& operator=(const UdpSocket& ) { return *this; } + bool m_connected; + char *m_ibuf; + int m_ibufsz; +}; +#endif // _UDPSOCKET_H diff --git a/src/shared/Network/Utility.cpp b/src/shared/Network/Utility.cpp new file mode 100644 index 0000000..83168d8 --- /dev/null +++ b/src/shared/Network/Utility.cpp @@ -0,0 +1,151 @@ +/** + ** File ......... Utility.cpp + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 "Utility.h" + +std::string Utility::base64(const std::string& str_in) +{ + std::string str; + Base64 m_b; + m_b.encode(str_in, str, false); // , false == do not add cr/lf + return str; +} + + +std::string Utility::base64d(const std::string& str_in) +{ + std::string str; + Base64 m_b; + m_b.decode(str_in, str); + return str; +} + + +std::string Utility::l2string(long l) +{ + std::string str; + char tmp[100]; + sprintf(tmp,"%ld",l); + str = tmp; + return str; +} + + +std::string Utility::bigint2string(uint64_t l) +{ + std::string str; + uint64_t tmp = l; + while (tmp) + { + uint64_t a = tmp % 10; + str = (char)(a + 48) + str; + tmp /= 10; + } + if (!str.size()) + { + str = "0"; + } + return str; +} + + +uint64_t Utility::atoi64(const std::string& str) +{ + uint64_t l = 0; + for (size_t i = 0; i < str.size(); i++) + { + l = l * 10 + str[i] - 48; + } + return l; +} + + +unsigned int Utility::hex2unsigned(const std::string& str) +{ + unsigned int r = 0; + for (size_t i = 0; i < str.size(); i++) + { + r = r * 16 + str[i] - 48 - ((str[i] >= 'A') ? 7 : 0) - ((str[i] >= 'a') ? 32 : 0); + } + return r; +} + + +/* + * Encode string per RFC1738 URL encoding rules + * tnx rstaveley + */ +std::string Utility::rfc1738_encode(const std::string& src) +{ + static char hex[] = "0123456789ABCDEF"; + std::string dst; + for (size_t i = 0; i < src.size(); i++) + { + if (isalnum(src[i])) + { + dst += src[i]; + } + else + if (src[i] == ' ') + { + dst += '+'; + } + else + { + dst += '%'; + dst += hex[src[i] / 16]; + dst += hex[src[i] % 16]; + } + } + return dst; +} // rfc1738_encode + + +/* + * Decode string per RFC1738 URL encoding rules + * tnx rstaveley + */ +std::string Utility::rfc1738_decode(const std::string& src) +{ + std::string dst; + for (size_t i = 0; i < src.size(); i++) + { + if (src[i] == '%' && isxdigit(src[i + 1]) && isxdigit(src[i + 2])) + { + char c1 = src[i + 1]; + char c2 = src[i + 2]; + c1 = c1 - 48 - ((c1 >= 'A') ? 7 : 0) - ((c1 >= 'a') ? 32 : 0); + c2 = c2 - 48 - ((c2 >= 'A') ? 7 : 0) - ((c2 >= 'a') ? 32 : 0); + dst += (char)(c1 * 16 + c2); + } + else + if (src[i] == '+') + { + dst += ' '; + } + else + { + dst += src[i]; + } + } + return dst; +} // rfc1738_decode diff --git a/src/shared/Network/Utility.h b/src/shared/Network/Utility.h new file mode 100644 index 0000000..105ea4d --- /dev/null +++ b/src/shared/Network/Utility.h @@ -0,0 +1,51 @@ +/** + ** File ......... Utility.h + ** Published .... 2004-02-13 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _UTILITY_H +#define _UTILITY_H + +#include +#ifdef _WIN32 +typedef unsigned __int64 uint64_t; +#else +#include +#ifdef SOLARIS +# include +#else +# include +#endif +#endif +#include "Base64.h" + +class Utility +{ + public: + static std::string base64(const std::string& str_in); + static std::string base64d(const std::string& str_in); + static std::string l2string(long l); + static std::string bigint2string(uint64_t l); + static uint64_t atoi64(const std::string& str); + static unsigned int hex2unsigned(const std::string& str); + static std::string rfc1738_encode(const std::string& src); + static std::string rfc1738_decode(const std::string& src); +}; +#endif // _UTILITY_H diff --git a/src/shared/Network/socket_include.cpp b/src/shared/Network/socket_include.cpp new file mode 100644 index 0000000..04c4b36 --- /dev/null +++ b/src/shared/Network/socket_include.cpp @@ -0,0 +1,31 @@ +/** + ** File ......... socket_include.cpp + ** Published .... 2004-11-28 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 + +// only to be included in win32 projects +const char *StrError(int x) +{ + static char tmp[100]; + sprintf(tmp, "Winsock error code: %d", x); + return tmp; +} diff --git a/src/shared/Network/socket_include.h b/src/shared/Network/socket_include.h new file mode 100644 index 0000000..b6f4330 --- /dev/null +++ b/src/shared/Network/socket_include.h @@ -0,0 +1,144 @@ +/** + ** File ......... socket_include.h + ** Published .... 2005-04-12 + ** Author ....... grymse@alhem.net + **/ +/* +Copyright (C) 2004,2005 Anders Hedstrom + +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 _SOCKET_INCLUDE_H +#define _SOCKET_INCLUDE_H + +#if (defined(__unix__) || defined(unix)) && !defined(USG) +#include +#endif + +#ifndef _WIN32 +// ---------------------------------------- +// common unix includes / defines +#include +#include +#include +#include +#include +#include +#include +#define Errno errno +#define StrError strerror + +// WIN32 adapt +#define closesocket close +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +typedef int SOCKET; + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif // INADDR_NONE +#endif // !_WIN32 + +// ---------------------------------------- +// Generic +#ifndef SOL_IP +#define SOL_IP IPPROTO_IP +#endif + +// ---------------------------------------- +// OS specific adaptions + +#ifdef SOLARIS +// ---------------------------------------- +// Solaris +typedef unsigned short port_t; +#define s6_addr16 _S6_un._S6_u8 +#define MSG_NOSIGNAL 0 + +#elif defined(__FreeBSD__) || defined(__OpenBSD__) +// ---------------------------------------- +// FreeBSD and OpenBSD + +# if defined(__FreeBSD__) && __FreeBSD_version < 400014 +# error FreeBSD versions prior to 400014 does not support ipv6 +# endif + +# define s6_addr16 __u6_addr.__u6_addr16 +# if !defined(MSG_NOSIGNAL) +# define MSG_NOSIGNAL 0 +# endif +# include +typedef in_addr_t ipaddr_t; +typedef in_port_t port_t; +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#elif defined __APPLE_CC__ +// ---------------------------------------- +// Mac OS X +#include +#include +typedef unsigned long ipaddr_t; +#define s6_addr16 __u6_addr.__u6_addr16 +#define MSG_NOSIGNAL 0 // oops - thanks Derek +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#elif defined _WIN32 +// ---------------------------------------- +// Win32 +#pragma comment(lib, "wsock32.lib") +typedef unsigned long ipaddr_t; +typedef unsigned short port_t; +typedef int socklen_t; +#define MSG_NOSIGNAL 0 +#define SHUT_RDWR 2 + +// 1.8.6: define FD_SETSIZE to something bigger than 64 if there are a lot of +// simultaneous connections (must be done before including winsock.h) +#define FD_SETSIZE 1024 +#include + +#define Errno WSAGetLastError() +const char *StrError(int x); + +// class WSAInitializer is a part of the Socket class (on win32) +// as a static instance - so whenever an application uses a Socket, +// winsock is initialized +class WSAInitializer // Winsock Initializer +{ + public: + WSAInitializer() + { + if (WSAStartup(0x101,&m_wsadata)) + { + exit(-1); + } + } + ~WSAInitializer() + { + WSACleanup(); + } + private: + WSADATA m_wsadata; +}; + +#else +// ---------------------------------------- +// LINUX +typedef unsigned long ipaddr_t; +typedef unsigned short port_t; +#endif +#endif // _SOCKET_INCLUDE_H diff --git a/src/shared/SysDefs.h b/src/shared/SysDefs.h new file mode 100644 index 0000000..dec3cdd --- /dev/null +++ b/src/shared/SysDefs.h @@ -0,0 +1,86 @@ +#ifndef _SYSDEFS_H +#define _SYSDEFS_H + +////////////////////////////////////// +// Platform defines +////////////////////////////////////// + +#define PLATFORM_WIN32 0 +#define PLATFORM_UNIX 1 +#define PLATFORM_APPLE 2 +#define PLATFORM_INTEL 3 + +#if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 ) +# define PLATFORM PLATFORM_WIN32 +#elif defined( __APPLE_CC__ ) +# define PLATFORM PLATFORM_APPLE +#elif defined( __INTEL_COMPILER ) +# define PLATFORM PLATFORM_INTEL +#else +# define PLATFORM PLATFORM_UNIX +#endif + +#define COMPILER_MICROSOFT 0 +#define COMPILER_GNU 1 +#define COMPILER_BORLAND 2 +#define COMPILER_INTEL 3 + +#ifdef _MSC_VER +# define COMPILER COMPILER_MICROSOFT +#elif defined( __BORLANDC__ ) +# define COMPILER COMPILER_BORLAND +#elif defined( __INTEL_COMPILER ) +# define COMPILER COMPILER_INTEL +#elif defined( __GNUC__ ) +# define COMPILER COMPILER_GNU +#else +# pragma error "FATAL ERROR: Unknown compiler." +#endif + +#if COMPILER == COMPILER_MICROSOFT + # pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data + # pragma warning( disable : 4786 ) // identifier was truncated to '255' characters in the debug information + #ifndef _DEBUG + # pragma warning( disable : 4244 ) // conversion from 'uint64' to 'int16', possible loss of data + #endif +#endif + +//////////////////////////////////// +// Compiler defines +//////////////////////////////////// + +#if COMPILER == COMPILER_MICROSOFT + #define I64FMT "%016I64X" + #define I64FMTD "%I64u" + #define SI64FMTD "%I64d" + #define snprintf _snprintf + #define atoll __atoi64 + #define vsnprintf _vsnprintf + #define strdup _strdup + typedef __int64 int64; + typedef long int32; + typedef short int16; + typedef char int8; + typedef unsigned __int64 uint64; + typedef unsigned long uint32; + typedef unsigned short uint16; + typedef unsigned char uint8; +#else + #define stricmp strcasecmp + #define strnicmp strncasecmp + #define I64FMT "%016llX" + #define I64FMTD "%llu" + #define SI64FMTD "%lld" + typedef __int64_t int64; + typedef __int32_t int32; + typedef __int16_t int16; + typedef __int8_t int8; + typedef __uint64_t uint64; + typedef __uint32_t uint32; + typedef __uint16_t uint16; + typedef __uint8_t uint8; + typedef uint16 WORD; + typedef uint32 DWORD; +#endif + +#endif \ No newline at end of file diff --git a/src/shared/common.h b/src/shared/common.h new file mode 100644 index 0000000..2c6f58d --- /dev/null +++ b/src/shared/common.h @@ -0,0 +1,29 @@ +#ifndef _COMMON_H +#define _COMMON_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include "../zthread/ZThread.h" +#include "zthread/FastMutex.h" +#include "zthread/LockedQueue.h" +#include "zthread/Runnable.h" +#include "zthread/Thread.h" + +#include "SysDefs.h" +#include "DebugStuff.h" +#include "tools.h" + + +#endif + diff --git a/src/shared/tools.cpp b/src/shared/tools.cpp new file mode 100644 index 0000000..23f3c2b --- /dev/null +++ b/src/shared/tools.cpp @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include "tools.h" + +/* +char *triml(char *data,int count){ + data=data+count; + return data; +} + +void nullify(char *ptr,int len){ + int i; + for(i=0;i +std::string toString(T num){ + std::stringstream ss; + ss << num; + return ss.str(); +} + +std::string getDateString(void) +{ + time_t t = time(NULL); + tm* aTm = localtime(&t); + char str[19]; + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + sprintf(str,"%-4d-%02d-%02d %02d:%02d:%02d ",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec); + return std::string(str); +} diff --git a/src/shared/tools.h b/src/shared/tools.h new file mode 100644 index 0000000..9e32c45 --- /dev/null +++ b/src/shared/tools.h @@ -0,0 +1,30 @@ +#ifndef _TOOLS_H +#define _TOOLS_H + +#include "common.h" + + +// old obsoelete functions +//char *triml(char*,int); +//void nullify(char*,int); +void printchex(std::string,bool); +//char *strl(char*,int); +//char *strr(char*,int); +//char *trimr(char*,int); +//char *genrndstr(int); +//char *StrToHex(char*,int); +//char *HexToStr(char*,int); +//char *NewNullString(int); +//char *Reverse(char*,int); +//void rawcpy(char*,char*,int); +//void rawcat(char*,char*,int,int); +//void TrimQuotes(char*); + +// new functions +std::string stringToUpper(std::string); +std::string stringToLower(std::string); +std::string toString(uint64 num); +std::string toString(int64 num); +std::string getDateString(void); + +#endif \ No newline at end of file diff --git a/src/zlib.vcproj b/src/zlib.vcproj new file mode 100644 index 0000000..d751a7e --- /dev/null +++ b/src/zlib.vcproj @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/zthread.vcproj b/src/zthread.vcproj new file mode 100644 index 0000000..8956616 --- /dev/null +++ b/src/zthread.vcproj @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/thanks_to.txt b/thanks_to.txt new file mode 100644 index 0000000..86f8706 --- /dev/null +++ b/thanks_to.txt @@ -0,0 +1,25 @@ +#Coders: +False.Genesis (project starter) +Mini + + +#Testers: +========= +Project-Eden crew: Leito, Michel [Milk Addict], ©haos, Orochi, SoulReaper + + + +#Special thanks to: +=================== + +©haos for the neat icon and many hours that passed by while discussing +about PseuWoW related stuff. + + + + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// + +Want to be named here? Then do something for the Project! diff --git a/todo_tofix_someday.txt b/todo_tofix_someday.txt new file mode 100644 index 0000000..e75aac4 --- /dev/null +++ b/todo_tofix_someday.txt @@ -0,0 +1,11 @@ +realm login: +- use the correct IP in CLIENT_LOGON_CHALLENGE, and not 127.0.0.1 +- use correct timezone, maybe settable via conf file later on +- define the crc_hash as it should be + +controller: +- complete recoding + +shared: +-fix CircularBuffer::IncreaseSize() (its BUGGED and corrupts the data) +