hlibgit2 (empty) → 0.1
raw patch · 122 files changed
+24499/−0 lines, 122 filesdep +basedep +bindings-DSLdep +hlibgit2setup-changedbinary-added
Dependencies added: base, bindings-DSL, hlibgit2, process
Files
- Bindings/Libgit2.hs +36/−0
- Bindings/Libgit2/Blob.hsc +17/−0
- Bindings/Libgit2/Blob.hsc.helper.c +6/−0
- Bindings/Libgit2/Commit.hsc +27/−0
- Bindings/Libgit2/Commit.hsc.helper.c +6/−0
- Bindings/Libgit2/Common.hsc +39/−0
- Bindings/Libgit2/Errors.hsc +8/−0
- Bindings/Libgit2/Index.hsc +67/−0
- Bindings/Libgit2/Object.hsc +20/−0
- Bindings/Libgit2/Odb.hsc +30/−0
- Bindings/Libgit2/OdbBackend.hsc +12/−0
- Bindings/Libgit2/Oid.hsc +26/−0
- Bindings/Libgit2/Refs.hsc +24/−0
- Bindings/Libgit2/Repository.hsc +17/−0
- Bindings/Libgit2/Revwalk.hsc +21/−0
- Bindings/Libgit2/Signature.hsc +11/−0
- Bindings/Libgit2/Tag.hsc +23/−0
- Bindings/Libgit2/Tag.hsc.helper.c +6/−0
- Bindings/Libgit2/ThreadUtils.hsc +9/−0
- Bindings/Libgit2/Tree.hsc +27/−0
- Bindings/Libgit2/Tree.hsc.helper.c +6/−0
- Bindings/Libgit2/Types.hsc +76/−0
- LICENSE +19/−0
- Setup.hs +2/−0
- hlibgit2.cabal +179/−0
- libgit2/deps/zlib/adler32.c +169/−0
- libgit2/deps/zlib/deflate.c +1834/−0
- libgit2/deps/zlib/deflate.h +342/−0
- libgit2/deps/zlib/inffast.c +340/−0
- libgit2/deps/zlib/inffast.h +11/−0
- libgit2/deps/zlib/inffixed.h +94/−0
- libgit2/deps/zlib/inflate.c +1480/−0
- libgit2/deps/zlib/inflate.h +122/−0
- libgit2/deps/zlib/inftrees.c +330/−0
- libgit2/deps/zlib/inftrees.h +62/−0
- libgit2/deps/zlib/trees.c +1244/−0
- libgit2/deps/zlib/trees.h +128/−0
- libgit2/deps/zlib/zconf.h +57/−0
- libgit2/deps/zlib/zlib.h +1613/−0
- libgit2/deps/zlib/zutil.c +318/−0
- libgit2/deps/zlib/zutil.h +274/−0
- libgit2/include/git2.h +56/−0
- libgit2/include/git2/blob.h +128/−0
- libgit2/include/git2/commit.h +188/−0
- libgit2/include/git2/common.h +172/−0
- libgit2/include/git2/errors.h +45/−0
- libgit2/include/git2/index.h +199/−0
- libgit2/include/git2/object.h +198/−0
- libgit2/include/git2/odb.h +201/−0
- libgit2/include/git2/odb_backend.h +77/−0
- libgit2/include/git2/oid.h +191/−0
- libgit2/include/git2/refs.h +246/−0
- libgit2/include/git2/repository.h +191/−0
- libgit2/include/git2/revwalk.h +187/−0
- libgit2/include/git2/signature.h +70/−0
- libgit2/include/git2/tag.h +154/−0
- libgit2/include/git2/thread-utils.h +72/−0
- libgit2/include/git2/tree.h +223/−0
- libgit2/include/git2/types.h +154/−0
- libgit2/include/git2/zlib.h +58/−0
- libgit2/src/blob.c +136/−0
- libgit2/src/blob.h +17/−0
- libgit2/src/block-sha1/sha1.c +281/−0
- libgit2/src/block-sha1/sha1.h +22/−0
- libgit2/src/bswap.h +97/−0
- libgit2/src/cc-compat.h +73/−0
- libgit2/src/commit.c +299/−0
- libgit2/src/commit.h +29/−0
- libgit2/src/common.h +56/−0
- libgit2/src/delta-apply.c +109/−0
- libgit2/src/delta-apply.h +25/−0
- libgit2/src/dir.h +41/−0
- libgit2/src/errors.c +44/−0
- libgit2/src/filebuf.c +291/−0
- libgit2/src/filebuf.h +44/−0
- libgit2/src/fileops.c +553/−0
- libgit2/src/fileops.h +191/−0
- libgit2/src/hash.c +94/−0
- libgit2/src/hash.h +26/−0
- libgit2/src/hashtable.c +261/−0
- libgit2/src/hashtable.h +73/−0
- libgit2/src/index.c +768/−0
- libgit2/src/index.h +34/−0
- libgit2/src/map.h +31/−0
- libgit2/src/mingw-compat.h +13/−0
- libgit2/src/msvc-compat.h +42/−0
- libgit2/src/object.c +487/−0
- libgit2/src/odb.c +396/−0
- libgit2/src/odb.h +17/−0
- libgit2/src/odb_loose.c +658/−0
- libgit2/src/odb_pack.c +1406/−0
- libgit2/src/oid.c +346/−0
- libgit2/src/pqueue.c +157/−0
- libgit2/src/pqueue.h +97/−0
- libgit2/src/refs.c +1594/−0
- libgit2/src/refs.h +42/−0
- libgit2/src/repository.c +541/−0
- libgit2/src/repository.h +65/−0
- libgit2/src/revwalk.c +565/−0
- libgit2/src/signature.c +199/−0
- libgit2/src/signature.h +12/−0
- libgit2/src/t03-data.h +344/−0
- libgit2/src/tag.c +232/−0
- libgit2/src/tag.h +22/−0
- libgit2/src/thread-utils.c +49/−0
- libgit2/src/thread-utils.h +28/−0
- libgit2/src/tree.c +351/−0
- libgit2/src/tree.h +26/−0
- libgit2/src/unix/map.c +61/−0
- libgit2/src/util.c +406/−0
- libgit2/src/util.h +119/−0
- libgit2/src/vector.c +175/−0
- libgit2/src/vector.h +36/−0
- libgit2/src/win32/dir.c +98/−0
- libgit2/src/win32/fileops.c +41/−0
- libgit2/src/win32/map.c +125/−0
- libgit2/src/win32/pthread.c +120/−0
- libgit2/src/win32/pthread.h +67/−0
- tests/Main.hi binary
- tests/Main.hs +15/−0
- tests/Main.hs~ +10/−0
- tests/Main.o binary
+ Bindings/Libgit2.hs view
@@ -0,0 +1,36 @@++module Bindings.Libgit2 (+ module Bindings.Libgit2.Refs,+ module Bindings.Libgit2.Odb,+ module Bindings.Libgit2.Types,+ module Bindings.Libgit2.Index,+ module Bindings.Libgit2.ThreadUtils,+ module Bindings.Libgit2.Oid,+ module Bindings.Libgit2.Tag,+ module Bindings.Libgit2.Object,+ module Bindings.Libgit2.Signature,+ module Bindings.Libgit2.Blob,+ module Bindings.Libgit2.OdbBackend,+ module Bindings.Libgit2.Repository,+ module Bindings.Libgit2.Common,+ module Bindings.Libgit2.Commit,+ module Bindings.Libgit2.Errors,+ module Bindings.Libgit2.Tree,+ module Bindings.Libgit2.Revwalk) where+import Bindings.Libgit2.Refs+import Bindings.Libgit2.Odb+import Bindings.Libgit2.Types+import Bindings.Libgit2.Index+import Bindings.Libgit2.ThreadUtils+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Tag+import Bindings.Libgit2.Object+import Bindings.Libgit2.Signature+import Bindings.Libgit2.Blob+import Bindings.Libgit2.OdbBackend+import Bindings.Libgit2.Repository+import Bindings.Libgit2.Common+import Bindings.Libgit2.Commit+import Bindings.Libgit2.Errors+import Bindings.Libgit2.Tree+import Bindings.Libgit2.Revwalk
+ Bindings/Libgit2/Blob.hsc view
@@ -0,0 +1,17 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Blob where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Object+#ccall git_blob_set_rawcontent_fromfile , Ptr <git_blob> -> CString -> IO (CInt)+#ccall git_blob_set_rawcontent , Ptr <git_blob> -> Ptr Word8 -> CSize -> IO (CInt)+#ccall git_blob_rawcontent , Ptr <git_blob> -> IO (Ptr Word8)+#ccall git_blob_rawsize , Ptr <git_blob> -> IO (CInt)+#ccall git_blob_writefile , Ptr <git_oid> -> Ptr <git_repository> -> CString -> IO (CInt)+#cinline git_blob_lookup , Ptr (Ptr <git_blob>) -> Ptr <git_repository> -> Ptr <git_oid> -> IO (CInt)+#cinline git_blob_new , Ptr (Ptr <git_blob>) -> Ptr <git_repository> -> IO (CInt)
+ Bindings/Libgit2/Blob.hsc.helper.c view
@@ -0,0 +1,6 @@++#include <bindings.cmacros.h>+#include <git2.h>++BC_INLINE3(git_blob_lookup, git_blob **, git_repository *, const git_oid *,int)+BC_INLINE2(git_blob_new, git_blob **, git_repository *,int)
+ Bindings/Libgit2/Commit.hsc view
@@ -0,0 +1,27 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Commit where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Object+#ccall git_commit_id , Ptr <git_commit> -> IO (Ptr <git_oid>)+#ccall git_commit_message_short , Ptr <git_commit> -> IO (CString)+#ccall git_commit_message , Ptr <git_commit> -> IO (CString)+#ccall git_commit_time , Ptr <git_commit> -> IO (CTime)+#ccall git_commit_time_offset , Ptr <git_commit> -> IO (CInt)+#ccall git_commit_committer , Ptr <git_commit> -> IO (Ptr <git_signature>)+#ccall git_commit_author , Ptr <git_commit> -> IO (Ptr <git_signature>)+#ccall git_commit_tree , Ptr (Ptr <git_tree>) -> Ptr <git_commit> -> IO (CInt)+#ccall git_commit_parentcount , Ptr <git_commit> -> IO (CUInt)+#ccall git_commit_parent , Ptr (Ptr <git_commit>) -> Ptr <git_commit> -> CUInt -> IO (CInt)+#ccall git_commit_add_parent , Ptr <git_commit> -> Ptr <git_commit> -> IO (CInt)+#ccall git_commit_set_message , Ptr <git_commit> -> CString -> IO ()+#ccall git_commit_set_committer , Ptr <git_commit> -> Ptr <git_signature> -> IO ()+#ccall git_commit_set_author , Ptr <git_commit> -> Ptr <git_signature> -> IO ()+#ccall git_commit_set_tree , Ptr <git_commit> -> Ptr <git_tree> -> IO (CInt)+#cinline git_commit_lookup , Ptr (Ptr <git_commit>) -> Ptr <git_repository> -> Ptr <git_oid> -> IO (CInt)+#cinline git_commit_new , Ptr (Ptr <git_commit>) -> Ptr <git_repository> -> IO (CInt)
+ Bindings/Libgit2/Commit.hsc.helper.c view
@@ -0,0 +1,6 @@++#include <bindings.cmacros.h>+#include <git2.h>++BC_INLINE3(git_commit_lookup, git_commit **, git_repository *, const git_oid *,int)+BC_INLINE2(git_commit_new, git_commit **, git_repository *,int)
+ Bindings/Libgit2/Common.hsc view
@@ -0,0 +1,39 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Common where+#strict_import++import Bindings.Libgit2.ThreadUtils+#num GIT_SUCCESS+#num GIT_ERROR+#num GIT_ENOTOID+#num GIT_ENOTFOUND+#num GIT_ENOMEM+#num GIT_EOSERR+#num GIT_EOBJTYPE+#num GIT_EOBJCORRUPTED+#num GIT_ENOTAREPO+#num GIT_EINVALIDTYPE+#num GIT_EMISSINGOBJDATA+#num GIT_EPACKCORRUPTED+#num GIT_EFLOCKFAIL+#num GIT_EZLIB+#num GIT_EBUSY+#num GIT_EBAREINDEX+#num GIT_EINVALIDREFNAME+#num GIT_EREFCORRUPTED+#num GIT_ETOONESTEDSYMREF+#num GIT_EPACKEDREFSCORRUPTED+#num GIT_EINVALIDPATH+#num GIT_EREVWALKOVER+#num GIT_EINVALIDREFSTATE+{- typedef struct {+ char **strings;+ size_t count;+} git_strarray; -}+#starttype git_strarray+#field strings , Ptr CString+#field count , CSize+#stoptype+#ccall git_strarray_free , Ptr <git_strarray> -> IO ()
+ Bindings/Libgit2/Errors.hsc view
@@ -0,0 +1,8 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Errors where+#strict_import+++#ccall git_strerror , CInt -> IO (CString)
+ Bindings/Libgit2/Index.hsc view
@@ -0,0 +1,67 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Index where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+#num GIT_IDXENTRY_NAMEMASK+#num GIT_IDXENTRY_STAGEMASK+#num GIT_IDXENTRY_EXTENDED+#num GIT_IDXENTRY_VALID+#num GIT_IDXENTRY_STAGESHIFT+{- typedef struct {+ git_time_t seconds;+ + unsigned int nanoseconds;+} git_index_time; -}+#starttype git_index_time+#field seconds , CTime+#field nanoseconds , CUInt+#stoptype+{- typedef struct git_index_entry {+ git_index_time ctime;+ git_index_time mtime;++ unsigned int dev;+ unsigned int ino;+ unsigned int mode;+ unsigned int uid;+ unsigned int gid;+ git_off_t file_size;++ git_oid oid;++ unsigned short flags;+ unsigned short flags_extended;++ char *path;+} git_index_entry; -}+#starttype git_index_entry+#field ctime , <git_index_time>+#field mtime , <git_index_time>+#field dev , CUInt+#field ino , CUInt+#field mode , CUInt+#field uid , CUInt+#field gid , CUInt+#field file_size , <git_off_t>+#field oid , <git_oid>+#field flags , CUShort+#field flags_extended , CUShort+#field path , CString+#stoptype+#ccall git_index_open_bare , Ptr (Ptr <git_index>) -> CString -> IO (CInt)+#ccall git_index_open_inrepo , Ptr (Ptr <git_index>) -> Ptr <git_repository> -> IO (CInt)+#ccall git_index_clear , Ptr <git_index> -> IO ()+#ccall git_index_free , Ptr <git_index> -> IO ()+#ccall git_index_read , Ptr <git_index> -> IO (CInt)+#ccall git_index_write , Ptr <git_index> -> IO (CInt)+#ccall git_index_find , Ptr <git_index> -> CString -> IO (CInt)+#ccall git_index_add , Ptr <git_index> -> CString -> CInt -> IO (CInt)+#ccall git_index_remove , Ptr <git_index> -> CInt -> IO (CInt)+#ccall git_index_insert , Ptr <git_index> -> Ptr <git_index_entry> -> IO (CInt)+#ccall git_index_get , Ptr <git_index> -> CInt -> IO (Ptr <git_index_entry>)+#ccall git_index_entrycount , Ptr <git_index> -> IO (CUInt)
+ Bindings/Libgit2/Object.hsc view
@@ -0,0 +1,20 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Object where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+#ccall git_object_lookup , Ptr (Ptr <git_object>) -> Ptr <git_repository> -> Ptr <git_oid> -> <git_otype> -> IO (CInt)+#ccall git_object_new , Ptr (Ptr <git_object>) -> Ptr <git_repository> -> <git_otype> -> IO (CInt)+#ccall git_object_write , Ptr <git_object> -> IO (CInt)+#ccall git_object_id , Ptr <git_object> -> IO (Ptr <git_oid>)+#ccall git_object_type , Ptr <git_object> -> IO (<git_otype>)+#ccall git_object_owner , Ptr <git_object> -> IO (Ptr <git_repository>)+#ccall git_object_close , Ptr <git_object> -> IO ()+#ccall git_object_type2string , <git_otype> -> IO (CString)+#ccall git_object_string2type , CString -> IO (<git_otype>)+#ccall git_object_typeisloose , <git_otype> -> IO (CInt)+#ccall git_object__size , <git_otype> -> IO (CSize)
+ Bindings/Libgit2/Odb.hsc view
@@ -0,0 +1,30 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Odb where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+{- typedef struct {+ void *data; + size_t len; + git_otype type; +} git_rawobj; -}+#starttype git_rawobj+#field data , Ptr Word8+#field len , CSize+#field type , <git_otype>+#stoptype+#ccall git_odb_new , Ptr (Ptr <git_odb>) -> IO (CInt)+#ccall git_odb_open , Ptr (Ptr <git_odb>) -> CString -> IO (CInt)+#ccall git_odb_add_backend , Ptr <git_odb> -> Ptr <git_odb_backend> -> CInt -> IO (CInt)+#ccall git_odb_add_alternate , Ptr <git_odb> -> Ptr <git_odb_backend> -> CInt -> IO (CInt)+#ccall git_odb_close , Ptr <git_odb> -> IO ()+#ccall git_odb_read , Ptr <git_rawobj> -> Ptr <git_odb> -> Ptr <git_oid> -> IO (CInt)+#ccall git_odb_read_header , Ptr <git_rawobj> -> Ptr <git_odb> -> Ptr <git_oid> -> IO (CInt)+#ccall git_odb_write , Ptr <git_oid> -> Ptr <git_odb> -> Ptr <git_rawobj> -> IO (CInt)+#ccall git_odb_exists , Ptr <git_odb> -> Ptr <git_oid> -> IO (CInt)+#ccall git_rawobj_hash , Ptr <git_oid> -> Ptr <git_rawobj> -> IO (CInt)+#ccall git_rawobj_close , Ptr <git_rawobj> -> IO ()
+ Bindings/Libgit2/OdbBackend.hsc view
@@ -0,0 +1,12 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.OdbBackend where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Odb+#ccall git_odb_backend_pack , Ptr (Ptr <git_odb_backend>) -> CString -> IO (CInt)+#ccall git_odb_backend_loose , Ptr (Ptr <git_odb_backend>) -> CString -> IO (CInt)
+ Bindings/Libgit2/Oid.hsc view
@@ -0,0 +1,26 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Oid where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+#num GIT_OID_RAWSZ+#num GIT_OID_HEXSZ+#opaque_t git_oid_shorten+{- typedef struct {+ + unsigned char id[GIT_OID_RAWSZ];+} git_oid; -}+#starttype git_oid+#array_field id , Word8+#stoptype+#ccall git_oid_mkstr , Ptr <git_oid> -> CString -> IO (CInt)+#ccall git_oid_mkraw , Ptr <git_oid> -> Ptr Word8 -> IO ()+#ccall git_oid_fmt , CString -> Ptr <git_oid> -> IO ()+#ccall git_oid_pathfmt , CString -> Ptr <git_oid> -> IO ()+#ccall git_oid_allocfmt , Ptr <git_oid> -> IO (CString)+#ccall git_oid_to_string , CString -> CSize -> Ptr <git_oid> -> IO (CString)+#ccall git_oid_cpy , Ptr <git_oid> -> Ptr <git_oid> -> IO ()+#ccall git_oid_cmp , Ptr <git_oid> -> Ptr <git_oid> -> IO (CInt)
+ Bindings/Libgit2/Refs.hsc view
@@ -0,0 +1,24 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Refs where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+#ccall git_reference_lookup , Ptr (Ptr <git_reference>) -> Ptr <git_repository> -> CString -> IO (CInt)+#ccall git_reference_create_symbolic , Ptr (Ptr <git_reference>) -> Ptr <git_repository> -> CString -> CString -> IO (CInt)+#ccall git_reference_create_oid , Ptr (Ptr <git_reference>) -> Ptr <git_repository> -> CString -> Ptr <git_oid> -> IO (CInt)+#ccall git_reference_oid , Ptr <git_reference> -> IO (Ptr <git_oid>)+#ccall git_reference_target , Ptr <git_reference> -> IO (CString)+#ccall git_reference_type , Ptr <git_reference> -> IO (<git_rtype>)+#ccall git_reference_name , Ptr <git_reference> -> IO (CString)+#ccall git_reference_resolve , Ptr (Ptr <git_reference>) -> Ptr <git_reference> -> IO (CInt)+#ccall git_reference_owner , Ptr <git_reference> -> IO (Ptr <git_repository>)+#ccall git_reference_set_target , Ptr <git_reference> -> CString -> IO (CInt)+#ccall git_reference_set_oid , Ptr <git_reference> -> Ptr <git_oid> -> IO (CInt)+#ccall git_reference_rename , Ptr <git_reference> -> CString -> IO (CInt)+#ccall git_reference_delete , Ptr <git_reference> -> IO (CInt)+#ccall git_reference_packall , Ptr <git_repository> -> IO (CInt)+#ccall git_reference_listall , Ptr <git_strarray> -> Ptr <git_repository> -> CUInt -> IO (CInt)
+ Bindings/Libgit2/Repository.hsc view
@@ -0,0 +1,17 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Repository where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+#ccall git_repository_open , Ptr (Ptr <git_repository>) -> CString -> IO (CInt)+#ccall git_repository_open2 , Ptr (Ptr <git_repository>) -> CString -> CString -> CString -> CString -> IO (CInt)+#ccall git_repository_open3 , Ptr (Ptr <git_repository>) -> CString -> Ptr <git_odb> -> CString -> CString -> IO (CInt)+#ccall git_repository_database , Ptr <git_repository> -> IO (Ptr <git_odb>)+#ccall git_repository_index , Ptr (Ptr <git_index>) -> Ptr <git_repository> -> IO (CInt)+#ccall git_repository_free , Ptr <git_repository> -> IO ()+#ccall git_repository_gc , Ptr <git_repository> -> IO (CInt)+#ccall git_repository_init , Ptr (Ptr <git_repository>) -> CString -> CUInt -> IO (CInt)
+ Bindings/Libgit2/Revwalk.hsc view
@@ -0,0 +1,21 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Revwalk where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+#num GIT_SORT_NONE+#num GIT_SORT_TOPOLOGICAL+#num GIT_SORT_TIME+#num GIT_SORT_REVERSE+#ccall git_revwalk_new , Ptr (Ptr <git_revwalk>) -> Ptr <git_repository> -> IO (CInt)+#ccall git_revwalk_reset , Ptr <git_revwalk> -> IO ()+#ccall git_revwalk_push , Ptr <git_revwalk> -> Ptr <git_oid> -> IO (CInt)+#ccall git_revwalk_hide , Ptr <git_revwalk> -> Ptr <git_oid> -> IO (CInt)+#ccall git_revwalk_next , Ptr <git_oid> -> Ptr <git_revwalk> -> IO (CInt)+#ccall git_revwalk_sorting , Ptr <git_revwalk> -> CUInt -> IO ()+#ccall git_revwalk_free , Ptr <git_revwalk> -> IO ()+#ccall git_revwalk_repository , Ptr <git_revwalk> -> IO (Ptr <git_repository>)
+ Bindings/Libgit2/Signature.hsc view
@@ -0,0 +1,11 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Signature where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+#ccall git_signature_new , CString -> CString -> CTime -> CInt -> IO (Ptr <git_signature>)+#ccall git_signature_dup , Ptr <git_signature> -> IO (Ptr <git_signature>)+#ccall git_signature_free , Ptr <git_signature> -> IO ()
+ Bindings/Libgit2/Tag.hsc view
@@ -0,0 +1,23 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Tag where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Object+#ccall git_tag_id , Ptr <git_tag> -> IO (Ptr <git_oid>)+#ccall git_tag_target , Ptr (Ptr <git_object>) -> Ptr <git_tag> -> IO (CInt)+#ccall git_tag_target_oid , Ptr <git_tag> -> IO (Ptr <git_oid>)+#ccall git_tag_type , Ptr <git_tag> -> IO (<git_otype>)+#ccall git_tag_name , Ptr <git_tag> -> IO (CString)+#ccall git_tag_tagger , Ptr <git_tag> -> IO (Ptr <git_signature>)+#ccall git_tag_message , Ptr <git_tag> -> IO (CString)+#ccall git_tag_set_target , Ptr <git_tag> -> Ptr <git_object> -> IO (CInt)+#ccall git_tag_set_name , Ptr <git_tag> -> CString -> IO ()+#ccall git_tag_set_tagger , Ptr <git_tag> -> Ptr <git_signature> -> IO ()+#ccall git_tag_set_message , Ptr <git_tag> -> CString -> IO ()+#cinline git_tag_lookup , Ptr (Ptr <git_tag>) -> Ptr <git_repository> -> Ptr <git_oid> -> IO (CInt)+#cinline git_tag_new , Ptr (Ptr <git_tag>) -> Ptr <git_repository> -> IO (CInt)
+ Bindings/Libgit2/Tag.hsc.helper.c view
@@ -0,0 +1,6 @@++#include <bindings.cmacros.h>+#include <git2.h>++BC_INLINE3(git_tag_lookup, git_tag **, git_repository *, const git_oid *,int)+BC_INLINE2(git_tag_new, git_tag **, git_repository *,int)
+ Bindings/Libgit2/ThreadUtils.hsc view
@@ -0,0 +1,9 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.ThreadUtils where+#strict_import+++#num GIT_HAS_TLS+#num GIT_THREADS
+ Bindings/Libgit2/Tree.hsc view
@@ -0,0 +1,27 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Tree where+#strict_import++import Bindings.Libgit2.Common+import Bindings.Libgit2.Types+import Bindings.Libgit2.Oid+import Bindings.Libgit2.Object+#ccall git_tree_id , Ptr <git_tree> -> IO (Ptr <git_oid>)+#ccall git_tree_entrycount , Ptr <git_tree> -> IO (CSize)+#ccall git_tree_entry_byname , Ptr <git_tree> -> CString -> IO (Ptr <git_tree_entry>)+#ccall git_tree_entry_byindex , Ptr <git_tree> -> CInt -> IO (Ptr <git_tree_entry>)+#ccall git_tree_entry_attributes , Ptr <git_tree_entry> -> IO (CUInt)+#ccall git_tree_entry_name , Ptr <git_tree_entry> -> IO (CString)+#ccall git_tree_entry_id , Ptr <git_tree_entry> -> IO (Ptr <git_oid>)+#ccall git_tree_entry_2object , Ptr (Ptr <git_object>) -> Ptr <git_tree_entry> -> IO (CInt)+#ccall git_tree_add_entry , Ptr (Ptr <git_tree_entry>) -> Ptr <git_tree> -> Ptr <git_oid> -> CString -> CInt -> IO (CInt)+#ccall git_tree_remove_entry_byindex , Ptr <git_tree> -> CInt -> IO (CInt)+#ccall git_tree_remove_entry_byname , Ptr <git_tree> -> CString -> IO (CInt)+#ccall git_tree_clear_entries , Ptr <git_tree> -> IO ()+#ccall git_tree_entry_set_id , Ptr <git_tree_entry> -> Ptr <git_oid> -> IO ()+#ccall git_tree_entry_set_name , Ptr <git_tree_entry> -> CString -> IO ()+#ccall git_tree_entry_set_attributes , Ptr <git_tree_entry> -> CUInt -> IO (CInt)+#cinline git_tree_lookup , Ptr (Ptr <git_tree>) -> Ptr <git_repository> -> Ptr <git_oid> -> IO (CInt)+#cinline git_tree_new , Ptr (Ptr <git_tree>) -> Ptr <git_repository> -> IO (CInt)
+ Bindings/Libgit2/Tree.hsc.helper.c view
@@ -0,0 +1,6 @@++#include <bindings.cmacros.h>+#include <git2.h>++BC_INLINE3(git_tree_lookup, git_tree **, git_repository *, const git_oid *,int)+BC_INLINE2(git_tree_new, git_tree **, git_repository *,int)
+ Bindings/Libgit2/Types.hsc view
@@ -0,0 +1,76 @@++#include <bindings.dsl.h>+#include <git2.h>+module Bindings.Libgit2.Types where+#strict_import+++#integral_t git_off_t+{- typedef enum {+ GIT_OBJ_ANY = -2, /**< Object can be any of the following */+ GIT_OBJ_BAD = -1, /**< Object is invalid. */+ GIT_OBJ__EXT1 = 0, /**< Reserved for future use. */+ GIT_OBJ_COMMIT = 1, /**< A commit object. */+ GIT_OBJ_TREE = 2, /**< A tree (directory listing) object. */+ GIT_OBJ_BLOB = 3, /**< A file revision object. */+ GIT_OBJ_TAG = 4, /**< An annotated tag object. */+ GIT_OBJ__EXT2 = 5, /**< Reserved for future use. */+ GIT_OBJ_OFS_DELTA = 6, /**< A delta, base is given by an offset. */+ GIT_OBJ_REF_DELTA = 7, /**< A delta, base is given by object id. */+} git_otype; -}+#integral_t git_otype+#num GIT_OBJ_ANY+#num GIT_OBJ_BAD+#num GIT_OBJ__EXT1+#num GIT_OBJ_COMMIT+#num GIT_OBJ_TREE+#num GIT_OBJ_BLOB+#num GIT_OBJ_TAG+#num GIT_OBJ__EXT2+#num GIT_OBJ_OFS_DELTA+#num GIT_OBJ_REF_DELTA+{- typedef enum {+ GIT_REF_INVALID = 0, /** Invalid reference */+ GIT_REF_OID = 1, /** A reference which points at an object id */+ GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */+ GIT_REF_PACKED = 4,+ GIT_REF_HAS_PEEL = 8,+ GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,+} git_rtype; -}+#integral_t git_rtype+#num GIT_REF_INVALID+#num GIT_REF_OID+#num GIT_REF_SYMBOLIC+#num GIT_REF_PACKED+#num GIT_REF_HAS_PEEL+#num GIT_REF_LISTALL+#opaque_t git_odb+#opaque_t git_odb_backend+#opaque_t git_repository+#opaque_t git_object+#opaque_t git_revwalk+#opaque_t git_tag+#opaque_t git_blob+#opaque_t git_commit+#opaque_t git_tree_entry+#opaque_t git_tree+#opaque_t git_index+#opaque_t git_reference+{- typedef struct git_time {+ time_t time; + int offset; +} git_time; -}+#starttype git_time+#field time , CTime+#field offset , CInt+#stoptype+{- typedef struct git_signature {+ char *name; + char *email; + git_time when; +} git_signature; -}+#starttype git_signature+#field name , CString+#field email , CString+#field when , <git_time>+#stoptype
+ LICENSE view
@@ -0,0 +1,19 @@+Copyright (c) 2011 Sakari Jokinen, Jacob Stanley++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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hlibgit2.cabal view
@@ -0,0 +1,179 @@++Name: hlibgit2+Version: 0.1+Synopsis: Bindings to libgit2 v0.1.0-265-gb5c5f0f+Description: Generated bindings to libgit2.+License-file: LICENSE+License: MIT+Author: Sakari Jokinen, Jacob Stanley+Maintainer: sakariij@gmail.com+Build-Type: Simple+Cabal-Version: >=1.10+Category: FFI++extra-source-files:+ tests/Main.hs~+ tests/Main.hs+ tests/Main.o+ tests/Main.hi+ libgit2/include/git2.h+ libgit2/include/git2/refs.h+ libgit2/include/git2/odb.h+ libgit2/include/git2/types.h+ libgit2/include/git2/index.h+ libgit2/include/git2/thread-utils.h+ libgit2/include/git2/oid.h+ libgit2/include/git2/tag.h+ libgit2/include/git2/zlib.h+ libgit2/include/git2/object.h+ libgit2/include/git2/signature.h+ libgit2/include/git2/blob.h+ libgit2/include/git2/odb_backend.h+ libgit2/include/git2/repository.h+ libgit2/include/git2/common.h+ libgit2/include/git2/commit.h+ libgit2/include/git2/errors.h+ libgit2/include/git2/tree.h+ libgit2/include/git2/revwalk.h+ libgit2/src/cc-compat.h+ libgit2/src/refs.h+ libgit2/src/odb.h+ libgit2/src/delta-apply.h+ libgit2/src/index.h+ libgit2/src/thread-utils.h+ libgit2/src/vector.h+ libgit2/src/tag.h+ libgit2/src/dir.h+ libgit2/src/map.h+ libgit2/src/signature.h+ libgit2/src/blob.h+ libgit2/src/hash.h+ libgit2/src/fileops.h+ libgit2/src/repository.h+ libgit2/src/hashtable.h+ libgit2/src/common.h+ libgit2/src/util.h+ libgit2/src/bswap.h+ libgit2/src/t03-data.h+ libgit2/src/filebuf.h+ libgit2/src/mingw-compat.h+ libgit2/src/commit.h+ libgit2/src/pqueue.h+ libgit2/src/msvc-compat.h+ libgit2/src/tree.h+ libgit2/src/block-sha1/sha1.h+ libgit2/deps/zlib/inffixed.h+ libgit2/deps/zlib/zconf.h+ libgit2/deps/zlib/inflate.h+ libgit2/deps/zlib/inftrees.h+ libgit2/deps/zlib/zlib.h+ libgit2/deps/zlib/trees.h+ libgit2/deps/zlib/zutil.h+ libgit2/deps/zlib/inffast.h+ libgit2/deps/zlib/deflate.h+ libgit2/src/win32/pthread.h++Source-repository head+ type: git+ location: git://github.com/sakari/hlibgit2.git++Source-repository this+ type: git+ location: git://github.com/sakari/hlibgit2.git+ tag: hlibgit2-0.1++test-suite smoke+ default-language: Haskell98+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: tests+ build-depends:+ base >=3,+ hlibgit2,+ process++library+ default-language: Haskell98+ default-extensions:+ ForeignFunctionInterface+ build-depends:+ base >= 3 && < 5,+ bindings-DSL >= 1.0.9 && < 1.1+ exposed-modules:+ Bindings.Libgit2+ Bindings.Libgit2.Refs+ Bindings.Libgit2.Odb+ Bindings.Libgit2.Types+ Bindings.Libgit2.Index+ Bindings.Libgit2.ThreadUtils+ Bindings.Libgit2.Oid+ Bindings.Libgit2.Tag+ Bindings.Libgit2.Object+ Bindings.Libgit2.Signature+ Bindings.Libgit2.Blob+ Bindings.Libgit2.OdbBackend+ Bindings.Libgit2.Repository+ Bindings.Libgit2.Common+ Bindings.Libgit2.Commit+ Bindings.Libgit2.Errors+ Bindings.Libgit2.Tree+ Bindings.Libgit2.Revwalk+ c-sources:+ Bindings/Libgit2/Tag.hsc.helper.c+ Bindings/Libgit2/Blob.hsc.helper.c+ Bindings/Libgit2/Commit.hsc.helper.c+ Bindings/Libgit2/Tree.hsc.helper.c++ include-dirs:+ libgit2/include+ libgit2/src+ libgit2/src/block-sha1+ libgit2/deps/zlib+ c-sources:+ libgit2/src/hash.c+ libgit2/src/index.c+ libgit2/src/pqueue.c+ libgit2/src/filebuf.c+ libgit2/src/hashtable.c+ libgit2/src/util.c+ libgit2/src/errors.c+ libgit2/src/odb.c+ libgit2/src/delta-apply.c+ libgit2/src/odb_loose.c+ libgit2/src/tree.c+ libgit2/src/thread-utils.c+ libgit2/src/revwalk.c+ libgit2/src/oid.c+ libgit2/src/odb_pack.c+ libgit2/src/tag.c+ libgit2/src/signature.c+ libgit2/src/vector.c+ libgit2/src/blob.c+ libgit2/src/refs.c+ libgit2/src/repository.c+ libgit2/src/fileops.c+ libgit2/src/object.c+ libgit2/src/commit.c+ libgit2/src/block-sha1/sha1.c+ libgit2/deps/zlib/trees.c+ libgit2/deps/zlib/zutil.c+ libgit2/deps/zlib/inffast.c+ libgit2/deps/zlib/adler32.c+ libgit2/deps/zlib/deflate.c+ libgit2/deps/zlib/inflate.c+ libgit2/deps/zlib/inftrees.c++ if os(windows)+ cc-options: -DGIT_WIN32 -DNO_VIZ+ include-dirs:+ libgit2/src/win32+ c-sources:+ libgit2/src/win32/pthread.c+ libgit2/src/win32/dir.c+ libgit2/src/win32/fileops.c+ libgit2/src/win32/map.c+ else+ include-dirs:+ libgit2/src/unix+ c-sources:+ libgit2/src/unix/map.c
+ libgit2/deps/zlib/adler32.c view
@@ -0,0 +1,169 @@+/* adler32.c -- compute the Adler-32 checksum of a data stream+ * Copyright (C) 1995-2007 Mark Adler+ * For conditions of distribution and use, see copyright notice in zlib.h+ */++/* @(#) $Id$ */++#include "zutil.h"++#define local static++local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);++#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);+}++/* ========================================================================= */+local uLong adler32_combine_(adler1, adler2, len2)+ uLong adler1;+ uLong adler2;+ z_off64_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);+}++/* ========================================================================= */+uLong ZEXPORT adler32_combine(adler1, adler2, len2)+ uLong adler1;+ uLong adler2;+ z_off_t len2;+{+ return adler32_combine_(adler1, adler2, len2);+}++uLong ZEXPORT adler32_combine64(adler1, adler2, len2)+ uLong adler1;+ uLong adler2;+ z_off64_t len2;+{+ return adler32_combine_(adler1, adler2, len2);+}
+ libgit2/deps/zlib/deflate.c view
@@ -0,0 +1,1834 @@+/* deflate.c -- compress data using the deflation algorithm+ * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler+ * 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.5 Copyright 1995-2010 Jean-loup Gailly and 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.+ */++/* ===========================================================================+ * 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 block_state deflate_rle OF((deflate_state *s, int flush));+local block_state deflate_huff OF((deflate_state *s, int flush));+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));+#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++#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 */++/* 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)<<s->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->high_water = 0; /* nothing written to s->window yet */++ 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 > s->w_size) {+ length = s->w_size;+ 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 ((strategy != s->strategy || func != configuration_table[level].func) &&+ strm->total_in != 0) {+ /* Flush the last buffer: */+ err = deflate(strm, Z_BLOCK);+ }+ 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. 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 complen, wraplen;+ Bytef *str;++ /* conservative upper bound for compressed data */+ complen = sourceLen ++ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;++ /* if can't get parameters, return conservative bound plus zlib wrapper */+ if (strm == Z_NULL || strm->state == Z_NULL)+ return complen + 6;++ /* compute wrapper length */+ s = strm->state;+ switch (s->wrap) {+ case 0: /* raw deflate */+ wraplen = 0;+ break;+ case 1: /* zlib wrapper */+ wraplen = 6 + (s->strstart ? 4 : 0);+ break;+ case 2: /* gzip wrapper */+ wraplen = 18;+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */+ if (s->gzhead->extra != Z_NULL)+ wraplen += 2 + s->gzhead->extra_len;+ str = s->gzhead->name;+ if (str != Z_NULL)+ do {+ wraplen++;+ } while (*str++);+ str = s->gzhead->comment;+ if (str != Z_NULL)+ do {+ wraplen++;+ } while (*str++);+ if (s->gzhead->hcrc)+ wraplen += 2;+ }+ break;+ default: /* for compiler happiness */+ wraplen = 6;+ }++ /* if not default parameters, return conservative bound */+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)+ return complen + wraplen;++ /* default settings: return tight bound for that case */+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) ++ (sourceLen >> 25) + 13 - 6 + wraplen;+}++/* =========================================================================+ * 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_BLOCK || 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 == Z_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 != Z_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 != Z_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 != Z_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 != Z_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 = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :+ (*(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 if (flush != Z_BLOCK) { /* 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 */+ if (s->lookahead == 0) {+ s->strstart = 0;+ s->block_start = 0L;+ }+ }+ }+ 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 */++#else /* FASTEST */++/* ---------------------------------------------------------------------------+ * Optimized version for FASTEST only+ */+local uInt longest_match(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;+}++#endif /* FASTEST */++#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.)+ */+ 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);++ /* If the WIN_INIT bytes after the end of the current data have never been+ * written, then zero those bytes in order to avoid memory check reports of+ * the use of uninitialized (or uninitialised as Julian writes) bytes by+ * the longest match routines. Update the high water mark for the next+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.+ */+ if (s->high_water < s->window_size) {+ ulg curr = s->strstart + (ulg)(s->lookahead);+ ulg init;++ if (s->high_water < curr) {+ /* Previous high water mark below current data -- zero WIN_INIT+ * bytes or up to end of window, whichever is less.+ */+ init = s->window_size - curr;+ if (init > WIN_INIT)+ init = WIN_INIT;+ zmemzero(s->window + curr, (unsigned)init);+ s->high_water = curr + init;+ }+ else if (s->high_water < (ulg)curr + WIN_INIT) {+ /* High water mark at or above current data, but below current data+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up+ * to end of window, whichever is less.+ */+ init = (ulg)curr + WIN_INIT - s->high_water;+ if (init > s->window_size - s->high_water)+ init = s->window_size - s->high_water;+ zmemzero(s->window + s->high_water, (unsigned)init);+ s->high_water += init;+ }+ }+}++/* ===========================================================================+ * 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, last) { \+ _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), \+ (last)); \+ s->block_start = s->strstart; \+ flush_pending(s->strm); \+ Tracev((stderr,"[FLUSH]")); \+}++/* Same but force premature exit if necessary. */+#define FLUSH_BLOCK(s, last) { \+ FLUSH_BLOCK_ONLY(s, last); \+ if (s->strm->avail_out == 0) return (last) ? 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; /* 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:+ */+ hash_head = NIL;+ 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).+ */+ s->match_length = longest_match (s, hash_head);+ /* longest_match() 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; /* 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:+ */+ hash_head = NIL;+ 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).+ */+ s->match_length = longest_match (s, hash_head);+ /* longest_match() 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 */++/* ===========================================================================+ * 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 prev; /* byte at distance one to match */+ Bytef *scan, *strend; /* scan goes up to strend for length 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 */+ s->match_length = 0;+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {+ scan = s->window + s->strstart - 1;+ prev = *scan;+ if (prev == *++scan && prev == *++scan && prev == *++scan) {+ strend = s->window + s->strstart + MAX_MATCH;+ do {+ } while (prev == *++scan && prev == *++scan &&+ prev == *++scan && prev == *++scan &&+ prev == *++scan && prev == *++scan &&+ prev == *++scan && prev == *++scan &&+ scan < strend);+ s->match_length = MAX_MATCH - (int)(strend - scan);+ if (s->match_length > s->lookahead)+ s->match_length = s->lookahead;+ }+ }++ /* Emit match if have run of MIN_MATCH or longer, else emit literal */+ if (s->match_length >= MIN_MATCH) {+ check_match(s, s->strstart, s->strstart - 1, s->match_length);++ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);++ s->lookahead -= s->match_length;+ s->strstart += s->match_length;+ s->match_length = 0;+ } 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;+}++/* ===========================================================================+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.+ * (It will be regenerated if this run of deflate switches away from Huffman.)+ */+local block_state deflate_huff(s, flush)+ deflate_state *s;+ int flush;+{+ int bflush; /* set if current block must be flushed */++ for (;;) {+ /* Make sure that we have a literal to write. */+ if (s->lookahead == 0) {+ fill_window(s);+ if (s->lookahead == 0) {+ if (flush == Z_NO_FLUSH)+ return need_more;+ break; /* flush the current block */+ }+ }++ /* Output a literal byte */+ s->match_length = 0;+ 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;+}
+ libgit2/deps/zlib/deflate.h view
@@ -0,0 +1,342 @@+/* deflate.h -- internal compression state+ * Copyright (C) 1995-2010 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.+ */++ ulg high_water;+ /* High water mark offset in window for initialized bytes -- bytes above+ * this are set to zero in order to avoid memory check warnings when+ * longest match routines access bytes past the input. This is then+ * updated to the new high water mark.+ */++} 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.+ */++#define WIN_INIT MAX_MATCH+/* Number of bytes after end of data in window to initialize in order to avoid+ memory checker errors from longest match routines */++ /* in trees.c */+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,+ ulg stored_len, int last));+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,+ ulg stored_len, int last));++#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 ZLIB_INTERNAL _length_code[];+ extern uch ZLIB_INTERNAL _dist_code[];+#else+ extern const uch ZLIB_INTERNAL _length_code[];+ extern const uch ZLIB_INTERNAL _dist_code[];+#endif++# define _tr_tally_lit(s, c, flush) \+ { uch cc = (uch)(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 = (uch)(length); \+ ush dist = (ush)(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 */
+ libgit2/deps/zlib/inffast.c view
@@ -0,0 +1,340 @@+/* inffast.c -- fast decoding+ * Copyright (C) 1995-2008, 2010 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 ZLIB_INTERNAL 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 wnext; /* 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 here; /* 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;+ wnext = state->wnext;+ 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;+ }+ here = lcode[hold & lmask];+ dolen:+ op = (unsigned)(here.bits);+ hold >>= op;+ bits -= op;+ op = (unsigned)(here.op);+ if (op == 0) { /* literal */+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?+ "inflate: literal '%c'\n" :+ "inflate: literal 0x%02x\n", here.val));+ PUP(out) = (unsigned char)(here.val);+ }+ else if (op & 16) { /* length base */+ len = (unsigned)(here.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;+ }+ here = dcode[hold & dmask];+ dodist:+ op = (unsigned)(here.bits);+ hold >>= op;+ bits -= op;+ op = (unsigned)(here.op);+ if (op & 16) { /* distance base */+ dist = (unsigned)(here.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) {+ if (state->sane) {+ strm->msg =+ (char *)"invalid distance too far back";+ state->mode = BAD;+ break;+ }+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR+ if (len <= op - whave) {+ do {+ PUP(out) = 0;+ } while (--len);+ continue;+ }+ len -= op - whave;+ do {+ PUP(out) = 0;+ } while (--op > whave);+ if (op == 0) {+ from = out - dist;+ do {+ PUP(out) = PUP(from);+ } while (--len);+ continue;+ }+#endif+ }+ from = window - OFF;+ if (wnext == 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 (wnext < op) { /* wrap around window */+ from += wsize + wnext - op;+ op -= wnext;+ if (op < len) { /* some from end of window */+ len -= op;+ do {+ PUP(out) = PUP(from);+ } while (--op);+ from = window - OFF;+ if (wnext < len) { /* some from start of window */+ op = wnext;+ len -= op;+ do {+ PUP(out) = PUP(from);+ } while (--op);+ from = out - dist; /* rest from output */+ }+ }+ }+ else { /* contiguous in window */+ from += wnext - 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 */+ here = dcode[here.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 */+ here = lcode[here.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 wnext == 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 */
+ libgit2/deps/zlib/inffast.h view
@@ -0,0 +1,11 @@+/* inffast.h -- header to use inffast.c+ * Copyright (C) 1995-2003, 2010 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 ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
+ libgit2/deps/zlib/inffixed.h view
@@ -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}+ };
+ libgit2/deps/zlib/inflate.c view
@@ -0,0 +1,1480 @@+/* inflate.c -- zlib decompression+ * Copyright (C) 1995-2010 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 wnext == 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->wnext = 0;+ state->hold = 0;+ state->bits = 0;+ state->lencode = state->distcode = state->next = state->codes;+ state->sane = 1;+ state->back = -1;+ Tracev((stderr, "inflate: reset\n"));+ return Z_OK;+}++int ZEXPORT inflateReset2(strm, windowBits)+z_streamp strm;+int windowBits;+{+ int wrap;+ struct inflate_state FAR *state;++ /* get the state */+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;+ state = (struct inflate_state FAR *)strm->state;++ /* extract wrap request from windowBits parameter */+ if (windowBits < 0) {+ wrap = 0;+ windowBits = -windowBits;+ }+ else {+ wrap = (windowBits >> 4) + 1;+#ifdef GUNZIP+ if (windowBits < 48)+ windowBits &= 15;+#endif+ }++ /* set number of window bits, free window if different */+ if (windowBits && (windowBits < 8 || windowBits > 15))+ return Z_STREAM_ERROR;+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {+ ZFREE(strm, state->window);+ state->window = Z_NULL;+ }++ /* update state and reset the rest of it */+ state->wrap = wrap;+ state->wbits = (unsigned)windowBits;+ return inflateReset(strm);+}++int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)+z_streamp strm;+int windowBits;+const char *version;+int stream_size;+{+ int ret;+ 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;+ state->window = Z_NULL;+ ret = inflateReset2(strm, windowBits);+ if (ret != Z_OK) {+ ZFREE(strm, state);+ strm->state = Z_NULL;+ }+ return ret;+}++int ZEXPORT inflateInit_(strm, version, stream_size)+z_streamp strm;+const char *version;+int stream_size;+{+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);+}++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 < 0) {+ state->hold = 0;+ state->bits = 0;+ return Z_OK;+ }+ 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;+}++/*+ 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 <stdio.h>++/*+ 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->wnext = 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->wnext = 0;+ state->whave = state->wsize;+ }+ else {+ dist = state->wsize - state->wnext;+ if (dist > copy) dist = copy;+ zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);+ copy -= dist;+ if (copy) {+ zmemcpy(state->window, strm->next_out - copy, copy);+ state->wnext = copy;+ state->whave = state->wsize;+ }+ else {+ state->wnext += dist;+ if (state->wnext == state->wsize) state->wnext = 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 here; /* 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 (state->wbits == 0)+ state->wbits = len;+ else 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 || flush == Z_TREES) 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 */+ if (flush == Z_TREES) {+ DROPBITS(2);+ goto inf_leave;+ }+ 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_;+ if (flush == Z_TREES) goto inf_leave;+ case COPY_:+ 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 (;;) {+ here = state->lencode[BITS(state->lenbits)];+ if ((unsigned)(here.bits) <= bits) break;+ PULLBYTE();+ }+ if (here.val < 16) {+ NEEDBITS(here.bits);+ DROPBITS(here.bits);+ state->lens[state->have++] = here.val;+ }+ else {+ if (here.val == 16) {+ NEEDBITS(here.bits + 2);+ DROPBITS(here.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 (here.val == 17) {+ NEEDBITS(here.bits + 3);+ DROPBITS(here.bits);+ len = 0;+ copy = 3 + BITS(3);+ DROPBITS(3);+ }+ else {+ NEEDBITS(here.bits + 7);+ DROPBITS(here.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;++ /* check for end-of-block code (better have one) */+ if (state->lens[256] == 0) {+ strm->msg = (char *)"invalid code -- missing end-of-block";+ state->mode = BAD;+ break;+ }++ /* build code tables -- note: do not change the lenbits or distbits+ values here (9 and 6) without reading the comments in inftrees.h+ concerning the ENOUGH constants, which depend on those values */+ 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_;+ if (flush == Z_TREES) goto inf_leave;+ case LEN_:+ state->mode = LEN;+ case LEN:+ if (have >= 6 && left >= 258) {+ RESTORE();+ inflate_fast(strm, out);+ LOAD();+ if (state->mode == TYPE)+ state->back = -1;+ break;+ }+ state->back = 0;+ for (;;) {+ here = state->lencode[BITS(state->lenbits)];+ if ((unsigned)(here.bits) <= bits) break;+ PULLBYTE();+ }+ if (here.op && (here.op & 0xf0) == 0) {+ last = here;+ for (;;) {+ here = state->lencode[last.val ++ (BITS(last.bits + last.op) >> last.bits)];+ if ((unsigned)(last.bits + here.bits) <= bits) break;+ PULLBYTE();+ }+ DROPBITS(last.bits);+ state->back += last.bits;+ }+ DROPBITS(here.bits);+ state->back += here.bits;+ state->length = (unsigned)here.val;+ if ((int)(here.op) == 0) {+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?+ "inflate: literal '%c'\n" :+ "inflate: literal 0x%02x\n", here.val));+ state->mode = LIT;+ break;+ }+ if (here.op & 32) {+ Tracevv((stderr, "inflate: end of block\n"));+ state->back = -1;+ state->mode = TYPE;+ break;+ }+ if (here.op & 64) {+ strm->msg = (char *)"invalid literal/length code";+ state->mode = BAD;+ break;+ }+ state->extra = (unsigned)(here.op) & 15;+ state->mode = LENEXT;+ case LENEXT:+ if (state->extra) {+ NEEDBITS(state->extra);+ state->length += BITS(state->extra);+ DROPBITS(state->extra);+ state->back += state->extra;+ }+ Tracevv((stderr, "inflate: length %u\n", state->length));+ state->was = state->length;+ state->mode = DIST;+ case DIST:+ for (;;) {+ here = state->distcode[BITS(state->distbits)];+ if ((unsigned)(here.bits) <= bits) break;+ PULLBYTE();+ }+ if ((here.op & 0xf0) == 0) {+ last = here;+ for (;;) {+ here = state->distcode[last.val ++ (BITS(last.bits + last.op) >> last.bits)];+ if ((unsigned)(last.bits + here.bits) <= bits) break;+ PULLBYTE();+ }+ DROPBITS(last.bits);+ state->back += last.bits;+ }+ DROPBITS(here.bits);+ state->back += here.bits;+ if (here.op & 64) {+ strm->msg = (char *)"invalid distance code";+ state->mode = BAD;+ break;+ }+ state->offset = (unsigned)here.val;+ state->extra = (unsigned)(here.op) & 15;+ state->mode = DISTEXT;+ case DISTEXT:+ if (state->extra) {+ NEEDBITS(state->extra);+ state->offset += BITS(state->extra);+ DROPBITS(state->extra);+ state->back += state->extra;+ }+#ifdef INFLATE_STRICT+ if (state->offset > state->dmax) {+ strm->msg = (char *)"invalid distance too far back";+ state->mode = BAD;+ break;+ }+#endif+ 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->whave) {+ if (state->sane) {+ strm->msg = (char *)"invalid distance too far back";+ state->mode = BAD;+ break;+ }+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR+ Trace((stderr, "inflate.c too far\n"));+ copy -= state->whave;+ if (copy > state->length) copy = state->length;+ if (copy > left) copy = left;+ left -= copy;+ state->length -= copy;+ do {+ *put++ = 0;+ } while (--copy);+ if (state->length == 0) state->mode = LEN;+ break;+#endif+ }+ if (copy > state->wnext) {+ copy -= state->wnext;+ from = state->window + (state->wsize - copy);+ }+ else+ from = state->window + (state->wnext - 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) ++ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 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;+}++int ZEXPORT inflateUndermine(strm, subvert)+z_streamp strm;+int subvert;+{+ struct inflate_state FAR *state;++ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;+ state = (struct inflate_state FAR *)strm->state;+ state->sane = !subvert;+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR+ return Z_OK;+#else+ state->sane = 1;+ return Z_DATA_ERROR;+#endif+}++long ZEXPORT inflateMark(strm)+z_streamp strm;+{+ struct inflate_state FAR *state;++ if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;+ state = (struct inflate_state FAR *)strm->state;+ return ((long)(state->back) << 16) ++ (state->mode == COPY ? state->length :+ (state->mode == MATCH ? state->was - state->length : 0));+}
+ libgit2/deps/zlib/inflate.h view
@@ -0,0 +1,122 @@+/* inflate.h -- internal inflate state definition+ * Copyright (C) 1995-2009 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: same as COPY below, but only first time in */+ 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: same as LEN below, but only first time in */+ LEN, /* i: waiting for length/lit/eob 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 BAD or MEM on error -- not shown for clarity)++ Process header:+ HEAD -> (gzip) or (zlib) or (raw)+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->+ HCRC -> TYPE+ (zlib) -> DICTID or TYPE+ DICTID -> DICT -> TYPE+ (raw) -> TYPEDO+ Read deflate blocks:+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK+ STORED -> COPY_ -> COPY -> TYPE+ TABLE -> LENLENS -> CODELENS -> LEN_+ LEN_ -> LEN+ Read deflate codes in fixed or dynamic block:+ LEN -> LENEXT or LIT or TYPE+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN+ LIT -> LEN+ Process trailer:+ CHECK -> LENGTH -> DONE+ */++/* state maintained between inflate() calls. Approximately 10K 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 wnext; /* 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 */+ int sane; /* if false, allow invalid distance too far */+ int back; /* bits back of last unprocessed length/lit */+ unsigned was; /* initial length of match */+};
+ libgit2/deps/zlib/inftrees.c view
@@ -0,0 +1,330 @@+/* inftrees.c -- generate Huffman trees for efficient decoding+ * Copyright (C) 1995-2010 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.5 Copyright 1995-2010 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 ZLIB_INTERNAL 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 here; /* 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, 73, 195};+ 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 */+ here.op = (unsigned char)64; /* invalid code marker */+ here.bits = (unsigned char)1;+ here.val = (unsigned short)0;+ *(*table)++ = here; /* make a table to force an error */+ *(*table)++ = here;+ *bits = 1;+ return 0; /* no symbols, but wait for decoding to report error */+ }+ for (min = 1; min < max; 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 for LENS and DIST tables against+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in+ the initial root table size constants. See the comments in inftrees.h+ for more information.++ 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_LENS) ||+ (type == DISTS && used >= ENOUGH_DISTS))+ return 1;++ /* process all codes and make table entries */+ for (;;) {+ /* create table entry */+ here.bits = (unsigned char)(len - drop);+ if ((int)(work[sym]) < end) {+ here.op = (unsigned char)0;+ here.val = work[sym];+ }+ else if ((int)(work[sym]) > end) {+ here.op = (unsigned char)(extra[work[sym]]);+ here.val = base[work[sym]];+ }+ else {+ here.op = (unsigned char)(32 + 64); /* end of block */+ here.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] = here;+ } 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_LENS) ||+ (type == DISTS && used >= ENOUGH_DISTS))+ 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.+ */+ here.op = (unsigned char)64; /* invalid code marker */+ here.bits = (unsigned char)(len - drop);+ here.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;+ here.bits = (unsigned char)len;+ }++ /* put invalid code marker in table */+ next[huff >> drop] = here;++ /* 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;+}
+ libgit2/deps/zlib/inftrees.h view
@@ -0,0 +1,62 @@+/* inftrees.h -- header to use inftrees.c+ * Copyright (C) 1995-2005, 2010 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 the dynamic table. The maximum number of code structures is+ 1444, which is the sum of 852 for literal/length codes and 592 for distance+ codes. These values were found by exhaustive searches using the program+ examples/enough.c found in the zlib distribtution. The arguments to that+ program are the number of symbols, the initial root table size, and the+ maximum bit length of a code. "enough 286 9 15" for literal/length codes+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.+ The initial root table size (9 or 6) is found in the fifth argument of the+ inflate_table() calls in inflate.c and infback.c. If the root table size is+ changed, then these maximum sizes would be need to be recalculated and+ updated. */+#define ENOUGH_LENS 852+#define ENOUGH_DISTS 592+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)++/* Type of code to build for inflate_table() */+typedef enum {+ CODES,+ LENS,+ DISTS+} codetype;++int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,+ unsigned codes, code FAR * FAR *table,+ unsigned FAR *bits, unsigned short FAR *work));
+ libgit2/deps/zlib/trees.c view
@@ -0,0 +1,1244 @@+/* trees.c -- output deflated data using Huffman coding+ * Copyright (C) 1995-2010 Jean-loup Gailly+ * detect_data_type() function provided freely by Cosmin Truta, 2006+ * 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 <ctype.h>+#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 int detect_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 |= (ush)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 |= (ush)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 |= (ush)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 |= (ush)(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: */+#ifdef NO_INIT_GLOBAL_POINTERS+ 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;+#endif++ /* 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<<extra_lbits[code]); n++) {+ _length_code[length++] = (uch)code;+ }+ }+ Assert (length == 256, "tr_static_init: length != 256");+ /* Note that the length 255 (match length 258) can be represented+ * in two different ways: code 284 + 5 bits or code 285, so we+ * overwrite length_code[255] to use the best encoding:+ */+ _length_code[length-1] = (uch)code;++ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */+ dist = 0;+ for (code = 0 ; code < 16; code++) {+ base_dist[code] = dist;+ for (n = 0; n < (1<<extra_dbits[code]); n++) {+ _dist_code[dist++] = (uch)code;+ }+ }+ Assert (dist == 256, "tr_static_init: dist != 256");+ dist >>= 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 <stdio.h>+# 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 ZLIB_INTERNAL _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 ZLIB_INTERNAL _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 ZLIB_INTERNAL _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<<MAX_BITS)-1,+ "inconsistent bit counts");+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));++ for (n = 0; n <= max_code; n++) {+ int len = tree[n].Len;+ if (len == 0) continue;+ /* Now reverse the bits */+ tree[n].Code = (ush)bi_reverse(next_code[len]++, len);++ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));+ }+}++/* ===========================================================================+ * Construct one Huffman tree and assigns the code bit strings and lengths.+ * Update the total bit length for the current block.+ * IN assertion: the field freq is set for all tree elements.+ * OUT assertions: the fields len and code are set to the optimal bit length+ * and corresponding code. The length opt_len is updated; static_len is+ * also updated if stree is not null. The field max_code is set.+ */+local void build_tree(s, desc)+ deflate_state *s;+ tree_desc *desc; /* the tree descriptor */+{+ ct_data *tree = desc->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 += (ush)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 ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)+ deflate_state *s;+ charf *buf; /* input block */+ ulg stored_len; /* length of input block */+ int last; /* one if this is the last block for a file */+{+ send_bits(s, (STORED_BLOCK<<1)+last, 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 ZLIB_INTERNAL _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 ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)+ deflate_state *s;+ charf *buf; /* input block, or NULL if too old */+ ulg stored_len; /* length of input block */+ int last; /* one 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 (s->strm->data_type == Z_UNKNOWN)+ s->strm->data_type = detect_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, last);++#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)+last, 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)+last, 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 (last) {+ 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*last));+}++/* ===========================================================================+ * Save the match info and tally the frequency counts. Return true if+ * the current block must be flushed.+ */+int ZLIB_INTERNAL _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;+}++/* ===========================================================================+ * Check if the data type is TEXT or BINARY, using the following algorithm:+ * - TEXT if the two conditions below are satisfied:+ * a) There are no non-portable control characters belonging to the+ * "black list" (0..6, 14..25, 28..31).+ * b) There is at least one printable character belonging to the+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).+ * - BINARY otherwise.+ * - The following partially-portable control characters form a+ * "gray list" that is ignored in this detection algorithm:+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).+ * IN assertion: the fields Freq of dyn_ltree are set.+ */+local int detect_data_type(s)+ deflate_state *s;+{+ /* black_mask is the bit mask of black-listed bytes+ * set bits 0..6, 14..25, and 28..31+ * 0xf3ffc07f = binary 11110011111111111100000001111111+ */+ unsigned long black_mask = 0xf3ffc07fUL;+ int n;++ /* Check for non-textual ("black-listed") bytes. */+ for (n = 0; n <= 31; n++, black_mask >>= 1)+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))+ return Z_BINARY;++ /* Check for textual ("white-listed") bytes. */+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0+ || s->dyn_ltree[13].Freq != 0)+ return Z_TEXT;+ for (n = 32; n < LITERALS; n++)+ if (s->dyn_ltree[n].Freq != 0)+ return Z_TEXT;++ /* There are no "black-listed" or "white-listed" bytes:+ * this stream either is empty or has tolerated ("gray-listed") bytes only.+ */+ return 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++);+ }+}
+ libgit2/deps/zlib/trees.h view
@@ -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 ZLIB_INTERNAL _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 ZLIB_INTERNAL _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+};+
+ libgit2/deps/zlib/zconf.h view
@@ -0,0 +1,57 @@+/* zconf.h -- configuration of the zlib compression library+ * Copyright (C) 1995-2010 Jean-loup Gailly.+ * For conditions of distribution and use, see copyright notice in zlib.h+ */++/* @(#) $Id$ */++#ifndef ZCONF_H+#define ZCONF_H++#include "../../src/common.h"++#define NO_GZIP+#define STDC++/* Jeez, don't complain about non-prototype+ * forms, we didn't write zlib */+#if defined(_MSC_VER)+# pragma warning( disable : 4131 )+#endif++/* Maximum value for memLevel in deflateInit2 */+#define MAX_MEM_LEVEL 9++/* 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.)+ */+#define MAX_WBITS 15 /* 32K LZ77 window */++#define ZEXTERN extern+#define ZEXPORT+#define ZEXPORTVA+#ifndef FAR+# define FAR+#endif+#define OF(args) args++typedef unsigned char Byte; /* 8 bits */+typedef unsigned int uInt; /* 16 bits or more */+typedef unsigned long uLong; /* 32 bits or more */++typedef Byte FAR Bytef;+typedef char FAR charf;+typedef int FAR intf;+typedef uInt FAR uIntf;+typedef uLong FAR uLongf;++typedef void const *voidpc;+typedef void FAR *voidpf;+typedef void *voidp;++#define z_off_t git_off_t+#define z_off64_t z_off_t++#endif /* ZCONF_H */
+ libgit2/deps/zlib/zlib.h view
@@ -0,0 +1,1613 @@+/* zlib.h -- interface of the 'zlib' general purpose compression library+ version 1.2.5, April 19th, 2010++ Copyright (C) 1995-2010 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.5"+#define ZLIB_VERNUM 0x1250+#define ZLIB_VER_MAJOR 1+#define ZLIB_VER_MINOR 2+#define ZLIB_VER_REVISION 5+#define ZLIB_VER_SUBREVISION 0++/*+ 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,+ 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+#define Z_SYNC_FLUSH 2+#define Z_FULL_FLUSH 3+#define Z_FINISH 4+#define Z_BLOCK 5+#define Z_TREES 6+/* 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, or+ 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 accumulate 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. This+ completes the current deflate block and follows it with an empty stored block+ that is three bits plus filler bits to the next byte, followed by four bytes+ (00 00 ff ff).++ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the+ output buffer, but the output is not aligned to a byte boundary. All of the+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.+ This completes the current deflate block and follows it with an empty fixed+ codes block that is 10 bits long. This assures that enough bytes are output+ in order for the decompressor to finish the block before the empty fixed code+ block.++ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to+ seven bits of the current block are held to be written as the next byte after+ the next deflate block is completed. In this case, the decompressor may not+ be provided enough bits at this point in order to complete decompression of+ the data provided so far to the compressor. It may need to wait for the next+ block to be emitted. This is for advanced applications that need to control+ the emission of deflate blocks.++ 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 Z_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, or Z_STREAM_ERROR if the parameters are+ invalid, such as a null pointer to the structure. msg is set to null if+ there is no error message. inflateInit does not perform any decompression+ apart from possibly reading the zlib header if present: actual decompression+ will be done by inflate(). (So next_in and avail_in may be modified, but+ next_out and avail_out are unused and unchanged.) The current implementation+ of inflateInit() does not process any header information -- that is deferred+ until inflate() is called.+*/+++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,+ Z_BLOCK, or Z_TREES. 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. data_type is set as noted here every time inflate() returns for all+ flush options, and so can be used to determine the amount of currently+ consumed input in bits.++ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the+ end of each deflate block header is reached, before any actual data in that+ block is decoded. This allows the caller to determine the length of the+ deflate block header for later use in random access within a deflate block.+ 256 is added to the value of strm->data_type when inflate() returns+ immediately after reaching the end of the deflate block header.++ 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 or Z_TREES 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() can decompress and check either zlib-wrapped or gzip-wrapped+ deflate data. The header type is detected automatically, if requested when+ initializing with inflateInit2(). 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+ next_in or next_out was Z_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_STRATEGY 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 any parameter is invalid (such as an invalid+ method), or 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. 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+ provided in deflateInit or deflateInit2. 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 (e.g. dictionary being Z_NULL) 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 Z_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 Z_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(), and after deflateSetHeader(), if used. 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 zero to request that inflate use the window size in+ the zlib header of the compressed stream.++ 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_VERSION_ERROR if the zlib library version is incompatible with the+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are+ invalid, such as a null pointer to the structure. msg is set to null if+ there is no error message. inflateInit2 does not perform any decompression+ apart from possibly reading the zlib header if present: actual decompression+ will be done by inflate(). (So next_in and avail_in may be modified, but+ next_out and avail_out are unused and unchanged.) The current implementation+ of inflateInit2() does not process any header information -- that is+ deferred until inflate() is called.+*/++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 (e.g. dictionary being Z_NULL) 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 Z_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 Z_NULL).+*/++ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,+ int windowBits));+/*+ This function is the same as inflateReset, but it also permits changing+ the wrap and window size requests. The windowBits parameter is interpreted+ the same as it is for inflateInit2.++ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if+ the windowBits parameter is invalid.+*/++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.++ If bits is negative, then the input stream bit buffer is emptied. Then+ inflatePrime() can be called again to put bits in the buffer. This is used+ to clear out bits leftover after feeding inflate a block description prior+ to feeding inflate codes.++ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source+ stream state was inconsistent.+*/++ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));+/*+ This function returns two values, one in the lower 16 bits of the return+ value, and the other in the remaining upper bits, obtained by shifting the+ return value down 16 bits. If the upper value is -1 and the lower value is+ zero, then inflate() is currently decoding information outside of a block.+ If the upper value is -1 and the lower value is non-zero, then inflate is in+ the middle of a stored block, with the lower value equaling the number of+ bytes from the input remaining to copy. If the upper value is not -1, then+ it is the number of bits back from the current bit position in the input of+ the code (literal or length/distance pair) currently being processed. In+ that case the lower value is the number of bytes already emitted for that+ code.++ A code is being processed if inflate is waiting for more input to complete+ decoding of the code, or if it has completed decoding but is waiting for+ more output space to write the literal or match data.++ inflateMark() is used to mark locations in the input data for random+ access, which may be at bit positions, and to note those cases where the+ output of a code may span boundaries of random access blocks. The current+ location in the input stream can be determined from avail_in and data_type+ as noted in the description for the Z_BLOCK flush parameter for inflate.++ inflateMark returns the value noted above or -1 << 16 if the provided+ 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 or Z_TREES 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_in 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 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.++ 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 uncompressed buffer.++ 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.+*/+++ /* gzip file access functions */++/*+ This library 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.+*/++typedef voidp gzFile; /* opaque gzip file descriptor */++/*+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", 'R' for run-length encoding as in "wb1R", or 'F'+ for fixed code compression as in "wb9F". (See the description of+ deflateInit2 for more information about the strategy parameter.) Also "a"+ can be used instead of "w" to request that the gzip stream that will be+ written be appended to the file. "+" will result in an error, since reading+ and writing to the same gzip file is not supported.++ 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, if there was+ insufficient memory to allocate the gzFile state, or if an invalid mode was+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).+ errno can be checked to determine if the reason gzopen failed was that the+ file could not be opened.+*/++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 (if 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 fd = dup(fd_keep); gz = gzdopen(fd,+ mode);. The duplicated descriptor should be saved to avoid a leak, since+ gzdopen does not close fd if it fails.++ gzdopen returns NULL if there was insufficient memory to allocate the+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not+ provided, or '+' was provided), or if fd is -1. The file descriptor is not+ used until the next gz* read, write, seek, or close operation, so gzdopen+ will not detect if fd is invalid (unless fd is -1).+*/++ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));+/*+ Set the internal buffer size used by this library's functions. The+ default buffer size is 8192 bytes. This function must be called after+ gzopen() or gzdopen(), and before any other calls that read or write the+ file. The buffer memory allocation is always deferred to the first read or+ write. Two buffers are allocated, either both of the specified size when+ writing, or one of the specified size and the other twice that size when+ reading. A larger buffer size of, for example, 64K or 128K bytes will+ noticeably increase the speed of decompression (reading).++ The new buffer size also affects the maximum length for gzprintf().++ gzbuffer() returns 0 on success, or -1 on failure, such as being called+ too late.+*/++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.++ After reaching the end of a gzip stream in the input, gzread will continue+ to read, looking for another gzip stream, or failing that, reading the rest+ of the input file directly without decompression. The entire input file+ will be read if gzread is called until it returns less than the requested+ len.++ gzread returns the number of uncompressed bytes actually read, less than+ len for end of file, or -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 written or 0 in case of+ error.+*/++ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));+/*+ Converts, formats, and writes the arguments to the compressed file under+ control of the format string, as in fprintf. gzprintf returns the number of+ uncompressed bytes actually written, or 0 in case of error. The number of+ uncompressed bytes written is limited to 8191, or one less than the buffer+ size given to gzbuffer(). The caller should assure that this limit is not+ exceeded. If it is exceeded, then gzprintf() will 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. This can be determined using+ zlibCompileFlags().+*/++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. If any characters are read or if len == 1, the+ string is terminated with a null character. If no characters are read due+ to an end-of-file or len < 1, then the buffer is left untouched.++ gzgets returns buf which is a null-terminated string, or it returns NULL+ for end-of-file or in case of error. If there was an error, the contents at+ buf are indeterminate.+*/++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 as the first character+ on the next read. At least one character of push-back is allowed.+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will+ fail if c is -1, and may fail if a character has been pushed but not read+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the+ output buffer size of pushed characters is allowed. (See gzbuffer above.)+ 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 is only permitted when writing.++ If the flush parameter is Z_FINISH, the remaining data is written and the+ gzip stream is completed in the output. If gzwrite() is called again, a new+ gzip stream will be started in the output. gzread() is able to read such+ concatented gzip streams.++ gzflush should be called only when strictly necessary because it will+ degrade compression if called too often.+*/++/*+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, and is zero when starting, even if appending or+ reading a gzip stream from the middle of a file using gzdopen().++ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)+*/++/*+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));++ Returns the current offset in the file being read or written. This offset+ includes the count of bytes that precede the gzip stream, for example when+ appending or when using gzdopen() for reading. When reading, the offset+ does not include as yet unused buffered input. This information can be used+ for a progress indicator. On error, gzoffset() returns -1.+*/++ZEXTERN int ZEXPORT gzeof OF((gzFile file));+/*+ Returns true (1) if the end-of-file indicator has been set while reading,+ false (0) otherwise. Note that the end-of-file indicator is set only if the+ read tried to go past the end of the input, but came up short. Therefore,+ just like feof(), gzeof() may return false even if there is no more data to+ read, in the event that the last read request was for the exact number of+ bytes remaining in the input file. This will happen if the input file size+ is an exact multiple of the buffer size.++ If gzeof() returns true, then the read functions will return no more data,+ unless the end-of-file indicator is reset by gzclearerr() and the input file+ has grown since the previous end of file was detected.+*/++ZEXTERN int ZEXPORT gzdirect OF((gzFile file));+/*+ Returns true (1) if file is being copied directly while reading, or false+ (0) if file is a gzip stream being decompressed. This state can change from+ false to true while reading the input file if the end of a gzip stream is+ reached, but is followed by data that is not another gzip stream.++ If the input file is empty, gzdirect() will return true, since the input+ does not contain a gzip stream.++ If gzdirect() is used immediately after gzopen() or gzdopen() it will+ cause buffers to be allocated to allow reading the file to determine if it+ is a gzip file. Therefore if gzbuffer() is used, it should be called before+ gzdirect().+*/++ZEXTERN int ZEXPORT gzclose OF((gzFile file));+/*+ Flushes all pending output if necessary, closes the compressed file and+ deallocates the (de)compression state. Note that once file is closed, you+ cannot call gzerror with file, since its structures have been deallocated.+ gzclose must not be called more than once on the same file, just as free+ must not be called more than once on the same allocation.++ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a+ file operation error, or Z_OK on success.+*/++ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));+/*+ Same as gzclose(), but gzclose_r() is only for use when reading, and+ gzclose_w() is only for use when writing or appending. The advantage to+ using these instead of gzclose() is that they avoid linking in zlib+ compression or decompression code that is not used when only reading or only+ writing respectively. If gzclose() is used, then both compression and+ decompression code will be included the application when linking to a static+ zlib library.+*/++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.++ The application must not modify the returned string. Future calls to+ this function may invalidate the previously returned string. If file is+ closed, then the string previously returned by gzerror will no longer be+ available.++ gzerror() should be used to distinguish errors from end-of-file for those+ functions above that do not distinguish those cases in their return values.+*/++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 Z_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 Z_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))++/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if+ * both are true, the application gets the *64 functions, and the regular+ * functions are changed to 64 bits) -- in case these are set on systems+ * without large file support, _LFS64_LARGEFILE must also be true+ */+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));+#endif++#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0+# define gzopen gzopen64+# define gzseek gzseek64+# define gztell gztell64+# define gzoffset gzoffset64+# define adler32_combine adler32_combine64+# define crc32_combine crc32_combine64+# ifdef _LARGEFILE64_SOURCE+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));+# endif+#else+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));+#endif++/* hack for buggy compilers */+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)+ struct internal_state {int dummy;};+#endif++/* undocumented functions */+ZEXTERN const char * ZEXPORT zError OF((int));+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));++#ifdef __cplusplus+}+#endif++#endif /* ZLIB_H */
+ libgit2/deps/zlib/zutil.c view
@@ -0,0 +1,318 @@+/* zutil.c -- target dependent utility functions for the compression library+ * Copyright (C) 1995-2005, 2010 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 ((int)(sizeof(uInt))) {+ case 2: break;+ case 4: flags += 1; break;+ case 8: flags += 2; break;+ default: flags += 3;+ }+ switch ((int)(sizeof(uLong))) {+ case 2: break;+ case 4: flags += 1 << 2; break;+ case 8: flags += 2 << 2; break;+ default: flags += 3 << 2;+ }+ switch ((int)(sizeof(voidpf))) {+ case 2: break;+ case 4: flags += 1 << 4; break;+ case 8: flags += 2 << 4; break;+ default: flags += 3 << 4;+ }+ switch ((int)(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 ZLIB_INTERNAL z_verbose = verbose;++void ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)+{+ if (opaque) opaque = 0; /* to make compiler happy */+ return _halloc((long)items, size);+}++void ZLIB_INTERNAL 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 ZLIB_INTERNAL 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 ZLIB_INTERNAL zcfree (opaque, ptr)+ voidpf opaque;+ voidpf ptr;+{+ free(ptr);+ if (opaque) return; /* make compiler happy */+}++#endif /* MY_ZCALLOC */
+ libgit2/deps/zlib/zutil.h view
@@ -0,0 +1,274 @@+/* zutil.h -- internal interface and configuration of the compression library+ * Copyright (C) 1995-2010 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++#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))+#else+# define ZLIB_INTERNAL+#endif++#include "zlib.h"++#ifdef STDC+# if !(defined(_WIN32_WCE) && defined(_MSC_VER))+# include <stddef.h>+# endif+# include <string.h>+# include <stdlib.h>+#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 <alloc.h>+# endif+# else /* MSC or DJGPP */+# include <malloc.h>+# 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 <malloc.h>+# 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 <unix.h> /* 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)) && !defined __INTERIX+# 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++#if defined(__BORLANDC__)+ #pragma warn -8004+ #pragma warn -8008+ #pragma warn -8066+#endif++/* provide prototypes for these when building zlib without LFS */+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));+#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)+# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )+# define vsnprintf _vsnprintf+# endif+# 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+ void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));+ int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));+ void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));+#endif++/* Diagnostic functions */+#ifdef DEBUG+# include <stdio.h>+ extern int ZLIB_INTERNAL z_verbose;+ extern void ZLIB_INTERNAL 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 ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,+ unsigned size));+void ZLIB_INTERNAL 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 */
+ libgit2/include/git2.h view
@@ -0,0 +1,56 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#ifndef INCLUDE_git_git_h__+#define INCLUDE_git_git_h__++#define LIBGIT2_VERSION "0.10.0"+#define LIBGIT2_VER_MAJOR 0+#define LIBGIT2_VER_MINOR 10+#define LIBGIT2_VER_REVISION 0++#include "git2/common.h"+#include "git2/errors.h"+#include "git2/zlib.h"++#include "git2/types.h"++#include "git2/oid.h"+#include "git2/signature.h"+#include "git2/odb.h"++#include "git2/repository.h"+#include "git2/revwalk.h"+#include "git2/refs.h"++#include "git2/object.h"+#include "git2/blob.h"+#include "git2/commit.h"+#include "git2/tag.h"+#include "git2/tree.h"++#include "git2/index.h"++#endif
+ libgit2/include/git2/blob.h view
@@ -0,0 +1,128 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_blob_h__+#define INCLUDE_git_blob_h__++#include "common.h"+#include "types.h"+#include "oid.h"+#include "object.h"++/**+ * @file git2/blob.h+ * @brief Git blob load and write routines+ * @defgroup git_blob Git blob load and write routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a blob object from a repository.+ * The generated blob object is owned by the revision+ * repo and shall not be freed by the user.+ *+ * @param blob pointer to the looked up blob+ * @param repo the repo to use when locating the blob.+ * @param id identity of the blob to locate.+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id)+{+ return git_object_lookup((git_object **)blob, repo, id, GIT_OBJ_BLOB);+}++/**+ * Create a new in-memory git_blob.+ *+ * The blob object must be manually filled using+ * the 'set_rawcontent' methods before it can+ * be written back to disk.+ *+ * @param blob pointer to the new blob+ * @param repo The repository where the object will reside+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_blob_new(git_blob **blob, git_repository *repo)+{+ return git_object_new((git_object **)blob, repo, GIT_OBJ_BLOB);+}++/**+ * Fill a blob with the contents inside+ * the pointed file.+ *+ * @param blob pointer to the new blob+ * @param filename name of the file to read+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename);++/**+ * Fill a blob with the contents inside+ * the pointed buffer+ *+ * @param blob pointer to the blob+ * @param buffer buffer with the contents for the blob+ * @param len size of the buffer+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len);++/**+ * Get a read-only buffer with the raw content of a blob.+ *+ * A pointer to the raw content of a blob is returned;+ * this pointer is owned internally by the object and shall+ * not be free'd. The pointer may be invalidated at a later+ * time (e.g. when changing the contents of the blob).+ *+ * @param blob pointer to the blob+ * @return the pointer; NULL if the blob has no contents+ */+GIT_EXTERN(const void *) git_blob_rawcontent(git_blob *blob);++/**+ * Get the size in bytes of the contents of a blob+ *+ * @param blob pointer to the blob+ * @return size on bytes+ */+GIT_EXTERN(int) git_blob_rawsize(git_blob *blob);++/**+ * Read a file from the working folder of a repository+ * and write it to the Object Database as a loose blob,+ * if such doesn't exist yet.+ *+ * @param written_id return the id of the written blob+ * @param repo repository where the blob will be written+ * @param path file from which the blob will be created+ */+GIT_EXTERN(int) git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/commit.h view
@@ -0,0 +1,188 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_commit_h__+#define INCLUDE_git_commit_h__++#include "common.h"+#include "types.h"+#include "oid.h"+#include "object.h"++/**+ * @file git2/commit.h+ * @brief Git commit parsing, formatting routines+ * @defgroup git_commit Git commit parsing, formatting routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a commit object from a repository.+ * The generated commit object is owned by the revision+ * repo and shall not be freed by the user.+ *+ * @param commit pointer to the looked up commit+ * @param repo the repo to use when locating the commit.+ * @param id identity of the commit to locate. If the object is+ * an annotated tag it will be peeled back to the commit.+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id)+{+ return git_object_lookup((git_object **)commit, repo, id, GIT_OBJ_COMMIT);+}++/**+ * Create a new in-memory git_commit.+ *+ * The commit object must be manually filled using+ * setter methods before it can be written to its+ * repository.+ *+ * @param commit pointer to the new commit+ * @param repo The repository where the object will reside+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_commit_new(git_commit **commit, git_repository *repo)+{+ return git_object_new((git_object **)commit, repo, GIT_OBJ_COMMIT);+}++/**+ * Get the id of a commit.+ * @param commit a previously loaded commit.+ * @return object identity for the commit.+ */+GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit);++/**+ * Get the short (one line) message of a commit.+ * @param commit a previously loaded commit.+ * @return the short message of a commit+ */+GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit);++/**+ * Get the full message of a commit.+ * @param commit a previously loaded commit.+ * @return the message of a commit+ */+GIT_EXTERN(const char *) git_commit_message(git_commit *commit);++/**+ * Get the commit time (i.e. committer time) of a commit.+ * @param commit a previously loaded commit.+ * @return the time of a commit+ */+GIT_EXTERN(time_t) git_commit_time(git_commit *commit);++/**+ * Get the commit timezone offset (i.e. committer's preferred timezone) of a commit.+ * @param commit a previously loaded commit.+ * @return positive or negative timezone offset, in minutes from UTC+ */+GIT_EXTERN(int) git_commit_time_offset(git_commit *commit);++/**+ * Get the committer of a commit.+ * @param commit a previously loaded commit.+ * @return the committer of a commit+ */+GIT_EXTERN(const git_signature *) git_commit_committer(git_commit *commit);++/**+ * Get the author of a commit.+ * @param commit a previously loaded commit.+ * @return the author of a commit+ */+GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit);++/**+ * Get the tree pointed to by a commit.+ * @param tree_out pointer where to store the tree object+ * @param commit a previously loaded commit.+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit);++/**+ * Get the number of parents of this commit+ *+ * @param commit a previously loaded commit.+ * @return integer of count of parents+ */+GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit);++/**+ * Get the specified parent of the commit.+ *+ * @param parent Pointer where to store the parent commit+ * @param commit a previously loaded commit.+ * @param n the position of the parent (from 0 to `parentcount`)+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);++/**+ * Add a new parent commit to an existing commit+ * @param commit the commit object+ * @param new_parent the new commit which will be a parent+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_commit_add_parent(git_commit *commit, git_commit *new_parent);++/**+ * Set the message of a commit+ * @param commit the commit object+ * @param message the new message+ */+GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message);++/**+ * Set the committer of a commit+ * @param commit the commit object+ * @param author_sig signature of the committer+ */+GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const git_signature *committer_sig);++/**+ * Set the author of a commit+ * @param commit the commit object+ * @param author_sig signature of the author+ */+GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_signature *author_sig);++/**+ * Set the tree which is pointed to by a commit+ * @param commit the commit object+ * @param tree the new tree+ * @param 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_commit_set_tree(git_commit *commit, git_tree *tree);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/common.h view
@@ -0,0 +1,172 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_common_h__+#define INCLUDE_git_common_h__++#include "thread-utils.h"+#include <time.h>+#include <stdlib.h>++#ifdef __cplusplus+# define GIT_BEGIN_DECL extern "C" {+# define GIT_END_DECL }+#else+ /** Start declarations in C mode */+# define GIT_BEGIN_DECL /* empty */+ /** End declarations in C mode */+# define GIT_END_DECL /* empty */+#endif++/** Declare a public function exported for application use. */+#ifdef __GNUC__+# define GIT_EXTERN(type) extern \+ __attribute__((visibility("default"))) \+ type+#elif defined(_MSC_VER)+# define GIT_EXTERN(type) __declspec(dllexport) type+#else+# define GIT_EXTERN(type) extern type+#endif++/** Declare a public TLS symbol exported for application use. */+#ifdef __GNUC__+# define GIT_EXTERN_TLS(type) extern \+ __attribute__((visibility("default"))) \+ GIT_TLS \+ type+#elif defined(_MSC_VER)+# define GIT_EXTERN_TLS(type) __declspec(dllexport) GIT_TLS type+#else+# define GIT_EXTERN_TLS(type) extern GIT_TLS type+#endif++/** Declare a function as always inlined. */+#if defined(_MSC_VER)+# define GIT_INLINE(type) static __inline type+#else+# define GIT_INLINE(type) static inline type+#endif++/** Declare a function's takes printf style arguments. */+#ifdef __GNUC__+# define GIT_FORMAT_PRINTF(a,b) __attribute__((format (printf, a, b)))+#else+# define GIT_FORMAT_PRINTF(a,b) /* empty */+#endif++/**+ * @file git2/common.h+ * @brief Git common platform definitions+ * @defgroup git_common Git common platform definitions+ * @ingroup Git+ * @{+ */++/** Operation completed successfully. */+#define GIT_SUCCESS 0++/**+ * Operation failed, with unspecified reason.+ * This value also serves as the base error code; all other+ * error codes are subtracted from it such that all errors+ * are < 0, in typical POSIX C tradition.+ */+#define GIT_ERROR -1++/** Input was not a properly formatted Git object id. */+#define GIT_ENOTOID (GIT_ERROR - 1)++/** Input does not exist in the scope searched. */+#define GIT_ENOTFOUND (GIT_ERROR - 2)++/** Not enough space available. */+#define GIT_ENOMEM (GIT_ERROR - 3)++/** Consult the OS error information. */+#define GIT_EOSERR (GIT_ERROR - 4)++/** The specified object is of invalid type */+#define GIT_EOBJTYPE (GIT_ERROR - 5)++/** The specified object has its data corrupted */+#define GIT_EOBJCORRUPTED (GIT_ERROR - 6)++/** The specified repository is invalid */+#define GIT_ENOTAREPO (GIT_ERROR - 7)++/** The object type is invalid or doesn't match */+#define GIT_EINVALIDTYPE (GIT_ERROR - 8)++/** The object cannot be written that because it's missing internal data */+#define GIT_EMISSINGOBJDATA (GIT_ERROR - 9)++/** The packfile for the ODB is corrupted */+#define GIT_EPACKCORRUPTED (GIT_ERROR - 10)++/** Failed to adquire or release a file lock */+#define GIT_EFLOCKFAIL (GIT_ERROR - 11)++/** The Z library failed to inflate/deflate an object's data */+#define GIT_EZLIB (GIT_ERROR - 12)++/** The queried object is currently busy */+#define GIT_EBUSY (GIT_ERROR - 13)++/** The index file is not backed up by an existing repository */+#define GIT_EBAREINDEX (GIT_ERROR - 14)++/** The name of the reference is not valid */+#define GIT_EINVALIDREFNAME (GIT_ERROR - 15)++/** The specified reference has its data corrupted */+#define GIT_EREFCORRUPTED (GIT_ERROR - 16)++/** The specified symbolic reference is too deeply nested */+#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17)++/** The pack-refs file is either corrupted of its format is not currently supported */+#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18)++/** The path is invalid */+#define GIT_EINVALIDPATH (GIT_ERROR - 19)++/** The revision walker is empty; there are no more commits left to iterate */+#define GIT_EREVWALKOVER (GIT_ERROR - 20)++/** The state of the reference is not valid */+#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21)++GIT_BEGIN_DECL++typedef struct {+ char **strings;+ size_t count;+} git_strarray;++GIT_EXTERN(void) git_strarray_free(git_strarray *array);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/errors.h view
@@ -0,0 +1,45 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_errors_h__+#define INCLUDE_git_errors_h__++/**+ * @file git2/errors.h+ * @brief Git error handling routines and variables+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * strerror() for the Git library+ * @param num The error code to explain+ * @return a string explaining the error code+ */+GIT_EXTERN(const char *) git_strerror(int num);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/index.h view
@@ -0,0 +1,199 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_index_h__+#define INCLUDE_git_index_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/index.h+ * @brief Git index parsing and manipulation routines+ * @defgroup git_index Git index parsing and manipulation routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++#define GIT_IDXENTRY_NAMEMASK (0x0fff)+#define GIT_IDXENTRY_STAGEMASK (0x3000)+#define GIT_IDXENTRY_EXTENDED (0x4000)+#define GIT_IDXENTRY_VALID (0x8000)+#define GIT_IDXENTRY_STAGESHIFT 12++/** Time used in a git index entry */+typedef struct {+ git_time_t seconds;+ /* nsec should not be stored as time_t compatible */+ unsigned int nanoseconds;+} git_index_time;++/** Memory representation of a file entry in the index. */+typedef struct git_index_entry {+ git_index_time ctime;+ git_index_time mtime;++ unsigned int dev;+ unsigned int ino;+ unsigned int mode;+ unsigned int uid;+ unsigned int gid;+ git_off_t file_size;++ git_oid oid;++ unsigned short flags;+ unsigned short flags_extended;++ char *path;+} git_index_entry;+++/**+ * Create a new Git index object as a memory representation+ * of the Git index file in 'index_path', without a repository+ * to back it.+ *+ * Since there is no ODB behind this index, any Index methods+ * which rely on the ODB (e.g. index_add) will fail with the+ * GIT_EBAREINDEX error code.+ *+ * @param index the pointer for the new index+ * @param index_path the path to the index file in disk+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_index_open_bare(git_index **index, const char *index_path);++/**+ * Open the Index inside the git repository pointed+ * by 'repo'.+ *+ * @param repo the git repo which owns the index+ * @param index_path the path to the index file in disk+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_index_open_inrepo(git_index **index, git_repository *repo);++/**+ * Clear the contents (all the entries) of an index object.+ * This clears the index object in memory; changes must be manually+ * written to disk for them to take effect.+ *+ * @param index an existing index object+ */+GIT_EXTERN(void) git_index_clear(git_index *index);++/**+ * Free an existing index object.+ *+ * @param index an existing index object+ */+GIT_EXTERN(void) git_index_free(git_index *index);++/**+ * Update the contents of an existing index object in memory+ * by reading from the hard disk.+ *+ * @param index an existing index object+ * @return 0 on success, otherwise an error code+ */+GIT_EXTERN(int) git_index_read(git_index *index);++/**+ * Write an existing index object from memory back to disk+ * using an atomic file lock.+ *+ * @param index an existing index object+ * @return 0 on success, otherwise an error code+ */+GIT_EXTERN(int) git_index_write(git_index *index);++/**+ * Find the first index of any entires which point to given+ * path in the Git index.+ *+ * @param index an existing index object+ * @param path path to search+ * @return an index >= 0 if found, -1 otherwise+ */+GIT_EXTERN(int) git_index_find(git_index *index, const char *path);++/**+ * Add or update an index entry from a file in disk.+ *+ * @param index an existing index object+ * @param path filename to add+ * @param stage stage for the entry+ * @return 0 on success, otherwise an error code+ */+GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage);++/**+ * Remove an entry from the index + *+ * @param index an existing index object+ * @param position position of the entry to remove+ * @return 0 on success, otherwise an error code+ */+GIT_EXTERN(int) git_index_remove(git_index *index, int position);++/**+ * Insert an entry into the index.+ * A full copy (including the 'path' string) of the given+ * 'source_entry' will be inserted on the index; if the index+ * already contains an entry for the same path, the entry+ * will be updated.+ *+ * @param index an existing index object+ * @param source_entry new entry object+ * @return 0 on success, otherwise an error code+ */+GIT_EXTERN(int) git_index_insert(git_index *index, const git_index_entry *source_entry);++/**+ * Get a pointer to one of the entries in the index+ *+ * This entry can be modified, and the changes will be written+ * back to disk on the next write() call.+ *+ * @param index an existing index object+ * @param n the position of the entry+ * @return a pointer to the entry; NULL if out of bounds+ */+GIT_EXTERN(git_index_entry *) git_index_get(git_index *index, int n);++/**+ * Get the count of entries currently in the index+ *+ * @param index an existing index object+ * @return integer of count of current entries+ */+GIT_EXTERN(unsigned int) git_index_entrycount(git_index *index);+++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/object.h view
@@ -0,0 +1,198 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_object_h__+#define INCLUDE_git_object_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/object.h+ * @brief Git revision object management routines+ * @defgroup git_object Git revision object management routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a reference to one of the objects in a repostory.+ *+ * The generated reference is owned by the repository and+ * should not be freed by the user.+ *+ * The 'type' parameter must match the type of the object+ * in the odb; the method will fail otherwise.+ * The special value 'GIT_OBJ_ANY' may be passed to let+ * the method guess the object's type.+ *+ * @param object pointer to the looked-up object+ * @param repo the repository to look up the object+ * @param id the unique identifier for the object+ * @param type the type of the object+ * @return a reference to the object+ */+GIT_EXTERN(int) git_object_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type);++/**+ * Create a new in-memory repository object with+ * the given type.+ *+ * The object's attributes can be filled in using the+ * corresponding setter methods.+ *+ * The object will be written back to given git_repository+ * when the git_object_write() function is called; objects+ * cannot be written to disk until all their main+ * attributes have been properly filled.+ *+ * Objects are instantiated with no SHA1 id; their id+ * will be automatically generated when writing to the+ * repository.+ *+ * @param object pointer to the new object+ * @parem repo Repository where the object belongs+ * @param type Type of the object to be created+ * @return the new object+ */+GIT_EXTERN(int) git_object_new(git_object **object, git_repository *repo, git_otype type);+++/**+ * Write back an object to disk.+ *+ * The object will be written to its corresponding+ * repository.+ *+ * If the object has no changes since it was first+ * read from the repository, no actions will take place.+ *+ * If the object has been modified since it was read from+ * the repository, or it has been created from scratch+ * in memory, it will be written to the repository and+ * its SHA1 ID will be updated accordingly.+ *+ * @param object Git object to write back+ * @return 0 on success; otherwise an error code+ */+GIT_EXTERN(int) git_object_write(git_object *object);++/**+ * Get the id (SHA1) of a repository object+ *+ * In-memory objects created by git_object_new() do not+ * have a SHA1 ID until they are written on a repository.+ *+ * @param obj the repository object+ * @return the SHA1 id+ */+GIT_EXTERN(const git_oid *) git_object_id(const git_object *obj);++/**+ * Get the object type of an object+ *+ * @param obj the repository object+ * @return the object's type+ */+GIT_EXTERN(git_otype) git_object_type(const git_object *obj);++/**+ * Get the repository that owns this object+ *+ * @param obj the object+ * @return the repository who owns this object+ */+GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj);++/**+ * Close an open object+ *+ * This method instructs the library to close an existing+ * object; note that git_objects are owned and cached by the repository+ * so the object may or may not be freed after this library call,+ * depending on how agressive is the caching mechanism used+ * by the repository.+ *+ * IMPORTANT:+ * It is *not* necessary to call this method when you stop using+ * an object, since all object memory is automatically reclaimed+ * by the repository when it is freed.+ *+ * Forgetting to call `git_object_close` does not cause memory+ * leaks, but it's is recommended to close as soon as possible+ * the biggest objects (e.g. blobs) to prevent wasting memory+ * space.+ *+ * @param object the object to close+ */+GIT_EXTERN(void) git_object_close(git_object *object);++/**+ * Convert an object type to it's string representation.+ *+ * The result is a pointer to a string in static memory and+ * should not be free()'ed.+ *+ * @param type object type to convert.+ * @return the corresponding string representation.+ */+GIT_EXTERN(const char *) git_object_type2string(git_otype type);++/**+ * Convert a string object type representation to it's git_otype.+ *+ * @param str the string to convert.+ * @return the corresponding git_otype.+ */+GIT_EXTERN(git_otype) git_object_string2type(const char *str);++/**+ * Determine if the given git_otype is a valid loose object type.+ *+ * @param type object type to test.+ * @return true if the type represents a valid loose object type,+ * false otherwise.+ */+GIT_EXTERN(int) git_object_typeisloose(git_otype type);++/**+ * Get the size in bytes for the structure which+ * acts as an in-memory representation of any given+ * object type.+ *+ * For all the core types, this would the equivalent+ * of calling `sizeof(git_commit)` if the core types+ * were not opaque on the external API.+ *+ * @param type object type to get its size+ * @return size in bytes of the object+ */+GIT_EXTERN(size_t) git_object__size(git_otype type);++/** @} */+GIT_END_DECL++#endif
+ libgit2/include/git2/odb.h view
@@ -0,0 +1,201 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_odb_h__+#define INCLUDE_git_odb_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/odb.h+ * @brief Git object database routines+ * @defgroup git_odb Git object database routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Create a new object database with no backends.+ *+ * Before the ODB can be used for read/writing, a custom database+ * backend must be manually added using `git_odb_add_backend()`+ *+ * @param out location to store the database pointer, if opened.+ * Set to NULL if the open failed.+ * @return GIT_SUCCESS if the database was created; otherwise an error+ * code describing why the open was not possible.+ */+GIT_EXTERN(int) git_odb_new(git_odb **out);++/**+ * Create a new object database and automatically add+ * the two default backends:+ *+ * - git_odb_backend_loose: read and write loose object files+ * from disk, assuming `objects_dir` as the Objects folder+ *+ * - git_odb_backend_pack: read objects from packfiles,+ * assuming `objects_dir` as the Objects folder which+ * contains a 'pack/' folder with the corresponding data+ *+ * @param out location to store the database pointer, if opened.+ * Set to NULL if the open failed.+ * @param objects_dir path of the backends' "objects" directory.+ * @return GIT_SUCCESS if the database opened; otherwise an error+ * code describing why the open was not possible.+ */+GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir);++/**+ * Add a custom backend to an existing Object DB+ *+ * Read <odb_backends.h> for more information.+ *+ * @param odb database to add the backend to+ * @paramm backend pointer to a git_odb_backend instance+ * @return 0 on sucess; error code otherwise+ */+GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority);++/**+ * Add a custom backend to an existing Object DB; this+ * backend will work as an alternate.+ *+ * Alternate backends are always checked for objects *after*+ * all the main backends have been exhausted.+ *+ * Writing is disabled on alternate backends.+ *+ * Read <odb_backends.h> for more information.+ *+ * @param odb database to add the backend to+ * @paramm backend pointer to a git_odb_backend instance+ * @return 0 on sucess; error code otherwise+ */+GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority);++/**+ * Close an open object database.+ * @param db database pointer to close. If NULL no action is taken.+ */+GIT_EXTERN(void) git_odb_close(git_odb *db);++/** An object read from the database. */+typedef struct {+ void *data; /**< Raw, decompressed object data. */+ size_t len; /**< Total number of bytes in data. */+ git_otype type; /**< Type of this object. */+} git_rawobj;++/**+ * Read an object from the database.+ *+ * If GIT_ENOTFOUND then out->data is set to NULL.+ *+ * @param out object descriptor to populate upon reading.+ * @param db database to search for the object in.+ * @param id identity of the object to read.+ * @return+ * - GIT_SUCCESS if the object was read;+ * - GIT_ENOTFOUND if the object is not in the database.+ */+GIT_EXTERN(int) git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id);++/**+ * Read the header of an object from the database, without+ * reading its full contents.+ *+ * Only the 'type' and 'len' fields of the git_rawobj structure+ * are filled. The 'data' pointer will always be NULL.+ *+ * The raw object pointed by 'out' doesn't need to be manually+ * closed with git_rawobj_close().+ *+ * @param out object descriptor to populate upon reading.+ * @param db database to search for the object in.+ * @param id identity of the object to read.+ * @return+ * - GIT_SUCCESS if the object was read;+ * - GIT_ENOTFOUND if the object is not in the database.+ */+GIT_EXTERN(int) git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id);++/**+ * Write an object to the database.+ *+ * @param id identity of the object written.+ * @param db database to which the object should be written.+ * @param obj object descriptor for the object to write.+ * @return+ * - GIT_SUCCESS if the object was written;+ * - GIT_ERROR otherwise.+ */+GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj);++/**+ * Determine if the given object can be found in the object database.+ *+ * @param db database to be searched for the given object.+ * @param id the object to search for.+ * @return+ * - true, if the object was found+ * - false, otherwise+ */+GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);++++++/**+ * Determine the object-ID (sha1 hash) of the given git_rawobj.+ *+ * The input obj must be a valid loose object type and the data+ * pointer must not be NULL, unless the len field is also zero.+ *+ * @param id the resulting object-ID.+ * @param obj the object whose hash is to be determined.+ * @return+ * - GIT_SUCCESS if the object-ID was correctly determined.+ * - GIT_ERROR if the given object is malformed.+ */+GIT_EXTERN(int) git_rawobj_hash(git_oid *id, git_rawobj *obj);++/**+ * Release all memory used by the obj structure.+ *+ * As a result of this call, obj->data will be set to NULL.+ *+ * If obj->data is already NULL, nothing happens.+ *+ * @param obj object descriptor to free.+ */+GIT_EXTERN(void) git_rawobj_close(git_rawobj *obj);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/odb_backend.h view
@@ -0,0 +1,77 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_odb_backend_h__+#define INCLUDE_git_odb_backend_h__++#include "common.h"+#include "types.h"+#include "oid.h"+#include "odb.h"++/**+ * @file git2/backend.h+ * @brief Git custom backend functions+ * @defgroup git_backend Git custom backend API+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/** An instance for a custom backend */+struct git_odb_backend {+ git_odb *odb;++ int (* read)(+ git_rawobj *,+ struct git_odb_backend *,+ const git_oid *);++ int (* read_header)(+ git_rawobj *,+ struct git_odb_backend *,+ const git_oid *);++ int (* write)(+ git_oid *id,+ struct git_odb_backend *,+ git_rawobj *obj);++ int (* exists)(+ struct git_odb_backend *,+ const git_oid *);++ void (* free)(struct git_odb_backend *);+};++GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir);+GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir);++#ifdef GIT2_SQLITE_BACKEND+GIT_EXTERN(int) git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db);+#endif++GIT_END_DECL++#endif
+ libgit2/include/git2/oid.h view
@@ -0,0 +1,191 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_oid_h__+#define INCLUDE_git_oid_h__++#include "common.h"+#include "types.h"++/**+ * @file git2/oid.h+ * @brief Git object id routines+ * @defgroup git_oid Git object id routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/** Size (in bytes) of a raw/binary oid */+#define GIT_OID_RAWSZ 20++/** Size (in bytes) of a hex formatted oid */+#define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2)++/** Unique identity of any object (commit, tree, blob, tag). */+typedef struct {+ /** raw binary formatted id */+ unsigned char id[GIT_OID_RAWSZ];+} git_oid;++/**+ * Parse a hex formatted object id into a git_oid.+ * @param out oid structure the result is written into.+ * @param str input hex string; must be pointing at the start of+ * the hex sequence and have at least the number of bytes+ * needed for an oid encoded in hex (40 bytes).+ * @return GIT_SUCCESS if valid; GIT_ENOTOID on failure.+ */+GIT_EXTERN(int) git_oid_mkstr(git_oid *out, const char *str);++/**+ * Copy an already raw oid into a git_oid structure.+ * @param out oid structure the result is written into.+ * @param raw the raw input bytes to be copied.+ */+GIT_EXTERN(void) git_oid_mkraw(git_oid *out, const unsigned char *raw);++/**+ * Format a git_oid into a hex string.+ * @param str output hex string; must be pointing at the start of+ * the hex sequence and have at least the number of bytes+ * needed for an oid encoded in hex (40 bytes). Only the+ * oid digits are written; a '\\0' terminator must be added+ * by the caller if it is required.+ * @param oid oid structure to format.+ */+GIT_EXTERN(void) git_oid_fmt(char *str, const git_oid *oid);++/**+ * Format a git_oid into a loose-object path string.+ * <p>+ * The resulting string is "aa/...", where "aa" is the first two+ * hex digitis of the oid and "..." is the remaining 38 digits.+ *+ * @param str output hex string; must be pointing at the start of+ * the hex sequence and have at least the number of bytes+ * needed for an oid encoded in hex (41 bytes). Only the+ * oid digits are written; a '\\0' terminator must be added+ * by the caller if it is required.+ * @param oid oid structure to format.+ */+GIT_EXTERN(void) git_oid_pathfmt(char *str, const git_oid *oid);++/**+ * Format a gid_oid into a newly allocated c-string.+ * @param oid the oid structure to format+ * @return the c-string; NULL if memory is exhausted. Caller must+ * deallocate the string with free().+ */+GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *oid);++/**+ * Format a git_oid into a buffer as a hex format c-string.+ * <p>+ * If the buffer is smaller than GIT_OID_HEXSZ+1, then the resulting+ * oid c-string will be truncated to n-1 characters. If there are+ * any input parameter errors (out == NULL, n == 0, oid == NULL),+ * then a pointer to an empty string is returned, so that the return+ * value can always be printed.+ *+ * @param out the buffer into which the oid string is output.+ * @param n the size of the out buffer.+ * @param oid the oid structure to format.+ * @return the out buffer pointer, assuming no input parameter+ * errors, otherwise a pointer to an empty string.+ */+GIT_EXTERN(char *) git_oid_to_string(char *out, size_t n, const git_oid *oid);++/**+ * Copy an oid from one structure to another.+ * @param out oid structure the result is written into.+ * @param src oid structure to copy from.+ */+GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src);++/**+ * Compare two oid structures.+ * @param a first oid structure.+ * @param b second oid structure.+ * @return <0, 0, >0 if a < b, a == b, a > b.+ */+GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b);++/**+ * OID Shortener object+ */+typedef struct git_oid_shorten git_oid_shorten;++/**+ * Create a new OID shortener.+ *+ * The OID shortener is used to process a list of OIDs+ * in text form and return the shortest length that would+ * uniquely identify all of them.+ *+ * E.g. look at the result of `git log --abbrev`.+ *+ * @param min_length The minimal length for all identifiers,+ * which will be used even if shorter OIDs would still+ * be unique.+ * @return a `git_oid_shorten` instance, NULL if OOM+ */+git_oid_shorten *git_oid_shorten_new(size_t min_length);++/**+ * Add a new OID to set of shortened OIDs and calculate+ * the minimal length to uniquely identify all the OIDs in+ * the set.+ *+ * The OID is expected to be a 40-char hexadecimal string.+ * The OID is owned by the user and will not be modified+ * or freed.+ *+ * For performance reasons, there is a hard-limit of how many+ * OIDs can be added to a single set (around ~22000, assuming+ * a mostly randomized distribution), which should be enough+ * for any kind of program, and keeps the algorithm fast and+ * memory-efficient.+ *+ * Attempting to add more than those OIDs will result in a+ * GIT_ENOMEM error+ *+ * @param os a `git_oid_shorten` instance+ * @param text_oid an OID in text form+ * @return the minimal length to uniquely identify all OIDs+ * added so far to the set; or an error code (<0) if an+ * error occurs.+ */+int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid);++/**+ * Free an OID shortener instance+ * + * @param os a `git_oid_shorten` instance+ */+void git_oid_shorten_free(git_oid_shorten *os);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/refs.h view
@@ -0,0 +1,246 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_refs_h__+#define INCLUDE_git_refs_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/refs.h+ * @brief Git reference management routines+ * @defgroup git_reference Git reference management routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a reference by its name in a repository.+ *+ * The generated reference is owned by the repository and+ * should not be freed by the user.+ *+ * @param reference_out pointer to the looked-up reference+ * @param repo the repository to look up the reference+ * @param name the long name for the reference (e.g. HEAD, ref/heads/master, refs/tags/v0.1.0, ...)+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_repository *repo, const char *name);++/**+ * Create a new symbolic reference.+ *+ * The reference will be created in the repository and written+ * to the disk.+ *+ * This reference is owned by the repository and shall not+ * be free'd by the user.+ *+ * @param ref_out Pointer to the newly created reference+ * @param repo Repository where that reference will live+ * @param name The name of the reference+ * @param target The target of the reference+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target);++/**+ * Create a new object id reference.+ *+ * The reference will be created in the repository and written+ * to the disk.+ *+ * This reference is owned by the repository and shall not+ * be free'd by the user.+ *+ * @param ref_out Pointer to the newly created reference+ * @param repo Repository where that reference will live+ * @param name The name of the reference+ * @param id The object id pointed to by the reference.+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id);++/**+ * Get the OID pointed to by a reference.+ * + * Only available if the reference is direct (i.e. not symbolic)+ *+ * @param ref The reference+ * @return a pointer to the oid if available, NULL otherwise+ */+GIT_EXTERN(const git_oid *) git_reference_oid(git_reference *ref);++/**+ * Get full name to the reference pointed by this reference+ * + * Only available if the reference is symbolic+ *+ * @param ref The reference+ * @return a pointer to the name if available, NULL otherwise+ */+GIT_EXTERN(const char *) git_reference_target(git_reference *ref);++/**+ * Get the type of a reference+ *+ * Either direct (GIT_REF_OID) or symbolic (GIT_REF_SYMBOLIC)+ *+ * @param ref The reference+ * @return the type+ */+GIT_EXTERN(git_rtype) git_reference_type(git_reference *ref);++/**+ * Get the full name of a reference+ *+ * @param ref The reference+ * @return the full name for the ref+ */+GIT_EXTERN(const char *) git_reference_name(git_reference *ref);++/**+ * Resolve a symbolic reference + *+ * Thie method iteratively peels a symbolic reference+ * until it resolves to a direct reference to an OID.+ *+ * If a direct reference is passed as an argument,+ * that reference is returned immediately+ *+ * @param resolved_ref Pointer to the peeled reference+ * @param ref The reference+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_resolve(git_reference **resolved_ref, git_reference *ref);++/**+ * Get the repository where a reference resides+ *+ * @param ref The reference+ * @return a pointer to the repo+ */+GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref);++/**+ * Set the symbolic target of a reference.+ *+ * The reference must be a symbolic reference, otherwise+ * this method will fail.+ *+ * The reference will be automatically updated in+ * memory and on disk.+ *+ * @param ref The reference+ * @param target The new target for the reference+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target);++/**+ * Set the OID target of a reference.+ *+ * The reference must be a direct reference, otherwise+ * this method will fail.+ *+ * The reference will be automatically updated in+ * memory and on disk.+ *+ * @param ref The reference+ * @param target The new target OID for the reference+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id);++/**+ * Rename an existing reference+ *+ * This method works for both direct and symbolic references.+ * The new name will be checked for validity and may be+ * modified into a normalized form.+ *+ * The refernece will be immediately renamed in-memory+ * and on disk.+ *+ */+GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name);++/**+ * Delete an existing reference+ *+ * This method works for both direct and symbolic references.+ *+ * The reference will be immediately removed on disk and from+ * memory. The given reference pointer will no longer be valid.+ *+ */+GIT_EXTERN(int) git_reference_delete(git_reference *ref);++/**+ * Pack all the loose references in the repository+ *+ * This method will load into the cache all the loose+ * references on the repository and update the + * `packed-refs` file with them.+ *+ * Once the `packed-refs` file has been written properly,+ * the loose references will be removed from disk.+ *+ * WARNING: calling this method may invalidate any existing+ * references previously loaded on the cache.+ *+ * @param repo Repository where the loose refs will be packed+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_packall(git_repository *repo);++/**+ * Fill a list with all the references that can be found+ * in a repository.+ *+ * The listed references may be filtered by type, or using+ * a bitwise OR of several types. Use the magic value+ * `GIT_REF_LISTALL` to obtain all references, including+ * packed ones.+ *+ * The string array will be filled with the names of all+ * references; these values are owned by the user and+ * should be free'd manually when no longer needed, using+ * `git_strarray_free`.+ *+ * @param array Pointer to a git_strarray structure where+ * the reference names will be stored+ * @param repo Repository where to find the refs+ * @param list_flags Filtering flags for the reference+ * listing.+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/repository.h view
@@ -0,0 +1,191 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_repository_h__+#define INCLUDE_git_repository_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/repository.h+ * @brief Git repository management routines+ * @defgroup git_repository Git repository management routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Open a git repository.+ *+ * The 'path' argument must point to an existing git repository+ * folder, e.g.+ *+ * /path/to/my_repo/.git/ (normal repository)+ * objects/+ * index+ * HEAD+ *+ * /path/to/bare_repo/ (bare repository)+ * objects/+ * index+ * HEAD+ *+ * The method will automatically detect if 'path' is a normal+ * or bare repository or fail is 'path' is neither.+ *+ * @param repository pointer to the repo which will be opened+ * @param path the path to the repository+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *path);+++/**+ * Open a git repository by manually specifying all its paths+ *+ * @param repository pointer to the repo which will be opened+ *+ * @param git_dir The full path to the repository folder+ * e.g. a '.git' folder for live repos, any folder for bare+ * Equivalent to $GIT_DIR. + * Cannot be NULL.+ *+ * @param git_object_directory The full path to the ODB folder.+ * the folder where all the loose and packed objects are stored+ * Equivalent to $GIT_OBJECT_DIRECTORY.+ * If NULL, "$GIT_DIR/objects/" is assumed.+ *+ * @param git_index_file The full path to the index (dircache) file+ * Equivalent to $GIT_INDEX_FILE.+ * If NULL, "$GIT_DIR/index" is assumed.+ *+ * @param git_work_tree The full path to the working tree of the repository,+ * if the repository is not bare.+ * Equivalent to $GIT_WORK_TREE.+ * If NULL, the repository is assumed to be bare.+ *+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_repository_open2(git_repository **repository,+ const char *git_dir,+ const char *git_object_directory,+ const char *git_index_file,+ const char *git_work_tree);+++/**+ * Open a git repository by manually specifying its paths and+ * the object database it will use.+ *+ * @param repository pointer to the repo which will be opened+ *+ * @param git_dir The full path to the repository folder+ * e.g. a '.git' folder for live repos, any folder for bare+ * Equivalent to $GIT_DIR. + * Cannot be NULL.+ *+ * @param object_database A pointer to a git_odb created & initialized+ * by the user (e.g. with custom backends). This object database+ * will be owned by the repository and will be automatically free'd.+ * It should not be manually free'd by the user, or this+ * git_repository object will become invalid.+ *+ * @param git_index_file The full path to the index (dircache) file+ * Equivalent to $GIT_INDEX_FILE.+ * If NULL, "$GIT_DIR/index" is assumed.+ *+ * @param git_work_tree The full path to the working tree of the repository,+ * if the repository is not bare.+ * Equivalent to $GIT_WORK_TREE.+ * If NULL, the repository is assumed to be bare.+ *+ * @return 0 on success; error code otherwise+ */++GIT_EXTERN(int) git_repository_open3(git_repository **repository,+ const char *git_dir,+ git_odb *object_database,+ const char *git_index_file,+ const char *git_work_tree);++/**+ * Get the object database behind a Git repository+ *+ * @param repo a repository object+ * @return a pointer to the object db+ */+GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo);++/**+ * Get the Index file of a Git repository+ *+ * This is a cheap operation; the index is only opened on the first call,+ * and subsequent calls only retrieve the previous pointer.+ *+ * @param index Pointer where to store the index+ * @param repo a repository object+ * @return 0 on success; error code if the index could not be opened+ */+GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo);++/**+ * Free a previously allocated repository+ *+ * @param repo repository handle to close. If NULL nothing occurs.+ */+GIT_EXTERN(void) git_repository_free(git_repository *repo);++/**+ * Force a garbage collector pass on the repository+ *+ * This will force-free any cached objects that have been+ * previously marked by the user as closed (`git_object_close`).+ *+ * @param repo repository handle to collect. If NULL nothing occurs.+ */+GIT_EXTERN(int) git_repository_gc(git_repository *repo);++/**+ * Creates a new Git repository in the given folder.+ *+ * TODO:+ * - Reinit the repository+ * - Create config files+ *+ * @param repo_out pointer to the repo which will be created or reinitialized+ * @param path the path to the repository+ * @param is_bare if true, a Git repository without a working directory is created + * at the pointed path. If false, provided path will be considered as the working + * directory into which the .git directory will be created.+ *+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/revwalk.h view
@@ -0,0 +1,187 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_revwalk_h__+#define INCLUDE_git_revwalk_h__++#include "common.h"+#include "types.h"+#include "oid.h"++/**+ * @file git2/revwalk.h+ * @brief Git revision traversal routines+ * @defgroup git_revwalk Git revision traversal routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Sort the repository contents in no particular ordering;+ * this sorting is arbitrary, implementation-specific+ * and subject to change at any time.+ * This is the default sorting for new walkers.+ */+#define GIT_SORT_NONE (0)++/**+ * Sort the repository contents in topological order+ * (parents before children); this sorting mode+ * can be combined with time sorting.+ */+#define GIT_SORT_TOPOLOGICAL (1 << 0)++/**+ * Sort the repository contents by commit time;+ * this sorting mode can be combined with+ * topological sorting.+ */+#define GIT_SORT_TIME (1 << 1)++/**+ * Iterate through the repository contents in reverse+ * order; this sorting mode can be combined with+ * any of the above.+ */+#define GIT_SORT_REVERSE (1 << 2)++/**+ * Allocate a new revision walker to iterate through a repo.+ *+ * This revision walker uses a custom memory pool and an internal+ * commit cache, so it is relatively expensive to allocate.+ *+ * For maximum performance, this revision walker should be+ * reused for different walks.+ *+ * This revision walker is *not* thread safe: it may only be+ * used to walk a repository on a single thread; however,+ * it is possible to have several revision walkers in+ * several different threads walking the same repository.+ *+ * @param walker pointer to the new revision walker+ * @param repo the repo to walk through+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_revwalk_new(git_revwalk **walker, git_repository *repo);++/**+ * Reset the revision walker for reuse.+ *+ * This will clear all the pushed and hidden commits, and+ * leave the walker in a blank state (just like at+ * creation) ready to receive new commit pushes and+ * start a new walk.+ *+ * The revision walk is automatically reset when a walk+ * is over.+ *+ * @param walker handle to reset.+ */+GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);++/**+ * Mark a commit to start traversal from.+ *+ * The given OID must belong to a commit on the walked+ * repository.+ *+ * The given commit will be used as one of the roots+ * when starting the revision walk. At least one commit+ * must be pushed the repository before a walk can+ * be started.+ *+ * @param walker the walker being used for the traversal.+ * @param oid the oid of the commit to start from.+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid);+++/**+ * Mark a commit (and its ancestors) uninteresting for the output.+ *+ * The given OID must belong to a commit on the walked+ * repository.+ *+ * The resolved commit and all its parents will be hidden from the+ * output on the revision walk.+ *+ * @param walker the walker being used for the traversal.+ * @param commit the commit that will be ignored during the traversal+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid);++/**+ * Get the next commit from the revision walk.+ *+ * The initial call to this method is *not* blocking when+ * iterating through a repo with a time-sorting mode.+ *+ * Iterating with Topological or inverted modes makes the initial+ * call blocking to preprocess the commit list, but this block should be+ * mostly unnoticeable on most repositories (topological preprocessing+ * times at 0.3s on the git.git repo).+ *+ * The revision walker is reset when the walk is over.+ *+ * @param oid Pointer where to store the oid of the next commit+ * @param walk the walker to pop the commit from.+ * @return GIT_SUCCESS if the next commit was found;+ * GIT_EREVWALKOVER if there are no commits left to iterate+ */+GIT_EXTERN(int) git_revwalk_next(git_oid *oid, git_revwalk *walk);++/**+ * Change the sorting mode when iterating through the+ * repository's contents.+ *+ * Changing the sorting mode resets the walker.+ *+ * @param walk the walker being used for the traversal.+ * @param sort_mode combination of GIT_SORT_XXX flags+ */+GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);++/**+ * Free a revision walker previously allocated.+ *+ * @param walk traversal handle to close. If NULL nothing occurs.+ */+GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk);++/**+ * Return the repository on which this walker+ * is operating.+ *+ * @param walk the revision walker+ * @return the repository being walked+ */+GIT_EXTERN(git_repository *) git_revwalk_repository(git_revwalk *walk);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/signature.h view
@@ -0,0 +1,70 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_signature_h__+#define INCLUDE_git_signature_h__++#include "common.h"+#include "types.h"++/**+ * @file git2/signature.h+ * @brief Git signature creation+ * @defgroup git_signature Git signature creation+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Create a new action signature. The signature must be freed+ * manually or using git_signature_free+ *+ * @name name of the person+ * @email email of the person+ * @time time when the action happened+ * @offset timezone offset in minutes for the time+ * @return the new sig, NULl on out of memory+ */+GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, time_t time, int offset);++/**+ * Create a copy of an existing signature.+ *+ * All internal strings are also duplicated.+ * @sig signature to duplicated+ * @return a copy of sig, NULL on out of memory+ */+GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig);++/**+ * Free an existing signature+ *+ * @sig signature to free+ */+GIT_EXTERN(void) git_signature_free(git_signature *sig);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/tag.h view
@@ -0,0 +1,154 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_tag_h__+#define INCLUDE_git_tag_h__++#include "common.h"+#include "types.h"+#include "oid.h"+#include "object.h"++/**+ * @file git2/tag.h+ * @brief Git tag parsing routines+ * @defgroup git_tag Git tag management+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a tag object from the repository.+ * The generated tag object is owned by the revision+ * repo and shall not be freed by the user.+ *+ * @param tag pointer to the looked up tag+ * @param repo the repo to use when locating the tag.+ * @param id identity of the tag to locate.+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oid *id)+{+ return git_object_lookup((git_object **)tag, repo, id, (git_otype)GIT_OBJ_TAG);+}++/**+ * Create a new in-memory git_tag.+ *+ * The tag object must be manually filled using+ * setter methods before it can be written to its+ * repository.+ *+ * @param tag pointer to the new tag+ * @param repo The repository where the object will reside+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_tag_new(git_tag **tag, git_repository *repo)+{+ return git_object_new((git_object **)tag, repo, (git_otype)GIT_OBJ_TAG);+}++/**+ * Get the id of a tag.+ * @param tag a previously loaded tag.+ * @return object identity for the tag.+ */+GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag);++/**+ * Get the tagged object of a tag+ * @param target pointer where to store the target+ * @param tag a previously loaded tag.+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(int) git_tag_target(git_object **target, git_tag *t);++/**+ * Get the OID of the tagged object of a tag+ * @param tag a previously loaded tag.+ * @return pointer to the OID+ */+GIT_EXTERN(const git_oid *) git_tag_target_oid(git_tag *t);++/**+ * Get the type of a tag's tagged object+ * @param tag a previously loaded tag.+ * @return type of the tagged object+ */+GIT_EXTERN(git_otype) git_tag_type(git_tag *t);++/**+ * Get the name of a tag+ * @param tag a previously loaded tag.+ * @return name of the tag+ */+GIT_EXTERN(const char *) git_tag_name(git_tag *t);++/**+ * Get the tagger (author) of a tag+ * @param tag a previously loaded tag.+ * @return reference to the tag's author+ */+GIT_EXTERN(const git_signature *) git_tag_tagger(git_tag *t);++/**+ * Get the message of a tag+ * @param tag a previously loaded tag.+ * @return message of the tag+ */+GIT_EXTERN(const char *) git_tag_message(git_tag *t);++/**+ * Set the target of a tag (i.e. the object that the tag points to)+ * @param tag The tag to modify+ * @param target the new tagged target+ */+GIT_EXTERN(int) git_tag_set_target(git_tag *tag, git_object *target);++/**+ * Set the name of a tag+ * @param tag The tag to modify+ * @param name the new name for the tag+ */+GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name);++/**+ * Set the tagger of a tag+ * @param tag The tag to modify+ * @param tagger_sig signature of the tagging action+ * @return 0 on success; error code otherwise+ */+GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig);++/**+ * Set the message of a tag+ * @param tag The tag to modify+ * @param message the new tagger for the tag+ */+GIT_EXTERN(void) git_tag_set_message(git_tag *tag, const char *message);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/thread-utils.h view
@@ -0,0 +1,72 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_thread_utils_h__+#define INCLUDE_git_thread_utils_h__++/*+ * How TLS works is compiler+platform dependant+ * Sources: http://en.wikipedia.org/wiki/Thread-Specific_Storage+ * http://predef.sourceforge.net/precomp.html+ */++#define GIT_HAS_TLS 1++#if defined(__APPLE__) && defined(__MACH__)+# undef GIT_TLS++#elif defined(__GNUC__) || \+ defined(__SUNPRO_C) || \+ defined(__SUNPRO_CC) || \+ defined(__xlc__) || \+ defined(__xlC__)+# define GIT_TLS __thread++#elif defined(__INTEL_COMPILER)+# if defined(_WIN32) || defined(_WIN32_CE)+# define GIT_TLS __declspec(thread)+# else+# define GIT_TLS __thread+# endif++#elif defined(_WIN32) || \+ defined(_WIN32_CE) || \+ defined(__BORLANDC__)+# define GIT_TLS __declspec(thread)++#else+# undef GIT_HAS_TLS+# define GIT_TLS /* nothing: tls vars are thread-global */+#endif++/* sparse and cygwin don't grok thread-local variables */+#if defined(__CHECKER__) || defined(__CYGWIN__)+# undef GIT_HAS_TLS+# undef GIT_TLS+# define GIT_TLS+#endif++#define GIT_THREADS 1++#endif /* INCLUDE_git_thread_utils_h__ */
+ libgit2/include/git2/tree.h view
@@ -0,0 +1,223 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_tree_h__+#define INCLUDE_git_tree_h__++#include "common.h"+#include "types.h"+#include "oid.h"+#include "object.h"++/**+ * @file git2/tree.h+ * @brief Git tree parsing, loading routines+ * @defgroup git_tree Git tree parsing, loading routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Lookup a tree object from the repository.+ * The generated tree object is owned by the revision+ * repo and shall not be freed by the user.+ *+ * @param tree pointer to the looked up tree+ * @param repo the repo to use when locating the tree.+ * @param id identity of the tree to locate.+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git_oid *id)+{+ return git_object_lookup((git_object **)tree, repo, id, GIT_OBJ_TREE);+}++/**+ * Create a new in-memory git_tree.+ *+ * The tree object must be manually filled using+ * setter methods before it can be written to its+ * repository.+ *+ * @param tree pointer to the new tree+ * @param repo The repository where the object will reside+ * @return 0 on success; error code otherwise+ */+GIT_INLINE(int) git_tree_new(git_tree **tree, git_repository *repo)+{+ return git_object_new((git_object **)tree, repo, GIT_OBJ_TREE);+}++/**+ * Get the id of a tree.+ * @param tree a previously loaded tree.+ * @return object identity for the tree.+ */+GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);+++/**+ * Get the number of entries listed in a tree+ * @param tree a previously loaded tree.+ * @return the number of entries in the tree+ */+GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree);++/**+ * Lookup a tree entry by its filename+ * @param tree a previously loaded tree.+ * @param filename the filename of the desired entry+ * @return the tree entry; NULL if not found+ */+GIT_EXTERN(git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *filename);++/**+ * Lookup a tree entry by its position in the tree+ * @param tree a previously loaded tree.+ * @param idx the position in the entry list+ * @return the tree entry; NULL if not found+ */+GIT_EXTERN(git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx);++/**+ * Get the UNIX file attributes of a tree entry+ * @param entry a tree entry+ * @return attributes as an integer+ */+GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry);++/**+ * Get the filename of a tree entry+ * @param entry a tree entry+ * @return the name of the file+ */+GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry);++/**+ * Get the id of the object pointed by the entry+ * @param entry a tree entry+ * @return the oid of the object+ */+GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);++/**+ * Convert a tree entry to the git_object it points too.+ *+ * @param object pointer to the converted object+ * @param entry a tree entry+ * @return a reference to the pointed object in the repository+ */+GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entry);++/**+ * Add a new entry to a tree and return the new entry.+ *+ * This will mark the tree as modified; the new entry will+ * be written back to disk on the next git_object_write()+ *+ * @param entry_out Pointer to the entry that just got+ * created. May be NULL if you are not interested on+ * getting the new entry+ * @param tree Tree object to store the entry+ * @iparam id OID for the tree entry+ * @param filename Filename for the tree entry+ * @param attributes UNIX file attributes for the entry+ * @return 0 on success; otherwise error code+ */+GIT_EXTERN(int) git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes);++/**+ * Remove an entry by its index.+ *+ * Index must be >= 0 and < than git_tree_entrycount().+ *+ * This will mark the tree as modified; the modified entry will+ * be written back to disk on the next git_object_write()+ *+ * @param tree Tree where to remove the entry+ * @param idx index of the entry+ * @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found+ */+GIT_EXTERN(int) git_tree_remove_entry_byindex(git_tree *tree, int idx);++/**+ * Remove an entry by its filename.+ *+ * This will mark the tree as modified; the modified entry will+ * be written back to disk on the next git_object_write()+ *+ * @param tree Tree where to remove the entry+ * @param filename File name of the entry+ * @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found+ */+GIT_EXTERN(int) git_tree_remove_entry_byname(git_tree *tree, const char *filename);++/**+ * Clear all the entries in a tree.+ *+ * This will mark the tree as modified; the modified entry will+ * be written back to disk on the next git_object_write().+ *+ * @param tree Tree object whose entries are to be sorted+ */+GIT_EXTERN(void) git_tree_clear_entries(git_tree *tree);++/**+ * Change the SHA1 id of a tree entry.+ *+ * This will mark the tree that contains the entry as modified;+ * the modified entry will be written back to disk on the next git_object_write()+ *+ * @param entry Entry object which will be modified+ * @param oid new SHA1 oid for the entry+ */+GIT_EXTERN(void) git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid);++/**+ * Change the filename of a tree entry.+ *+ * This will mark the tree that contains the entry as modified;+ * the modified entry will be written back to disk on the next git_object_write()+ *+ * @param entry Entry object which will be modified+ * @param oid new filename for the entry+ */+GIT_EXTERN(void) git_tree_entry_set_name(git_tree_entry *entry, const char *name);++/**+ * Change the attributes of a tree entry.+ *+ * This will mark the tree that contains the entry as modified;+ * the modified entry will be written back to disk on the next git_object_write()+ *+ * @param entry Entry object which will be modified+ * @param oid new attributes for the entry+ * @return 0 if the attributes were properly set; error code otherwise+ */+GIT_EXTERN(int) git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr);++/** @} */+GIT_END_DECL+#endif
+ libgit2/include/git2/types.h view
@@ -0,0 +1,154 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_types_h__+#define INCLUDE_git_types_h__++/**+ * @file git2/types.h+ * @brief libgit2 base & compatibility types+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++/**+ * Cross-platform compatibility types for off_t / time_t+ *+ * NOTE: This needs to be in a public header so that both the library+ * implementation and client applications both agree on the same types.+ * Otherwise we get undefined behavior.+ *+ * Use the "best" types that each platform provides. Currently we truncate+ * these intermediate representations for compatibility with the git ABI, but+ * if and when it changes to support 64 bit types, our code will naturally+ * adapt.+ * NOTE: These types should match those that are returned by our internal+ * stat() functions, for all platforms.+ */+#include <sys/types.h>++#if defined(_MSC_VER)++typedef __int64 git_off_t;+typedef __time64_t git_time_t;++#elif defined(__MINGW32__)++typedef off64_t git_off_t;+typedef time_t git_time_t;++#else /* POSIX */++/* + * Note: Can't use off_t since if a client program includes <sys/types.h>+ * before us (directly or indirectly), they'll get 32 bit off_t in their client+ * app, even though /we/ define _FILE_OFFSET_BITS=64.+ */+typedef long long git_off_t;+typedef time_t git_time_t;++#endif+++/** Basic type (loose or packed) of any Git object. */+typedef enum {+ GIT_OBJ_ANY = -2, /**< Object can be any of the following */+ GIT_OBJ_BAD = -1, /**< Object is invalid. */+ GIT_OBJ__EXT1 = 0, /**< Reserved for future use. */+ GIT_OBJ_COMMIT = 1, /**< A commit object. */+ GIT_OBJ_TREE = 2, /**< A tree (directory listing) object. */+ GIT_OBJ_BLOB = 3, /**< A file revision object. */+ GIT_OBJ_TAG = 4, /**< An annotated tag object. */+ GIT_OBJ__EXT2 = 5, /**< Reserved for future use. */+ GIT_OBJ_OFS_DELTA = 6, /**< A delta, base is given by an offset. */+ GIT_OBJ_REF_DELTA = 7, /**< A delta, base is given by object id. */+} git_otype;++/** An open object database handle. */+typedef struct git_odb git_odb;++/** A custom backend in an ODB */+typedef struct git_odb_backend git_odb_backend;++/**+ * Representation of an existing git repository,+ * including all its object contents+ */+typedef struct git_repository git_repository;++/** Representation of a generic object in a repository */+typedef struct git_object git_object;++/** Representation of an in-progress walk through the commits in a repo */+typedef struct git_revwalk git_revwalk;++/** Parsed representation of a tag object. */+typedef struct git_tag git_tag;++/** In-memory representation of a blob object. */+typedef struct git_blob git_blob;++/** Parsed representation of a commit object. */+typedef struct git_commit git_commit;++/** Representation of each one of the entries in a tree object. */+typedef struct git_tree_entry git_tree_entry;++/** Representation of a tree object. */+typedef struct git_tree git_tree;++/** Memory representation of an index file. */+typedef struct git_index git_index;++/** Time in a signature */+typedef struct git_time {+ time_t time; /** time in seconds from epoch */+ int offset; /** timezone offset, in minutes */+} git_time;++/** An action signature (e.g. for committers, taggers, etc) */+typedef struct git_signature {+ char *name; /** full name of the author */+ char *email; /** email of the author */+ git_time when; /** time when the action happened */+} git_signature;++/** In-memory representation of a reference. */+typedef struct git_reference git_reference;++/** Basic type of any Git reference. */+typedef enum {+ GIT_REF_INVALID = 0, /** Invalid reference */+ GIT_REF_OID = 1, /** A reference which points at an object id */+ GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */+ GIT_REF_PACKED = 4,+ GIT_REF_HAS_PEEL = 8,+ GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,+} git_rtype;++/** @} */+GIT_END_DECL++#endif
+ libgit2/include/git2/zlib.h view
@@ -0,0 +1,58 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#ifndef INCLUDE_git_zlib_h__+#define INCLUDE_git_zlib_h__++#include <zlib.h>++/**+ * @file git2/zlib.h+ * @brief Git data compression routines+ * @defgroup git_zlib Git data compression routines+ * @ingroup Git+ * @{+ */+GIT_BEGIN_DECL++#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200+/**+ * deflateBound returns an upper bound on the compressed size.+ *+ * This is a stub function used when zlib does not supply the+ * deflateBound() implementation itself.+ *+ * @param stream the stream pointer.+ * @param s total length of the source data (in bytes).+ * @return maximum length of the compressed data.+ */+GIT_INLINE(size_t) deflateBound(z_streamp stream, size_t s)+{+ return (s + ((s + 7) >> 3) + ((s + 63) >> 6) + 11);+}+#endif++/** @} */+GIT_END_DECL+#endif
+ libgit2/src/blob.c view
@@ -0,0 +1,136 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "git2/common.h"+#include "git2/object.h"+#include "git2/repository.h"++#include "common.h"+#include "blob.h"++const void *git_blob_rawcontent(git_blob *blob)+{+ assert(blob);+ + if (blob->content.data != NULL)+ return blob->content.data;++ if (blob->object.in_memory)+ return NULL;++ if (!blob->object.source.open && git_object__source_open((git_object *)blob) < GIT_SUCCESS)+ return NULL;++ return blob->object.source.raw.data;+}++int git_blob_rawsize(git_blob *blob)+{+ assert(blob);++ if (blob->content.data != NULL)+ return blob->content.len;++ return blob->object.source.raw.len;+}++void git_blob__free(git_blob *blob)+{+ gitfo_free_buf(&blob->content);+ free(blob);+}++int git_blob__parse(git_blob *blob)+{+ assert(blob);+ return GIT_SUCCESS;+}++int git_blob__writeback(git_blob *blob, git_odb_source *src)+{+ assert(blob->object.modified);++ if (blob->content.data == NULL)+ return GIT_EMISSINGOBJDATA;++ return git__source_write(src, blob->content.data, blob->content.len);+}++int git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len)+{+ assert(blob && buffer);++ blob->object.modified = 1;++ git_object__source_close((git_object *)blob);++ if (blob->content.data != NULL)+ gitfo_free_buf(&blob->content);++ blob->content.data = git__malloc(len);+ blob->content.len = len;++ if (blob->content.data == NULL)+ return GIT_ENOMEM;++ memcpy(blob->content.data, buffer, len);++ return GIT_SUCCESS;+}++int git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename)+{+ assert(blob && filename);+ blob->object.modified = 1;++ if (blob->content.data != NULL)+ gitfo_free_buf(&blob->content);++ return gitfo_read_file(&blob->content, filename);+}++int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path)+{+ int error;+ git_blob *blob;++ if (gitfo_exists(path) < 0)+ return GIT_ENOTFOUND;++ if ((error = git_blob_new(&blob, repo)) < GIT_SUCCESS)+ return error;++ if ((error = git_blob_set_rawcontent_fromfile(blob, path)) < GIT_SUCCESS)+ return error;++ if ((error = git_object_write((git_object *)blob)) < GIT_SUCCESS)+ return error;++ git_oid_cpy(written_id, git_object_id((git_object *)blob));++ git_object_close((git_object*)blob);+ return GIT_SUCCESS;+}+
+ libgit2/src/blob.h view
@@ -0,0 +1,17 @@+#ifndef INCLUDE_blob_h__+#define INCLUDE_blob_h__++#include "git2/blob.h"+#include "repository.h"+#include "fileops.h"++struct git_blob {+ git_object object;+ gitfo_buf content;+};++void git_blob__free(git_blob *blob);+int git_blob__parse(git_blob *blob);+int git_blob__writeback(git_blob *blob, git_odb_source *src);++#endif
+ libgit2/src/block-sha1/sha1.c view
@@ -0,0 +1,281 @@+/*+ * SHA1 routine optimized to do word accesses rather than byte accesses,+ * and to avoid unnecessary copies into the context array.+ *+ * This was initially based on the Mozilla SHA1 implementation, although+ * none of the original Mozilla code remains.+ */++#include "common.h"+#include "sha1.h"++#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))++/*+ * Force usage of rol or ror by selecting the one with the smaller constant.+ * It _can_ generate slightly smaller code (a constant of 1 is special), but+ * perhaps more importantly it's possibly faster on any uarch that does a+ * rotate with a loop.+ */++#define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; })+#define SHA_ROL(x,n) SHA_ASM("rol", x, n)+#define SHA_ROR(x,n) SHA_ASM("ror", x, n)++#else++#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r)))+#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n))+#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n)++#endif++/*+ * If you have 32 registers or more, the compiler can (and should)+ * try to change the array[] accesses into registers. However, on+ * machines with less than ~25 registers, that won't really work,+ * and at least gcc will make an unholy mess of it.+ *+ * So to avoid that mess which just slows things down, we force+ * the stores to memory to actually happen (we might be better off+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as+ * suggested by Artur Skawina - that will also make gcc unable to+ * try to do the silly "optimize away loads" part because it won't+ * see what the value will be).+ *+ * Ben Herrenschmidt reports that on PPC, the C version comes close+ * to the optimized asm with this (ie on PPC you don't want that+ * 'volatile', since there are lots of registers).+ *+ * On ARM we get the best code generation by forcing a full memory barrier+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and+ * the stack frame size simply explode and performance goes down the drain.+ */++#if defined(__i386__) || defined(__x86_64__)+ #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))+#elif defined(__GNUC__) && defined(__arm__)+ #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)+#else+ #define setW(x, val) (W(x) = (val))+#endif++/*+ * Performance might be improved if the CPU architecture is OK with+ * unaligned 32-bit loads and a fast ntohl() is available.+ * Otherwise fall back to byte loads and shifts which is portable,+ * and is faster on architectures with memory alignment issues.+ */++#if defined(__i386__) || defined(__x86_64__) || \+ defined(_M_IX86) || defined(_M_X64) || \+ defined(__ppc__) || defined(__ppc64__) || \+ defined(__powerpc__) || defined(__powerpc64__) || \+ defined(__s390__) || defined(__s390x__)++#define get_be32(p) ntohl(*(unsigned int *)(p))+#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)++#else++#define get_be32(p) ( \+ (*((unsigned char *)(p) + 0) << 24) | \+ (*((unsigned char *)(p) + 1) << 16) | \+ (*((unsigned char *)(p) + 2) << 8) | \+ (*((unsigned char *)(p) + 3) << 0) )+#define put_be32(p, v) do { \+ unsigned int __v = (v); \+ *((unsigned char *)(p) + 0) = __v >> 24; \+ *((unsigned char *)(p) + 1) = __v >> 16; \+ *((unsigned char *)(p) + 2) = __v >> 8; \+ *((unsigned char *)(p) + 3) = __v >> 0; } while (0)++#endif++/* This "rolls" over the 512-bit array */+#define W(x) (array[(x)&15])++/*+ * Where do we get the source from? The first 16 iterations get it from+ * the input data, the next mix it from the 512-bit array.+ */+#define SHA_SRC(t) get_be32(data + t)+#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)++#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \+ unsigned int TEMP = input(t); setW(t, TEMP); \+ E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \+ B = SHA_ROR(B, 2); } while (0)++#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )++static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)+{+ unsigned int A,B,C,D,E;+ unsigned int array[16];++ A = ctx->H[0];+ B = ctx->H[1];+ C = ctx->H[2];+ D = ctx->H[3];+ E = ctx->H[4];++ /* Round 1 - iterations 0-16 take their input from 'data' */+ T_0_15( 0, A, B, C, D, E);+ T_0_15( 1, E, A, B, C, D);+ T_0_15( 2, D, E, A, B, C);+ T_0_15( 3, C, D, E, A, B);+ T_0_15( 4, B, C, D, E, A);+ T_0_15( 5, A, B, C, D, E);+ T_0_15( 6, E, A, B, C, D);+ T_0_15( 7, D, E, A, B, C);+ T_0_15( 8, C, D, E, A, B);+ T_0_15( 9, B, C, D, E, A);+ T_0_15(10, A, B, C, D, E);+ T_0_15(11, E, A, B, C, D);+ T_0_15(12, D, E, A, B, C);+ T_0_15(13, C, D, E, A, B);+ T_0_15(14, B, C, D, E, A);+ T_0_15(15, A, B, C, D, E);++ /* Round 1 - tail. Input from 512-bit mixing array */+ T_16_19(16, E, A, B, C, D);+ T_16_19(17, D, E, A, B, C);+ T_16_19(18, C, D, E, A, B);+ T_16_19(19, B, C, D, E, A);++ /* Round 2 */+ T_20_39(20, A, B, C, D, E);+ T_20_39(21, E, A, B, C, D);+ T_20_39(22, D, E, A, B, C);+ T_20_39(23, C, D, E, A, B);+ T_20_39(24, B, C, D, E, A);+ T_20_39(25, A, B, C, D, E);+ T_20_39(26, E, A, B, C, D);+ T_20_39(27, D, E, A, B, C);+ T_20_39(28, C, D, E, A, B);+ T_20_39(29, B, C, D, E, A);+ T_20_39(30, A, B, C, D, E);+ T_20_39(31, E, A, B, C, D);+ T_20_39(32, D, E, A, B, C);+ T_20_39(33, C, D, E, A, B);+ T_20_39(34, B, C, D, E, A);+ T_20_39(35, A, B, C, D, E);+ T_20_39(36, E, A, B, C, D);+ T_20_39(37, D, E, A, B, C);+ T_20_39(38, C, D, E, A, B);+ T_20_39(39, B, C, D, E, A);++ /* Round 3 */+ T_40_59(40, A, B, C, D, E);+ T_40_59(41, E, A, B, C, D);+ T_40_59(42, D, E, A, B, C);+ T_40_59(43, C, D, E, A, B);+ T_40_59(44, B, C, D, E, A);+ T_40_59(45, A, B, C, D, E);+ T_40_59(46, E, A, B, C, D);+ T_40_59(47, D, E, A, B, C);+ T_40_59(48, C, D, E, A, B);+ T_40_59(49, B, C, D, E, A);+ T_40_59(50, A, B, C, D, E);+ T_40_59(51, E, A, B, C, D);+ T_40_59(52, D, E, A, B, C);+ T_40_59(53, C, D, E, A, B);+ T_40_59(54, B, C, D, E, A);+ T_40_59(55, A, B, C, D, E);+ T_40_59(56, E, A, B, C, D);+ T_40_59(57, D, E, A, B, C);+ T_40_59(58, C, D, E, A, B);+ T_40_59(59, B, C, D, E, A);++ /* Round 4 */+ T_60_79(60, A, B, C, D, E);+ T_60_79(61, E, A, B, C, D);+ T_60_79(62, D, E, A, B, C);+ T_60_79(63, C, D, E, A, B);+ T_60_79(64, B, C, D, E, A);+ T_60_79(65, A, B, C, D, E);+ T_60_79(66, E, A, B, C, D);+ T_60_79(67, D, E, A, B, C);+ T_60_79(68, C, D, E, A, B);+ T_60_79(69, B, C, D, E, A);+ T_60_79(70, A, B, C, D, E);+ T_60_79(71, E, A, B, C, D);+ T_60_79(72, D, E, A, B, C);+ T_60_79(73, C, D, E, A, B);+ T_60_79(74, B, C, D, E, A);+ T_60_79(75, A, B, C, D, E);+ T_60_79(76, E, A, B, C, D);+ T_60_79(77, D, E, A, B, C);+ T_60_79(78, C, D, E, A, B);+ T_60_79(79, B, C, D, E, A);++ ctx->H[0] += A;+ ctx->H[1] += B;+ ctx->H[2] += C;+ ctx->H[3] += D;+ ctx->H[4] += E;+}++void git__blk_SHA1_Init(blk_SHA_CTX *ctx)+{+ ctx->size = 0;++ /* Initialize H with the magic constants (see FIPS180 for constants) */+ ctx->H[0] = 0x67452301;+ ctx->H[1] = 0xefcdab89;+ ctx->H[2] = 0x98badcfe;+ ctx->H[3] = 0x10325476;+ ctx->H[4] = 0xc3d2e1f0;+}++void git__blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)+{+ unsigned int lenW = ctx->size & 63;++ ctx->size += len;++ /* Read the data into W and process blocks as they get full */+ if (lenW) {+ unsigned int left = 64 - lenW;+ if (len < left)+ left = len;+ memcpy(lenW + (char *)ctx->W, data, left);+ lenW = (lenW + left) & 63;+ len -= left;+ data = ((const char *)data + left);+ if (lenW)+ return;+ blk_SHA1_Block(ctx, ctx->W);+ }+ while (len >= 64) {+ blk_SHA1_Block(ctx, data);+ data = ((const char *)data + 64);+ len -= 64;+ }+ if (len)+ memcpy(ctx->W, data, len);+}++void git__blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx)+{+ static const unsigned char pad[64] = { 0x80 };+ unsigned int padlen[2];+ int i;++ /* Pad with a binary 1 (ie 0x80), then zeroes, then length */+ padlen[0] = htonl((uint32_t)(ctx->size >> 29));+ padlen[1] = htonl((uint32_t)(ctx->size << 3));++ i = ctx->size & 63;+ git__blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));+ git__blk_SHA1_Update(ctx, padlen, 8);++ /* Output hash */+ for (i = 0; i < 5; i++)+ put_be32(hashout + i*4, ctx->H[i]);+}
+ libgit2/src/block-sha1/sha1.h view
@@ -0,0 +1,22 @@+/*+ * SHA1 routine optimized to do word accesses rather than byte accesses,+ * and to avoid unnecessary copies into the context array.+ *+ * This was initially based on the Mozilla SHA1 implementation, although+ * none of the original Mozilla code remains.+ */++typedef struct {+ unsigned long long size;+ unsigned int H[5];+ unsigned int W[16];+} blk_SHA_CTX;++void git__blk_SHA1_Init(blk_SHA_CTX *ctx);+void git__blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len);+void git__blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);++#define SHA_CTX blk_SHA_CTX+#define SHA1_Init git__blk_SHA1_Init+#define SHA1_Update git__blk_SHA1_Update+#define SHA1_Final git__blk_SHA1_Final
+ libgit2/src/bswap.h view
@@ -0,0 +1,97 @@+/*+ * Let's make sure we always have a sane definition for ntohl()/htonl().+ * Some libraries define those as a function call, just to perform byte+ * shifting, bringing significant overhead to what should be a simple+ * operation.+ */++#include "common.h"++/*+ * Default version that the compiler ought to optimize properly with+ * constant values.+ */+GIT_INLINE(uint32_t) default_swab32(uint32_t val)+{+ return (((val & 0xff000000) >> 24) |+ ((val & 0x00ff0000) >> 8) |+ ((val & 0x0000ff00) << 8) |+ ((val & 0x000000ff) << 24));+}++#undef bswap32++GIT_INLINE(uint16_t) default_swab16(uint16_t val)+{+ return (((val & 0xff00) >> 8) |+ ((val & 0x00ff) << 8));+}++#undef bswap16++#if defined(__GNUC__) && defined(__i386__)++#define bswap32(x) ({ \+ uint32_t __res; \+ if (__builtin_constant_p(x)) { \+ __res = default_swab32(x); \+ } else { \+ __asm__("bswap %0" : "=r" (__res) : "0" ((uint32_t)(x))); \+ } \+ __res; })++#define bswap16(x) ({ \+ uint16_t __res; \+ if (__builtin_constant_p(x)) { \+ __res = default_swab16(x); \+ } else { \+ __asm__("xchgb %b0,%h0" : "=q" (__res) : "0" ((uint16_t)(x))); \+ } \+ __res; })++#elif defined(__GNUC__) && defined(__x86_64__)++#define bswap32(x) ({ \+ uint32_t __res; \+ if (__builtin_constant_p(x)) { \+ __res = default_swab32(x); \+ } else { \+ __asm__("bswapl %0" : "=r" (__res) : "0" ((uint32_t)(x))); \+ } \+ __res; })++#define bswap16(x) ({ \+ uint16_t __res; \+ if (__builtin_constant_p(x)) { \+ __res = default_swab16(x); \+ } else { \+ __asm__("xchgb %b0,%h0" : "=Q" (__res) : "0" ((uint16_t)(x))); \+ } \+ __res; })++#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))++#include <stdlib.h>++#define bswap32(x) _byteswap_ulong(x)+#define bswap16(x) _byteswap_ushort(x)++#endif++#ifdef bswap32++#undef ntohl+#undef htonl+#define ntohl(x) bswap32(x)+#define htonl(x) bswap32(x)++#endif++#ifdef bswap16++#undef ntohs+#undef htons+#define ntohs(x) bswap16(x)+#define htons(x) bswap16(x)++#endif
+ libgit2/src/cc-compat.h view
@@ -0,0 +1,73 @@+/*+ * cc-compat.h - C compiler compat macros for internal use+ */+#ifndef INCLUDE_compat_h__+#define INCLUDE_compat_h__++/*+ * See if our compiler is known to support flexible array members.+ */+#ifndef GIT_FLEX_ARRAY+# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)+# define GIT_FLEX_ARRAY /* empty */+# elif defined(__GNUC__)+# if (__GNUC__ >= 3)+# define GIT_FLEX_ARRAY /* empty */+# else+# define GIT_FLEX_ARRAY 0 /* older GNU extension */+# endif+# endif++/* Default to safer but a bit wasteful traditional style */+# ifndef GIT_FLEX_ARRAY+# define GIT_FLEX_ARRAY 1+# endif+#endif++#ifdef __GNUC__+# define GIT_TYPEOF(x) (__typeof__(x))+#else+# define GIT_TYPEOF(x)+#endif++#ifdef __cplusplus+# define GIT_UNUSED(x)+#else+# ifdef __GNUC__+# define GIT_UNUSED(x) x __attribute__ ((__unused__))+# else+# define GIT_UNUSED(x) x+# endif+#endif++#if defined(_MSC_VER)+#define GIT_UNUSED_ARG(x) ((void)(x)); /* note trailing ; */+#else+#define GIT_UNUSED_ARG(x)+#endif++/*+ * Does our compiler/platform support the C99 <inttypes.h> and+ * <stdint.h> header files. (C99 requires that <inttypes.h>+ * includes <stdint.h>).+ */+#if !defined(_MSC_VER)+# define GIT_HAVE_INTTYPES_H 1+#endif++/* Define the printf format specifer to use for size_t output */+#if defined(_MSC_VER) || defined(__MINGW32__)+# define PRIuZ "Iu"+#else+# define PRIuZ "zu"+#endif++/* Micosoft Visual C/C++ */+#if defined(_MSC_VER)+/* disable "deprecated function" warnings */+# pragma warning ( disable : 4996 )+/* disable "conditional expression is constant" level 4 warnings */+# pragma warning ( disable : 4127 )+#endif++#endif /* INCLUDE_compat_h__ */
+ libgit2/src/commit.c view
@@ -0,0 +1,299 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "git2/common.h"+#include "git2/object.h"+#include "git2/repository.h"+#include "git2/signature.h"++#include "common.h"+#include "commit.h"+#include "signature.h"++#define COMMIT_BASIC_PARSE 0x0+#define COMMIT_FULL_PARSE 0x1++#define COMMIT_PRINT(commit) {\+ char oid[41]; oid[40] = 0;\+ git_oid_fmt(oid, &commit->object.id);\+ printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\+}++static void clear_parents(git_commit *commit)+{+ unsigned int i;++ for (i = 0; i < commit->parent_oids.length; ++i) {+ git_oid *parent = git_vector_get(&commit->parent_oids, i);+ free(parent);+ }++ git_vector_clear(&commit->parent_oids);+}++void git_commit__free(git_commit *commit)+{+ clear_parents(commit);+ git_vector_free(&commit->parent_oids);++ git_signature_free(commit->author);+ git_signature_free(commit->committer);++ free(commit->message);+ free(commit->message_short);+ free(commit);+}++const git_oid *git_commit_id(git_commit *c)+{+ return git_object_id((git_object *)c);+}++int git_commit__writeback(git_commit *commit, git_odb_source *src)+{+ unsigned int i;++ git__write_oid(src, "tree", &commit->tree_oid);++ for (i = 0; i < commit->parent_oids.length; ++i) {+ git_oid *parent_oid;++ parent_oid = git_vector_get(&commit->parent_oids, i);+ git__write_oid(src, "parent", parent_oid);+ }++ if (commit->author == NULL)+ return GIT_EMISSINGOBJDATA;++ git_signature__write(src, "author", commit->author);++ if (commit->committer == NULL)+ return GIT_EMISSINGOBJDATA;++ git_signature__write(src, "committer", commit->committer);++ if (commit->message != NULL) {+ git__source_write(src, "\n", 1);+ git__source_write(src, commit->message, strlen(commit->message));+ }++ return GIT_SUCCESS;+}++int commit_parse_buffer(git_commit *commit, void *data, size_t len)+{+ char *buffer = (char *)data;+ const char *buffer_end = (char *)data + len;++ git_oid parent_oid;+ int error;++ /* first parse; the vector hasn't been initialized yet */+ if (commit->parent_oids.contents == NULL) {+ git_vector_init(&commit->parent_oids, 4, NULL);+ }++ clear_parents(commit);++ if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)+ return error;++ /*+ * TODO: commit grafts!+ */++ while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {+ git_oid *new_oid;++ new_oid = git__malloc(sizeof(git_oid));+ git_oid_cpy(new_oid, &parent_oid);++ if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS)+ return GIT_ENOMEM;+ }++ if (commit->author)+ git_signature_free(commit->author);++ commit->author = git__malloc(sizeof(git_signature));+ if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)+ return error;++ /* Always parse the committer; we need the commit time */+ if (commit->committer)+ git_signature_free(commit->committer);++ commit->committer = git__malloc(sizeof(git_signature));+ if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS)+ return error;++ /* parse commit message */+ while (buffer <= buffer_end && *buffer == '\n')+ buffer++;++ if (buffer < buffer_end) {+ const char *line_end;+ size_t message_len = buffer_end - buffer;++ /* Long message */+ message_len = buffer_end - buffer;+ commit->message = git__malloc(message_len + 1);+ memcpy(commit->message, buffer, message_len);+ commit->message[message_len] = 0;++ /* Short message */+ if((line_end = memchr(buffer, '\n', buffer_end - buffer)) == NULL)+ line_end = buffer_end;+ message_len = line_end - buffer;++ commit->message_short = git__malloc(message_len + 1);+ memcpy(commit->message_short, buffer, message_len);+ commit->message_short[message_len] = 0;+ }++ return GIT_SUCCESS;+}++int git_commit__parse(git_commit *commit)+{+ assert(commit && commit->object.source.open);+ return commit_parse_buffer(commit,+ commit->object.source.raw.data, commit->object.source.raw.len);+}++#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \+ _rvalue git_commit_##_name(git_commit *commit) \+ {\+ assert(commit); \+ return _return; \+ }++GIT_COMMIT_GETTER(const git_signature *, author, commit->author)+GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)+GIT_COMMIT_GETTER(const char *, message, commit->message)+GIT_COMMIT_GETTER(const char *, message_short, commit->message_short)+GIT_COMMIT_GETTER(time_t, time, commit->committer->when.time)+GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)+GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)+++int git_commit_tree(git_tree **tree_out, git_commit *commit)+{+ assert(commit);+ return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid);+}++int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)+{+ git_oid *parent_oid;+ assert(commit);++ parent_oid = git_vector_get(&commit->parent_oids, n);+ if (parent_oid == NULL)+ return GIT_ENOTFOUND;++ return git_commit_lookup(parent, commit->object.repo, parent_oid);+}++++int git_commit_set_tree(git_commit *commit, git_tree *tree)+{+ const git_oid *oid;++ assert(commit && tree);++ if ((oid = git_object_id((git_object *)tree)) == NULL)+ return GIT_EMISSINGOBJDATA;++ commit->object.modified = 1;+ git_oid_cpy(&commit->tree_oid, oid);+ return GIT_SUCCESS;+}++int git_commit_add_parent(git_commit *commit, git_commit *new_parent)+{+ const git_oid *parent_oid;+ git_oid *new_oid;+ assert(commit && new_parent);++ if ((parent_oid = git_object_id((git_object *)new_parent)) == NULL)+ return GIT_EMISSINGOBJDATA;++ new_oid = git__malloc(sizeof(git_oid));+ if (new_oid == NULL)+ return GIT_ENOMEM;++ commit->object.modified = 1;+ git_oid_cpy(new_oid, parent_oid);+ return git_vector_insert(&commit->parent_oids, new_oid);+}++void git_commit_set_author(git_commit *commit, const git_signature *author_sig)+{+ assert(commit && author_sig);+ commit->object.modified = 1;++ git_signature_free(commit->author);+ commit->author = git_signature_dup(author_sig);+}++void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig)+{+ assert(commit && committer_sig);+ commit->object.modified = 1;++ git_signature_free(commit->committer);+ commit->committer = git_signature_dup(committer_sig);+}++void git_commit_set_message(git_commit *commit, const char *message)+{+ const char *line_end;+ size_t message_len;++ commit->object.modified = 1;++ if (commit->message)+ free(commit->message);++ if (commit->message_short)+ free(commit->message_short);++ commit->message = git__strdup(message);++ /* Short message */+ if((line_end = strchr(message, '\n')) == NULL) {+ commit->message_short = git__strdup(message);+ return;+ }++ message_len = line_end - message;++ commit->message_short = git__malloc(message_len + 1);+ memcpy(commit->message_short, message, message_len);+ commit->message_short[message_len] = 0;+}+
+ libgit2/src/commit.h view
@@ -0,0 +1,29 @@+#ifndef INCLUDE_commit_h__+#define INCLUDE_commit_h__++#include "git2/commit.h"+#include "tree.h"+#include "repository.h"+#include "vector.h"++#include <time.h>++struct git_commit {+ git_object object;++ git_vector parent_oids;+ git_oid tree_oid;++ git_signature *author;+ git_signature *committer;++ char *message;+ char *message_short;+};++void git_commit__free(git_commit *c);+int git_commit__parse(git_commit *commit);++int git_commit__writeback(git_commit *commit, git_odb_source *src);++#endif
+ libgit2/src/common.h view
@@ -0,0 +1,56 @@+#ifndef INCLUDE_common_h__+#define INCLUDE_common_h__++/** Force 64 bit off_t size on POSIX. */+#define _FILE_OFFSET_BITS 64++#if defined(_WIN32) && !defined(__CYGWIN__)+#define GIT_WIN32 1+#endif++#include "git2/thread-utils.h"+#include "cc-compat.h"++#ifdef GIT_HAVE_INTTYPES_H+# include <inttypes.h>+#endif+#include <assert.h>+#include <errno.h>+#include <limits.h>+#include <stdlib.h>+#include <stdio.h>+#include <string.h>++#include <sys/types.h>+#include <sys/stat.h>++#ifdef GIT_WIN32++# include <io.h>+# include <direct.h>+# include <windows.h>+# include "msvc-compat.h"+# include "mingw-compat.h"+# include "win32/pthread.h"++# define snprintf _snprintf++typedef SSIZE_T ssize_t;++#else++# include <unistd.h>+# include <arpa/inet.h>+# include <pthread.h>++#endif++#include "git2/common.h"+#include "git2/types.h"+#include "util.h"+#include "thread-utils.h"+#include "bswap.h"++#define GIT_PATH_MAX 4096++#endif /* INCLUDE_common_h__ */
+ libgit2/src/delta-apply.c view
@@ -0,0 +1,109 @@+#include "common.h"+#include "git2/odb.h"+#include "delta-apply.h"++/*+ * This file was heavily cribbed from BinaryDelta.java in JGit, which+ * itself was heavily cribbed from <code>patch-delta.c</code> in the+ * GIT project. The original delta patching code was written by+ * Nicolas Pitre <nico@cam.org>.+ */++static int hdr_sz(+ size_t *size,+ const unsigned char **delta,+ const unsigned char *end)+{+ const unsigned char *d = *delta;+ size_t r = 0;+ unsigned int c, shift = 0;++ do {+ if (d == end)+ return -1;+ c = *d++;+ r |= (c & 0x7f) << shift;+ shift += 7;+ } while (c & 0x80);+ *delta = d;+ *size = r;+ return 0;+}++int git__delta_apply(+ git_rawobj *out,+ const unsigned char *base,+ size_t base_len,+ const unsigned char *delta,+ size_t delta_len)+{+ const unsigned char *delta_end = delta + delta_len;+ size_t base_sz, res_sz;+ unsigned char *res_dp;++ /* Check that the base size matches the data we were given;+ * if not we would underflow while accessing data from the+ * base object, resulting in data corruption or segfault.+ */+ if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len))+ return GIT_ERROR;++ if (hdr_sz(&res_sz, &delta, delta_end) < 0)+ return GIT_ERROR;++ if ((res_dp = git__malloc(res_sz + 1)) == NULL)+ return GIT_ERROR;+ res_dp[res_sz] = '\0';+ out->data = res_dp;+ out->len = res_sz;++ while (delta < delta_end) {+ unsigned char cmd = *delta++;+ if (cmd & 0x80) {+ /* cmd is a copy instruction; copy from the base.+ */+ size_t off = 0, len = 0;++ if (cmd & 0x01) off = *delta++;+ if (cmd & 0x02) off |= *delta++ << 8;+ if (cmd & 0x04) off |= *delta++ << 16;+ if (cmd & 0x08) off |= *delta++ << 24;++ if (cmd & 0x10) len = *delta++;+ if (cmd & 0x20) len |= *delta++ << 8;+ if (cmd & 0x40) len |= *delta++ << 16;+ if (!len) len = 0x10000;++ if (base_len < off + len || res_sz < len)+ goto fail;+ memcpy(res_dp, base + off, len);+ res_dp += len;+ res_sz -= len;++ } else if (cmd) {+ /* cmd is a literal insert instruction; copy from+ * the delta stream itself.+ */+ if (delta_end - delta < cmd || res_sz < cmd)+ goto fail;+ memcpy(res_dp, delta, cmd);+ delta += cmd;+ res_dp += cmd;+ res_sz -= cmd;++ } else {+ /* cmd == 0 is reserved for future encodings.+ */+ goto fail;+ }+ }++ if (delta != delta_end || res_sz)+ goto fail;+ return GIT_SUCCESS;++fail:+ free(out->data);+ out->data = NULL;+ return GIT_ERROR;+}
+ libgit2/src/delta-apply.h view
@@ -0,0 +1,25 @@+#ifndef INCLUDE_delta_apply_h__+#define INCLUDE_delta_apply_h__++/**+ * Apply a git binary delta to recover the original content.+ *+ * @param out the output buffer to receive the original data.+ * Only out->data and out->len are populated, as this is+ * the only information available in the delta.+ * @param base the base to copy from during copy instructions.+ * @param base_len number of bytes available at base.+ * @param delta the delta to execute copy/insert instructions from.+ * @param delta_len total number of bytes in the delta.+ * @return+ * - GIT_SUCCESS on a successful delta unpack.+ * - GIT_ERROR if the delta is corrupt or doesn't match the base.+ */+extern int git__delta_apply(+ git_rawobj *out,+ const unsigned char *base,+ size_t base_len,+ const unsigned char *delta,+ size_t delta_len);++#endif
+ libgit2/src/dir.h view
@@ -0,0 +1,41 @@+#ifndef INCLUDE_dir_h__+#define INCLUDE_dir_h__++#include "common.h"++#ifndef GIT_WIN32+# include <dirent.h>+#endif++#ifdef GIT_WIN32++struct git__dirent {+ int d_ino;+ char d_name[261];+};++typedef struct {+ HANDLE h;+ WIN32_FIND_DATA f;+ struct git__dirent entry;+ char *dir;+ int first;+} git__DIR;++extern git__DIR *git__opendir(const char *);+extern struct git__dirent *git__readdir(git__DIR *);+extern void git__rewinddir(git__DIR *);+extern int git__closedir(git__DIR *);++# ifndef GIT__WIN32_NO_WRAP_DIR+# define dirent git__dirent+# define DIR git__DIR+# define opendir git__opendir+# define readdir git__readdir+# define rewinddir git__rewinddir+# define closedir git__closedir+# endif++#endif++#endif /* INCLUDE_dir_h__ */
+ libgit2/src/errors.c view
@@ -0,0 +1,44 @@+#include "common.h"+#include "thread-utils.h" /* for GIT_TLS */++static struct {+ int num;+ const char *str;+} error_codes[] = {+ {GIT_ERROR, "Unspecified error"},+ {GIT_ENOTOID, "Input was not a properly formatted Git object id."},+ {GIT_ENOTFOUND, "Object does not exist in the scope searched."},+ {GIT_ENOMEM, "Not enough space available."},+ {GIT_EOSERR, "Consult the OS error information."},+ {GIT_EOBJTYPE, "The specified object is of invalid type"},+ {GIT_EOBJCORRUPTED, "The specified object has its data corrupted"},+ {GIT_ENOTAREPO, "The specified repository is invalid"},+ {GIT_EINVALIDTYPE, "The object type is invalid or doesn't match"},+ {GIT_EMISSINGOBJDATA, "The object cannot be written that because it's missing internal data"},+ {GIT_EPACKCORRUPTED, "The packfile for the ODB is corrupted"},+ {GIT_EFLOCKFAIL, "Failed to adquire or release a file lock"},+ {GIT_EZLIB, "The Z library failed to inflate/deflate an object's data"},+ {GIT_EBUSY, "The queried object is currently busy"},+ {GIT_EINVALIDPATH, "The path is invalid"},+ {GIT_EBAREINDEX, "The index file is not backed up by an existing repository"},+ {GIT_EINVALIDREFNAME, "The name of the reference is not valid"},+ {GIT_EREFCORRUPTED, "The specified reference has its data corrupted"},+ {GIT_ETOONESTEDSYMREF, "The specified symbolic reference is too deeply nested"},+ {GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},+ {GIT_EINVALIDPATH, "The path is invalid" },+ {GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},+ {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}+};++const char *git_strerror(int num)+{+ size_t i;++ if (num == GIT_EOSERR)+ return strerror(errno);+ for (i = 0; i < ARRAY_SIZE(error_codes); i++)+ if (num == error_codes[i].num)+ return error_codes[i].str;++ return "Unknown error";+}
+ libgit2/src/filebuf.c view
@@ -0,0 +1,291 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#include <stdarg.h>++#include "common.h"+#include "filebuf.h"+#include "fileops.h"++static const size_t WRITE_BUFFER_SIZE = (4096 * 2);++static int lock_file(git_filebuf *file, int flags)+{+ if (gitfo_exists(file->path_lock) == 0) {+ if (flags & GIT_FILEBUF_FORCE)+ gitfo_unlink(file->path_lock);+ else+ return GIT_EOSERR;+ }++ /* create path to the file buffer is required */+ if (flags & GIT_FILEBUF_FORCE) {+ file->fd = gitfo_creat_force(file->path_lock, 0644);+ } else {+ file->fd = gitfo_creat(file->path_lock, 0644);+ }++ if (file->fd < 0)+ return GIT_EOSERR;++ /* TODO: do a flock() in the descriptor file_lock */++ if ((flags & GIT_FILEBUF_APPEND) && gitfo_exists(file->path_original) == 0) {+ git_file source;+ char buffer[2048];+ size_t read_bytes;++ source = gitfo_open(file->path_original, O_RDONLY);+ if (source < 0)+ return GIT_EOSERR;++ while ((read_bytes = gitfo_read(source, buffer, 2048)) > 0) {+ gitfo_write(file->fd, buffer, read_bytes);+ if (file->digest)+ git_hash_update(file->digest, buffer, read_bytes);+ }++ gitfo_close(source);+ }++ return GIT_SUCCESS;+}++void git_filebuf_cleanup(git_filebuf *file)+{+ if (file->fd >= 0)+ gitfo_close(file->fd);++ if (gitfo_exists(file->path_lock) == GIT_SUCCESS)+ gitfo_unlink(file->path_lock);++ if (file->digest)+ git_hash_free_ctx(file->digest);++ free(file->buffer);++#ifdef GIT_FILEBUF_THREADS+ free(file->buffer_back);+#endif++ free(file->path_original);+ free(file->path_lock);+}++static int flush_buffer(git_filebuf *file)+{+ int result = GIT_SUCCESS;++ if (file->buf_pos > 0) {+ result = gitfo_write(file->fd, file->buffer, file->buf_pos);+ if (file->digest)+ git_hash_update(file->digest, file->buffer, file->buf_pos);++ file->buf_pos = 0;+ }++ return result;+}++int git_filebuf_open(git_filebuf *file, const char *path, int flags)+{+ int error;+ size_t path_len;++ if (file == NULL || path == NULL)+ return GIT_ERROR;++ memset(file, 0x0, sizeof(git_filebuf));++ file->buf_size = WRITE_BUFFER_SIZE;+ file->buf_pos = 0;+ file->fd = -1;++ path_len = strlen(path);++ file->path_original = git__strdup(path);+ if (file->path_original == NULL) {+ error = GIT_ENOMEM;+ goto cleanup;+ }++ file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);+ if (file->path_lock == NULL) {+ error = GIT_ENOMEM;+ goto cleanup;+ }++ memcpy(file->path_lock, file->path_original, path_len);+ memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);++ file->buffer = git__malloc(file->buf_size);+ if (file->buffer == NULL){+ error = GIT_ENOMEM;+ goto cleanup;+ }++#ifdef GIT_FILEBUF_THREADS+ file->buffer_back = git__malloc(file->buf_size);+ if (file->buffer_back == NULL){+ error = GIT_ENOMEM;+ goto cleanup;+ }+#endif++ if (flags & GIT_FILEBUF_HASH_CONTENTS) {+ if ((file->digest = git_hash_new_ctx()) == NULL) {+ error = GIT_ENOMEM;+ goto cleanup;+ }+ }++ if ((error = lock_file(file, flags)) < GIT_SUCCESS)+ goto cleanup;++ return GIT_SUCCESS;++cleanup:+ git_filebuf_cleanup(file);+ return error;+}++int git_filebuf_hash(git_oid *oid, git_filebuf *file)+{+ int error;++ if (file->digest == NULL)+ return GIT_ERROR;++ if ((error = flush_buffer(file)) < GIT_SUCCESS)+ return error;++ git_hash_final(oid, file->digest);+ git_hash_free_ctx(file->digest);+ file->digest = NULL;++ return GIT_SUCCESS;+}++int git_filebuf_commit(git_filebuf *file)+{+ int error;++ if ((error = flush_buffer(file)) < GIT_SUCCESS)+ goto cleanup;++ gitfo_close(file->fd);+ file->fd = -1;++ error = gitfo_mv(file->path_lock, file->path_original);++cleanup:+ git_filebuf_cleanup(file);+ return error;+}++GIT_INLINE(void) add_to_cache(git_filebuf *file, void *buf, size_t len)+{+ memcpy(file->buffer + file->buf_pos, buf, len);+ file->buf_pos += len;+}++int git_filebuf_write(git_filebuf *file, void *buff, size_t len)+{+ int error;+ unsigned char *buf = buff;++ for (;;) {+ size_t space_left = file->buf_size - file->buf_pos;++ /* cache if it's small */+ if (space_left > len) {+ add_to_cache(file, buf, len);+ return GIT_SUCCESS;+ }++ /* flush the cache if it doesn't fit */+ if (file->buf_pos > 0) {+ add_to_cache(file, buf, space_left);++ if ((error = flush_buffer(file)) < GIT_SUCCESS)+ return error;++ len -= space_left;+ buf += space_left;+ }++ /* write too-large chunks immediately */+ if (len > file->buf_size) {+ error = gitfo_write(file->fd, buf, len);+ if (file->digest)+ git_hash_update(file->digest, buf, len);+ }+ }+}++int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len)+{+ int error;+ size_t space_left = file->buf_size - file->buf_pos;++ *buffer = NULL;++ if (len > file->buf_size)+ return GIT_ENOMEM;++ if (space_left <= len) {+ if ((error = flush_buffer(file)) < GIT_SUCCESS)+ return error;+ }++ *buffer = (file->buffer + file->buf_pos);+ file->buf_pos += len;++ return GIT_SUCCESS;+}++int git_filebuf_printf(git_filebuf *file, const char *format, ...)+{+ va_list arglist;+ size_t space_left = file->buf_size - file->buf_pos;+ int len, error;++ va_start(arglist, format);++ len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);++ if (len < 0 || (size_t)len >= space_left) {+ if ((error = flush_buffer(file)) < GIT_SUCCESS)+ return error;++ len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);+ if (len < 0 || (size_t)len > file->buf_size)+ return GIT_ENOMEM;+ }++ file->buf_pos += len;+ return GIT_SUCCESS;++}+
+ libgit2/src/filebuf.h view
@@ -0,0 +1,44 @@+#ifndef INCLUDE_filebuf_h__+#define INCLUDE_filebuf_h__++#include "fileops.h"+#include "hash.h"++#ifdef GIT_THREADS+# define GIT_FILEBUF_THREADS+#endif++#define GIT_FILEBUF_HASH_CONTENTS 0x1+#define GIT_FILEBUF_APPEND 0x2+#define GIT_FILEBUF_FORCE 0x4++#define GIT_FILELOCK_EXTENSION ".lock\0"+#define GIT_FILELOCK_EXTLENGTH 6++struct git_filebuf {+ char *path_original;+ char *path_lock;++ git_hash_ctx *digest;++ unsigned char *buffer;+#ifdef GIT_FILEBUF_THREADS+ unsigned char *buffer_back;+#endif++ size_t buf_size, buf_pos;+ git_file fd;+};++typedef struct git_filebuf git_filebuf;++int git_filebuf_write(git_filebuf *lock, void *buff, size_t len);+int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);+int git_filebuf_printf(git_filebuf *file, const char *format, ...);++int git_filebuf_open(git_filebuf *lock, const char *path, int flags);+int git_filebuf_commit(git_filebuf *lock);+void git_filebuf_cleanup(git_filebuf *lock);+int git_filebuf_hash(git_oid *oid, git_filebuf *file);++#endif
+ libgit2/src/fileops.c view
@@ -0,0 +1,553 @@+#include "common.h"+#include "fileops.h"+#include <ctype.h>++static int force_path(const char *to)+{+ const int mode = 0755; /* or 0777 ? */+ int error = GIT_SUCCESS;+ char target_folder_path[GIT_PATH_MAX];++ error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to);+ if (error < GIT_SUCCESS)+ return error;++ /* Does the containing folder exist? */+ if (gitfo_isdir(target_folder_path)) {+ git__joinpath(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */++ /* Let's create the tree structure */+ error = gitfo_mkdir_recurs(target_folder_path, mode);+ if (error < GIT_SUCCESS)+ return error;+ }++ return GIT_SUCCESS;+}++int gitfo_open(const char *path, int flags)+{+ int fd = open(path, flags | O_BINARY);+ return fd >= 0 ? fd : GIT_EOSERR;+}++int gitfo_creat(const char *path, int mode)+{+ int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);+ return fd >= 0 ? fd : GIT_EOSERR;+}++int gitfo_creat_force(const char *path, int mode)+{+ if (force_path(path) < GIT_SUCCESS)+ return GIT_EOSERR;++ return gitfo_creat(path, mode);+}++int gitfo_read(git_file fd, void *buf, size_t cnt)+{+ char *b = buf;+ while (cnt) {+ ssize_t r = read(fd, b, cnt);+ if (r < 0) {+ if (errno == EINTR || errno == EAGAIN)+ continue;+ return GIT_EOSERR;+ }+ if (!r) {+ errno = EPIPE;+ return GIT_EOSERR;+ }+ cnt -= r;+ b += r;+ }+ return GIT_SUCCESS;+}++int gitfo_write(git_file fd, void *buf, size_t cnt)+{+ char *b = buf;+ while (cnt) {+ ssize_t r = write(fd, b, cnt);+ if (r < 0) {+ if (errno == EINTR || errno == EAGAIN)+ continue;+ return GIT_EOSERR;+ }+ if (!r) {+ errno = EPIPE;+ return GIT_EOSERR;+ }+ cnt -= r;+ b += r;+ }+ return GIT_SUCCESS;+}++int gitfo_isdir(const char *path)+{+ struct stat st;+ int len, stat_error;++ if (!path)+ return GIT_ENOTFOUND;++ len = strlen(path);++ /* win32: stat path for folders cannot end in a slash */+ if (path[len - 1] == '/') {+ char *path_fixed = NULL;+ path_fixed = git__strdup(path);+ path_fixed[len - 1] = 0;+ stat_error = gitfo_stat(path_fixed, &st);+ free(path_fixed);+ } else {+ stat_error = gitfo_stat(path, &st);+ }++ if (stat_error < GIT_SUCCESS)+ return GIT_ENOTFOUND;++ if (!S_ISDIR(st.st_mode))+ return GIT_ENOTFOUND;++ return GIT_SUCCESS;+}++int gitfo_exists(const char *path)+{+ return access(path, F_OK);+}++git_off_t gitfo_size(git_file fd)+{+ struct stat sb;+ if (gitfo_fstat(fd, &sb))+ return GIT_EOSERR;+ return sb.st_size;+}++int gitfo_read_file(gitfo_buf *obj, const char *path)+{+ git_file fd;+ size_t len;+ git_off_t size;+ unsigned char *buff;++ assert(obj && path && *path);++ if ((fd = gitfo_open(path, O_RDONLY)) < 0)+ return GIT_ERROR;++ if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) {+ gitfo_close(fd);+ return GIT_ERROR;+ }+ len = (size_t) size;++ if ((buff = git__malloc(len + 1)) == NULL) {+ gitfo_close(fd);+ return GIT_ERROR;+ }++ if (gitfo_read(fd, buff, len) < 0) {+ gitfo_close(fd);+ free(buff);+ return GIT_ERROR;+ }+ buff[len] = '\0';++ gitfo_close(fd);++ obj->data = buff;+ obj->len = len;++ return GIT_SUCCESS;+}++void gitfo_free_buf(gitfo_buf *obj)+{+ assert(obj);+ free(obj->data);+ obj->data = NULL;+}++int gitfo_mv(const char *from, const char *to)+{+#ifdef GIT_WIN32+ /*+ * Win32 POSIX compilance my ass. If the destination+ * file exists, the `rename` call fails. This is as+ * close as it gets with the Win32 API.+ */+ return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) ? GIT_SUCCESS : GIT_EOSERR;+#else+ /* Don't even try this on Win32 */+ if (!link(from, to)) {+ gitfo_unlink(from);+ return GIT_SUCCESS;+ }++ if (!rename(from, to))+ return GIT_SUCCESS;++ return GIT_EOSERR;+#endif+}++int gitfo_mv_force(const char *from, const char *to)+{+ if (force_path(to) < GIT_SUCCESS)+ return GIT_EOSERR;++ return gitfo_mv(from, to);+}++int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len)+{+ if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < GIT_SUCCESS)+ return GIT_EOSERR;+ return GIT_SUCCESS;+}++void gitfo_free_map(git_map *out)+{+ git__munmap(out);+}++/* cached diskio */+struct gitfo_cache {+ git_file fd;+ size_t cache_size, pos;+ unsigned char *cache;+};++gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size)+{+ gitfo_cache *ioc;++ ioc = git__malloc(sizeof(*ioc));+ if (!ioc)+ return NULL;++ ioc->fd = fd;+ ioc->pos = 0;+ ioc->cache_size = cache_size;+ ioc->cache = git__malloc(cache_size);+ if (!ioc->cache) {+ free(ioc);+ return NULL;+ }++ return ioc;+}++GIT_INLINE(void) gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len)+{+ memcpy(ioc->cache + ioc->pos, buf, len);+ ioc->pos += len;+}++int gitfo_flush_cached(gitfo_cache *ioc)+{+ int result = GIT_SUCCESS;++ if (ioc->pos) {+ result = gitfo_write(ioc->fd, ioc->cache, ioc->pos);+ ioc->pos = 0;+ }++ return result;+}++int gitfo_write_cached(gitfo_cache *ioc, void *buff, size_t len)+{+ unsigned char *buf = buff;++ for (;;) {+ size_t space_left = ioc->cache_size - ioc->pos;+ /* cache if it's small */+ if (space_left > len) {+ gitfo_add_to_cache(ioc, buf, len);+ return GIT_SUCCESS;+ }++ /* flush the cache if it doesn't fit */+ if (ioc->pos) {+ int rc;+ gitfo_add_to_cache(ioc, buf, space_left);+ rc = gitfo_flush_cached(ioc);+ if (rc < 0)+ return rc;++ len -= space_left;+ buf += space_left;+ }++ /* write too-large chunks immediately */+ if (len > ioc->cache_size)+ return gitfo_write(ioc->fd, buf, len);+ }+}++int gitfo_close_cached(gitfo_cache *ioc)+{+ git_file fd;++ if (gitfo_flush_cached(ioc) < GIT_SUCCESS)+ return GIT_ERROR;++ fd = ioc->fd;+ free(ioc->cache);+ free(ioc);++ return gitfo_close(fd);+}++int gitfo_dirent(+ char *path,+ size_t path_sz,+ int (*fn)(void *, char *),+ void *arg)+{+ size_t wd_len = strlen(path);+ DIR *dir;+ struct dirent *de;++ if (!wd_len || path_sz < wd_len + 2)+ return GIT_ERROR;++ while (path[wd_len - 1] == '/')+ wd_len--;+ path[wd_len++] = '/';+ path[wd_len] = '\0';++ dir = opendir(path);+ if (!dir)+ return GIT_EOSERR;++ while ((de = readdir(dir)) != NULL) {+ size_t de_len;+ int result;++ /* always skip '.' and '..' */+ if (de->d_name[0] == '.') {+ if (de->d_name[1] == '\0')+ continue;+ if (de->d_name[1] == '.' && de->d_name[2] == '\0')+ continue;+ }++ de_len = strlen(de->d_name);+ if (path_sz < wd_len + de_len + 1) {+ closedir(dir);+ return GIT_ERROR;+ }++ strcpy(path + wd_len, de->d_name);+ result = fn(arg, path);+ if (result < GIT_SUCCESS) {+ closedir(dir);+ return result;+ }+ if (result > 0) {+ closedir(dir);+ return result;+ }+ }++ closedir(dir);+ return GIT_SUCCESS;+}++#ifdef GIT_WIN32++static int is_windows_rooted_path(const char *path)+{+ /* Does the root of the path look like a windows drive ? */+ if (isalpha(path[0]) && (path[1] == ':'))+ return GIT_SUCCESS;++ return GIT_ERROR;+}++#endif++int gitfo_mkdir_recurs(const char *path, int mode)+{+ int error;+ char *pp, *sp;+ char *path_copy = git__strdup(path);++ if (path_copy == NULL)+ return GIT_ENOMEM;++ error = GIT_SUCCESS;+ pp = path_copy;++#ifdef GIT_WIN32++ if (!is_windows_rooted_path(pp))+ pp += 2; /* Skip the drive name (eg. C: or D:) */++#endif++ while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) {+ if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) {+ *sp = 0;+ error = gitfo_mkdir(path_copy, mode);++ /* Do not choke while trying to recreate an existing directory */+ if (errno == EEXIST)+ error = GIT_SUCCESS;++ *sp = '/';+ }++ pp = sp + 1;+ }++ if (*(pp - 1) != '/' && error == GIT_SUCCESS)+ error = gitfo_mkdir(path, mode);++ free(path_copy);+ return error;+}++static int retrieve_previous_path_component_start(const char *path)+{+ int offset, len, start = 0;+ + len = strlen(path);+ offset = len - 1;++ /* Skip leading slash */+ if (path[start] == '/')+ start++;++ /* Skip trailing slash */+ if (path[offset] == '/')+ offset--;++ if (offset < 0)+ return GIT_ERROR;++ while (offset > start && path[offset-1] != '/') {+ offset--;+ }++ return offset;+}++int gitfo_prettify_dir_path(char *buffer_out, const char *path)+{+ int len = 0, segment_len, only_dots;+ char *current;+ const char *buffer_out_start, *buffer_end;++ buffer_out_start = buffer_out;+ current = (char *)path;+ buffer_end = path + strlen(path);++ while (current < buffer_end) {+ /* Prevent multiple slashes from being added to the output */+ if (*current == '/' && len > 0 && buffer_out_start[len - 1] == '/') {+ current++;+ continue;+ }+ + only_dots = 1;+ segment_len = 0;++ /* Copy path segment to the output */+ while (current < buffer_end && *current !='/')+ {+ only_dots &= (*current == '.');+ *buffer_out++ = *current++;+ segment_len++;+ len++;+ }++ /* Skip current directory */+ if (only_dots && segment_len == 1)+ {+ current++;+ buffer_out -= segment_len;+ len -= segment_len;+ continue;+ }++ /* Handle the double-dot upward directory navigation */+ if (only_dots && segment_len == 2)+ {+ current++;+ buffer_out -= segment_len;++ *buffer_out ='\0';+ len = retrieve_previous_path_component_start(buffer_out_start);+ if (len < GIT_SUCCESS)+ return GIT_EINVALIDPATH;++ buffer_out = (char *)buffer_out_start + len;+ continue;+ }++ /* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */+ if (only_dots &&segment_len > 0)+ return GIT_EINVALIDPATH;++ *buffer_out++ = '/';+ len++;+ }++ *buffer_out = '\0';++ return GIT_SUCCESS;+}++int gitfo_prettify_file_path(char *buffer_out, const char *path)+{+ int error, path_len, i;+ const char* pattern = "/..";++ path_len = strlen(path);++ /* Let's make sure the filename doesn't end with "/", "/." or "/.." */+ for (i = 1; path_len > i && i < 4; i++) {+ if (!strncmp(path + path_len - i, pattern, i))+ return GIT_EINVALIDPATH;+ }++ error = gitfo_prettify_dir_path(buffer_out, path);+ if (error < GIT_SUCCESS)+ return error;++ path_len = strlen(buffer_out);+ if (path_len < 2)+ return GIT_EINVALIDPATH;++ /* Remove the trailing slash */+ buffer_out[path_len - 1] = '\0';++ return GIT_SUCCESS;+}++int gitfo_cmp_path(const char *name1, int len1, int isdir1,+ const char *name2, int len2, int isdir2)+{+ int len = len1 < len2 ? len1 : len2;+ int cmp;++ cmp = memcmp(name1, name2, len);+ if (cmp)+ return cmp;+ if (len1 < len2)+ return ((!isdir1 && !isdir2) ? -1 :+ (isdir1 ? '/' - name2[len1] : name2[len1] - '/'));+ if (len1 > len2)+ return ((!isdir1 && !isdir2) ? 1 :+ (isdir2 ? name1[len2] - '/' : '/' - name1[len2]));+ return 0;+}+
+ libgit2/src/fileops.h view
@@ -0,0 +1,191 @@+/*+ * fileops.h - OS agnostic disk io operations+ *+ * This header describes the strictly internal part of the api+ */+#ifndef INCLUDE_fileops_h__+#define INCLUDE_fileops_h__++#include "common.h"+#include "map.h"+#include "dir.h"+#include <fcntl.h>+#include <time.h>++#ifdef GIT_WIN32+GIT_INLINE(int) link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new))+{+ GIT_UNUSED_ARG(old)+ GIT_UNUSED_ARG(new)+ errno = ENOSYS;+ return -1;+}++GIT_INLINE(int) git__mkdir(const char *path, int GIT_UNUSED(mode))+{+ GIT_UNUSED_ARG(mode)+ return mkdir(path);+}++extern int git__unlink(const char *path);+extern int git__mkstemp(char *template);+extern int git__fsync(int fd);++# ifndef GIT__WIN32_NO_HIDE_FILEOPS+# define unlink(p) git__unlink(p)+# define mkstemp(t) git__mkstemp(t)+# define mkdir(p,m) git__mkdir(p, m)+# define fsync(fd) git__fsync(fd)+# endif+#endif /* GIT_WIN32 */+++#if !defined(O_BINARY)+#define O_BINARY 0+#endif++#define GITFO_BUF_INIT {NULL, 0}++typedef int git_file;+typedef struct gitfo_cache gitfo_cache;++typedef struct { /* file io buffer */+ void *data; /* data bytes */+ size_t len; /* data length */+} gitfo_buf;++extern int gitfo_exists(const char *path);+extern int gitfo_open(const char *path, int flags);+extern int gitfo_creat(const char *path, int mode);+extern int gitfo_creat_force(const char *path, int mode);+extern int gitfo_isdir(const char *path);+extern int gitfo_mkdir_recurs(const char *path, int mode);+#define gitfo_close(fd) close(fd)++extern int gitfo_read(git_file fd, void *buf, size_t cnt);+extern int gitfo_write(git_file fd, void *buf, size_t cnt);+#define gitfo_lseek(f,n,w) lseek(f, n, w)+extern git_off_t gitfo_size(git_file fd);++extern int gitfo_read_file(gitfo_buf *obj, const char *path);+extern void gitfo_free_buf(gitfo_buf *obj);++/* Move (rename) a file; this operation is atomic */+extern int gitfo_mv(const char *from, const char *to);++/* Move a file (forced); this will create the destination+ * path if it doesn't exist */+extern int gitfo_mv_force(const char *from, const char *to);++#define gitfo_stat(p,b) stat(p, b)+#define gitfo_fstat(f,b) fstat(f, b)++#define gitfo_unlink(p) unlink(p)+#define gitfo_rmdir(p) rmdir(p)+#define gitfo_chdir(p) chdir(p)+#define gitfo_mkdir(p,m) mkdir(p, m)++#define gitfo_mkstemp(t) mkstemp(t)+#define gitfo_fsync(fd) fsync(fd)+#define gitfo_chmod(p,m) chmod(p, m)++/**+ * Read-only map all or part of a file into memory.+ * When possible this function should favor a virtual memory+ * style mapping over some form of malloc()+read(), as the+ * data access will be random and is not likely to touch the+ * majority of the region requested.+ *+ * @param out buffer to populate with the mapping information.+ * @param fd open descriptor to configure the mapping from.+ * @param begin first byte to map, this should be page aligned.+ * @param end number of bytes to map.+ * @return+ * - GIT_SUCCESS on success;+ * - GIT_EOSERR on an unspecified OS related error.+ */+extern int gitfo_map_ro(+ git_map *out,+ git_file fd,+ git_off_t begin,+ size_t len);++/**+ * Release the memory associated with a previous memory mapping.+ * @param map the mapping description previously configured.+ */+extern void gitfo_free_map(git_map *map);++/**+ * Walk each directory entry, except '.' and '..', calling fn(state).+ *+ * @param pathbuf buffer the function reads the initial directory+ * path from, and updates with each successive entry's name.+ * @param pathmax maximum allocation of pathbuf.+ * @param fn function to invoke with each entry. The first arg is+ * the input state and the second arg is pathbuf. The function+ * may modify the pathbuf, but only by appending new text.+ * @param state to pass to fn as the first arg.+ */+extern int gitfo_dirent(+ char *pathbuf,+ size_t pathmax,+ int (*fn)(void *, char *),+ void *state);++extern gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size);+extern int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len);+extern int gitfo_flush_cached(gitfo_cache *ioc);+extern int gitfo_close_cached(gitfo_cache *ioc);+++extern int gitfo_cmp_path(const char *name1, int len1, int isdir1,+ const char *name2, int len2, int isdir2);++/**+ * Clean up a provided absolute or relative directory path.+ * + * This prettification relies on basic operations such as coalescing + * multiple forward slashes into a single slash, removing '.' and + * './' current directory segments, and removing parent directory + * whenever '..' is encountered.+ *+ * If not empty, the returned path ends with a forward slash.+ *+ * For instance, this will turn "d1/s1///s2/..//../s3" into "d1/s3/".+ *+ * This only performs a string based analysis of the path.+ * No checks are done to make sure the path actually makes sense from + * the file system perspective.+ *+ * @param buffer_out buffer to populate with the normalized path.+ * @param path directory path to clean up.+ * @return+ * - GIT_SUCCESS on success;+ * - GIT_ERROR when the input path is invalid or escapes the current directory.+ */+GIT_EXTERN(int) gitfo_prettify_dir_path(char *buffer_out, const char *path);++/**+ * Clean up a provided absolute or relative file path.+ * + * This prettification relies on basic operations such as coalescing + * multiple forward slashes into a single slash, removing '.' and + * './' current directory segments, and removing parent directory + * whenever '..' is encountered.+ *+ * For instance, this will turn "d1/s1///s2/..//../s3" into "d1/s3".+ *+ * This only performs a string based analysis of the path.+ * No checks are done to make sure the path actually makes sense from + * the file system perspective.+ *+ * @param buffer_out buffer to populate with the normalized path.+ * @param path file path to clean up.+ * @return+ * - GIT_SUCCESS on success;+ * - GIT_ERROR when the input path is invalid or escapes the current directory.+ */+GIT_EXTERN(int) gitfo_prettify_file_path(char *buffer_out, const char *path);++#endif /* INCLUDE_fileops_h__ */
+ libgit2/src/hash.c view
@@ -0,0 +1,94 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "hash.h"++#if defined(PPC_SHA1)+# include "ppc/sha1.h"+#elif defined(OPENSSL_SHA1)+# include <openssl/sha.h>+#else+# include "block-sha1/sha1.h"+#endif++struct git_hash_ctx {+ SHA_CTX c;+};++git_hash_ctx *git_hash_new_ctx(void)+{+ git_hash_ctx *ctx = git__malloc(sizeof(*ctx));++ if (!ctx)+ return NULL;++ SHA1_Init(&ctx->c);++ return ctx;+}++void git_hash_free_ctx(git_hash_ctx *ctx)+{+ free(ctx);+}++void git_hash_init(git_hash_ctx *ctx)+{+ assert(ctx);+ SHA1_Init(&ctx->c);+}++void git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)+{+ assert(ctx);+ SHA1_Update(&ctx->c, data, len);+}++void git_hash_final(git_oid *out, git_hash_ctx *ctx)+{+ assert(ctx);+ SHA1_Final(out->id, &ctx->c);+}++void git_hash_buf(git_oid *out, const void *data, size_t len)+{+ SHA_CTX c;++ SHA1_Init(&c);+ SHA1_Update(&c, data, len);+ SHA1_Final(out->id, &c);+}++void git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n)+{+ SHA_CTX c;+ size_t i;++ SHA1_Init(&c);+ for (i = 0; i < n; i++)+ SHA1_Update(&c, vec[i].data, vec[i].len);+ SHA1_Final(out->id, &c);+}
+ libgit2/src/hash.h view
@@ -0,0 +1,26 @@+/*+ * hash.h+ */+#ifndef INCLUDE_hash_h__+#define INCLUDE_hash_h__++#include "git2/oid.h"++typedef struct git_hash_ctx git_hash_ctx;++typedef struct {+ void *data;+ size_t len;+} git_buf_vec;++git_hash_ctx *git_hash_new_ctx(void);+void git_hash_free_ctx(git_hash_ctx *ctx);++void git_hash_init(git_hash_ctx *c);+void git_hash_update(git_hash_ctx *c, const void *data, size_t len);+void git_hash_final(git_oid *out, git_hash_ctx *c);++void git_hash_buf(git_oid *out, const void *data, size_t len);+void git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n);++#endif /* INCLUDE_hash_h__ */
+ libgit2/src/hashtable.c view
@@ -0,0 +1,261 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "repository.h"+#include "commit.h"++#define MAX_LOOPS 5+static const double max_load_factor = 0.65;++static int resize_to(git_hashtable *self, size_t new_size);+static int set_size(git_hashtable *self, size_t new_size);+static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id);+static void node_swap_with(git_hashtable_node *self, git_hashtable_node *other);+static int node_insert(git_hashtable *self, git_hashtable_node *new_node);+static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size);++static int resize_to(git_hashtable *self, size_t new_size)+{+ git_hashtable_node *old_nodes = self->nodes;+ size_t old_size = self->size;++ self->is_resizing = 1;++ do {+ self->size = new_size;+ self->size_mask = new_size - 1;+ self->key_count = 0;+ self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size);++ if (self->nodes == NULL)+ return GIT_ENOMEM;++ if (insert_nodes(self, old_nodes, old_size) == 0)+ self->is_resizing = 0;+ else {+ new_size *= 2;+ free(self->nodes);+ }+ } while(self->is_resizing);++ free(old_nodes);+ return GIT_SUCCESS;+}++static int set_size(git_hashtable *self, size_t new_size)+{+ self->nodes = realloc(self->nodes, new_size * sizeof(git_hashtable_node));+ if (self->nodes == NULL)+ return GIT_ENOMEM;++ if (new_size > self->size) {+ memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(git_hashtable_node));+ }++ self->size = new_size;+ self->size_mask = new_size - 1;+ return GIT_SUCCESS;+}++static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id)+{+ size_t pos = self->hash(key, hash_id) & self->size_mask;+ return git_hashtable_node_at(self->nodes, pos);+}++static void node_swap_with(git_hashtable_node *self, git_hashtable_node *other)+{+ git_hashtable_node tmp = *self;+ *self = *other;+ *other = tmp;+}++static int node_insert(git_hashtable *self, git_hashtable_node *new_node)+{ + int iteration, hash_id;++ for (iteration = 0; iteration < MAX_LOOPS; iteration++) { + for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {+ git_hashtable_node *node;+ node = node_with_hash(self, new_node->key, hash_id);+ node_swap_with(new_node, node);+ if(new_node->key == 0x0){+ self->key_count++;+ return GIT_SUCCESS; + }+ }+ }++ if (self->is_resizing) + return GIT_EBUSY;++ resize_to(self, self->size * 2);+ git_hashtable_insert(self, new_node->key, new_node->value);+ return GIT_SUCCESS;+}++static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size)+{+ size_t i;++ for (i = 0; i < old_size; ++i) {+ git_hashtable_node *node = git_hashtable_node_at(old_nodes, i);+ if (node->key && git_hashtable_insert(self, node->key, node->value) < GIT_SUCCESS)+ return GIT_ENOMEM;+ }++ return GIT_SUCCESS;+}++git_hashtable *git_hashtable_alloc(size_t min_size, + git_hash_ptr hash,+ git_hash_keyeq_ptr key_eq)+{+ git_hashtable *table;++ assert(hash && key_eq);++ if ((table = git__malloc(sizeof(git_hashtable))) == NULL)+ return NULL;++ memset(table, 0x0, sizeof(git_hashtable));++ if (min_size < 8)+ min_size = 8;++ /* round up size to closest power of 2 */+ min_size--;+ min_size |= min_size >> 1;+ min_size |= min_size >> 2;+ min_size |= min_size >> 4;+ min_size |= min_size >> 8;+ min_size |= min_size >> 16;++ table->hash = hash;+ table->key_equal = key_eq;++ set_size(table, min_size + 1);++ return table;+}++void git_hashtable_clear(git_hashtable *self)+{+ assert(self);++ memset(self->nodes, 0x0, sizeof(git_hashtable_node) * self->size);+ self->key_count = 0;+}++void git_hashtable_free(git_hashtable *self)+{+ assert(self);++ free(self->nodes);+ free(self);+}+++int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, void **old_value)+{+ int hash_id;+ git_hashtable_node *node;++ assert(self && self->nodes);++ *old_value = NULL;++ for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {+ node = node_with_hash(self, key, hash_id);++ if (!node->key) {+ node->key = key;+ node->value = value;+ self->key_count++;+ return GIT_SUCCESS;+ }++ if (key == node->key || self->key_equal(key, node->key) == 0) {+ *old_value = node->value;+ node->key = key;+ node->value = value;+ return GIT_SUCCESS;+ }+ }++ /* no space in table; must do cuckoo dance */+ {+ git_hashtable_node x;+ x.key = key;+ x.value = value;+ return node_insert(self, &x);+ }+}++void *git_hashtable_lookup(git_hashtable *self, const void *key)+{+ int hash_id;+ git_hashtable_node *node;++ assert(self && self->nodes);++ for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {+ node = node_with_hash(self, key, hash_id);+ if (node->key && self->key_equal(key, node->key) == 0)+ return node->value;+ }++ return NULL;+}++int git_hashtable_remove(git_hashtable *self, const void *key)+{+ int hash_id;+ git_hashtable_node *node;++ assert(self && self->nodes);++ for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) {+ node = node_with_hash(self, key, hash_id);+ if (node->key && self->key_equal(key, node->key) == 0) {+ node->key = NULL;+ node->value = NULL;+ self->key_count--;+ return GIT_SUCCESS;+ }+ }++ return GIT_ENOTFOUND;+}++int git_hashtable_merge(git_hashtable *self, git_hashtable *other)+{+ if (resize_to(self, (self->size + other->size) * 2) < GIT_SUCCESS)+ return GIT_ENOMEM;++ return insert_nodes(self, other->nodes, other->key_count);+}+
+ libgit2/src/hashtable.h view
@@ -0,0 +1,73 @@+#ifndef INCLUDE_hashtable_h__+#define INCLUDE_hashtable_h__++#include "git2/common.h"+#include "git2/oid.h"+#include "git2/odb.h"++#define GIT_HASHTABLE_HASHES 3++typedef uint32_t (*git_hash_ptr)(const void *, int hash_id);+typedef int (*git_hash_keyeq_ptr)(const void *key_a, const void *key_b);++struct git_hashtable_node {+ const void *key;+ void *value;+};++struct git_hashtable {+ struct git_hashtable_node *nodes;++ size_t size_mask;+ size_t size;+ size_t key_count;++ int is_resizing;++ git_hash_ptr hash;+ git_hash_keyeq_ptr key_equal;+};++typedef struct git_hashtable_node git_hashtable_node;+typedef struct git_hashtable git_hashtable;++git_hashtable *git_hashtable_alloc(size_t min_size, + git_hash_ptr hash,+ git_hash_keyeq_ptr key_eq);+void *git_hashtable_lookup(git_hashtable *h, const void *key);+int git_hashtable_remove(git_hashtable *table, const void *key);+void git_hashtable_free(git_hashtable *h);+void git_hashtable_clear(git_hashtable *h);+int git_hashtable_merge(git_hashtable *self, git_hashtable *other);++int git_hashtable_insert2(git_hashtable *h, const void *key, void *value, void **old_value);++GIT_INLINE(int) git_hashtable_insert(git_hashtable *h, const void *key, void *value)+{+ void *_unused;+ return git_hashtable_insert2(h, key, value, &_unused);+}++#define git_hashtable_node_at(nodes, pos) ((git_hashtable_node *)(&nodes[pos]))++#define GIT_HASHTABLE_FOREACH(self, pkey, pvalue, code) {\+ git_hashtable *_self = (self);\+ git_hashtable_node *_nodes = _self->nodes;\+ unsigned int _i, _size = _self->size;\+ for (_i = 0; _i < _size; _i ++) {\+ git_hashtable_node *_node = git_hashtable_node_at(_nodes, _i);\+ if (_node->key)\+ {\+ pkey = _node->key;\+ pvalue = _node->value;\+ code;\+ }\+ }\+}++#define GIT_HASHTABLE_FOREACH_DELETE() {\+ _node->key = NULL; _node->value = NULL; _self->key_count--;\+}+++#endif
+ libgit2/src/index.c view
@@ -0,0 +1,768 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include <stddef.h>++#include "common.h"+#include "repository.h"+#include "index.h"+#include "hash.h"+#include "git2/odb.h"+#include "git2/blob.h"++#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)+#define short_entry_size(len) entry_size(struct entry_short, len)+#define long_entry_size(len) entry_size(struct entry_long, len)++#define minimal_entry_size (offsetof(struct entry_short, path))++static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;+static const size_t INDEX_HEADER_SIZE = 12;++static const unsigned int INDEX_VERSION_NUMBER = 2;+static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;++static const unsigned int INDEX_HEADER_SIG = 0x44495243;+static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};++struct index_header {+ uint32_t signature;+ uint32_t version;+ uint32_t entry_count;+};++struct index_extension {+ char signature[4];+ uint32_t extension_size;+};++struct entry_time {+ uint32_t seconds;+ uint32_t nanoseconds;+};++struct entry_short {+ struct entry_time ctime;+ struct entry_time mtime;+ uint32_t dev;+ uint32_t ino;+ uint32_t mode;+ uint32_t uid;+ uint32_t gid;+ uint32_t file_size;+ git_oid oid;+ uint16_t flags;+ char path[1]; /* arbritrary length */+};++struct entry_long {+ struct entry_time ctime;+ struct entry_time mtime;+ uint32_t dev;+ uint32_t ino;+ uint32_t mode;+ uint32_t uid;+ uint32_t gid;+ uint32_t file_size;+ git_oid oid;+ uint16_t flags;+ uint16_t flags_extended;+ char path[1]; /* arbritrary length */+};++/* local declarations */+static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);+static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size);+static int read_header(struct index_header *dest, const void *buffer);++static int read_tree(git_index *index, const char *buffer, size_t buffer_size);+static git_index_tree *read_tree_internal(const char **, const char *, git_index_tree *);++static int parse_index(git_index *index, const char *buffer, size_t buffer_size);+static void sort_index(git_index *index);+static int write_index(git_index *index, git_filebuf *file);++int index_srch(const void *key, const void *array_member)+{+ const char *filename = (const char *)key;+ const git_index_entry *entry = *(const git_index_entry **)(array_member);++ return strcmp(filename, entry->path);+}++int index_cmp(const void *a, const void *b)+{+ const git_index_entry *entry_a = *(const git_index_entry **)(a);+ const git_index_entry *entry_b = *(const git_index_entry **)(b);++ return strcmp(entry_a->path, entry_b->path);+}+++static int index_initialize(git_index **index_out, git_repository *owner, const char *index_path)+{+ git_index *index;++ assert(index_out && index_path);++ index = git__malloc(sizeof(git_index));+ if (index == NULL)+ return GIT_ENOMEM;++ memset(index, 0x0, sizeof(git_index));++ index->index_file_path = git__strdup(index_path);+ if (index->index_file_path == NULL) {+ free(index);+ return GIT_ENOMEM;+ }++ index->repository = owner;++ git_vector_init(&index->entries, 32, index_cmp);++ /* Check if index file is stored on disk already */+ if (gitfo_exists(index->index_file_path) == 0)+ index->on_disk = 1;++ *index_out = index;+ return GIT_SUCCESS;+}++int git_index_open_bare(git_index **index_out, const char *index_path)+{+ return index_initialize(index_out, NULL, index_path);+}++int git_index_open_inrepo(git_index **index_out, git_repository *repo)+{+ if (repo->is_bare)+ return GIT_EBAREINDEX;++ return index_initialize(index_out, repo, repo->path_index);+}++void git_index_free(git_index *index)+{+ if (index == NULL || index->repository != NULL)+ return;++ git_index_clear(index);+ git_vector_free(&index->entries);++ free(index->index_file_path);+ free(index);+}++static void free_tree(git_index_tree *tree)+{+ unsigned int i;++ if (tree == NULL)+ return;++ for (i = 0; i < tree->children_count; ++i)+ free_tree(tree->children[i]);++ free(tree->name);+ free(tree->children);+ free(tree);+}++void git_index_clear(git_index *index)+{+ unsigned int i;++ assert(index);++ for (i = 0; i < index->entries.length; ++i) {+ git_index_entry *e;+ e = git_vector_get(&index->entries, i);+ free(e->path);+ free(e);+ }++ git_vector_clear(&index->entries);+ index->last_modified = 0;++ free_tree(index->tree);+ index->tree = NULL;+}++int git_index_read(git_index *index)+{+ struct stat indexst;+ int error = GIT_SUCCESS;++ assert(index->index_file_path);++ if (!index->on_disk || gitfo_exists(index->index_file_path) < 0) {+ git_index_clear(index);+ index->on_disk = 0;+ return GIT_SUCCESS;+ }++ if (gitfo_stat(index->index_file_path, &indexst) < 0)+ return GIT_EOSERR;++ if (!S_ISREG(indexst.st_mode))+ return GIT_ENOTFOUND;++ if (indexst.st_mtime != index->last_modified) {++ gitfo_buf buffer;++ if (gitfo_read_file(&buffer, index->index_file_path) < GIT_SUCCESS)+ return GIT_EOSERR;++ git_index_clear(index);+ error = parse_index(index, buffer.data, buffer.len);++ if (error == GIT_SUCCESS)+ index->last_modified = indexst.st_mtime;++ gitfo_free_buf(&buffer);+ }++ return error;+}++int git_index_write(git_index *index)+{+ git_filebuf file;+ struct stat indexst;+ int error;++ sort_index(index);++ if ((error = git_filebuf_open(&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < GIT_SUCCESS)+ return error;++ if ((error = write_index(index, &file)) < GIT_SUCCESS) {+ git_filebuf_cleanup(&file);+ return error;+ }++ if ((error = git_filebuf_commit(&file)) < GIT_SUCCESS)+ return error;++ if (gitfo_stat(index->index_file_path, &indexst) == 0) {+ index->last_modified = indexst.st_mtime;+ index->on_disk = 1;+ }++ return GIT_SUCCESS;+}++unsigned int git_index_entrycount(git_index *index)+{+ assert(index);+ return index->entries.length;+}++git_index_entry *git_index_get(git_index *index, int n)+{+ assert(index);+ sort_index(index);+ return git_vector_get(&index->entries, (unsigned int)n);+}++int git_index_add(git_index *index, const char *rel_path, int stage)+{+ git_index_entry entry;+ char full_path[GIT_PATH_MAX];+ struct stat st;+ int error;++ if (index->repository == NULL)+ return GIT_EBAREINDEX;++ git__joinpath(full_path, index->repository->path_workdir, rel_path);++ if (gitfo_exists(full_path) < 0)+ return GIT_ENOTFOUND;++ if (gitfo_stat(full_path, &st) < 0)+ return GIT_EOSERR;++ if (stage < 0 || stage > 3)+ return GIT_ERROR;++ memset(&entry, 0x0, sizeof(git_index_entry));++ entry.ctime.seconds = st.st_ctime;+ entry.mtime.seconds = st.st_mtime;+ /* entry.mtime.nanoseconds = st.st_mtimensec; */+ /* entry.ctime.nanoseconds = st.st_ctimensec; */+ entry.dev= st.st_rdev;+ entry.ino = st.st_ino;+ entry.mode = st.st_mode;+ entry.uid = st.st_uid;+ entry.gid = st.st_gid;+ entry.file_size = st.st_size;++ /* write the blob to disk and get the oid */+ if ((error = git_blob_writefile(&entry.oid, index->repository, full_path)) < GIT_SUCCESS)+ return error;++ entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT);+ entry.path = (char *)rel_path; /* do not duplicate; index_insert already does this */++ return git_index_insert(index, &entry);+}++void sort_index(git_index *index)+{+ git_vector_sort(&index->entries);+}++int git_index_insert(git_index *index, const git_index_entry *source_entry)+{+ git_index_entry *entry;+ size_t path_length;+ int position;++ assert(index && source_entry);++ if (source_entry->path == NULL)+ return GIT_EMISSINGOBJDATA;++ entry = git__malloc(sizeof(git_index_entry));+ if (entry == NULL)+ return GIT_ENOMEM;++ memcpy(entry, source_entry, sizeof(git_index_entry));++ /* duplicate the path string so we own it */+ entry->path = git__strdup(entry->path);+ if (entry->path == NULL)+ return GIT_ENOMEM;++ /* make sure that the path length flag is correct */+ path_length = strlen(entry->path);++ entry->flags &= ~GIT_IDXENTRY_NAMEMASK;++ if (path_length < GIT_IDXENTRY_NAMEMASK)+ entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK;+ else+ entry->flags |= GIT_IDXENTRY_NAMEMASK;;+++ /* look if an entry with this path already exists */+ position = git_index_find(index, source_entry->path);++ /* if no entry exists, add the entry at the end;+ * the index is no longer sorted */+ if (position == GIT_ENOTFOUND) {+ if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS)+ return GIT_ENOMEM;++ /* if a previous entry exists, replace it */+ } else {+ git_index_entry **entry_array = (git_index_entry **)index->entries.contents;++ free(entry_array[position]->path);+ free(entry_array[position]);++ entry_array[position] = entry;+ }++ return GIT_SUCCESS;+}++int git_index_remove(git_index *index, int position)+{+ assert(index);+ sort_index(index);+ return git_vector_remove(&index->entries, (unsigned int)position);+}++int git_index_find(git_index *index, const char *path)+{+ sort_index(index);+ return git_vector_bsearch2(&index->entries, index_srch, path);+}++static git_index_tree *read_tree_internal(+ const char **buffer_in, const char *buffer_end, git_index_tree *parent)+{+ git_index_tree *tree;+ const char *name_start, *buffer;++ if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)+ return NULL;++ memset(tree, 0x0, sizeof(git_index_tree));+ tree->parent = parent;++ buffer = name_start = *buffer_in;++ if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL)+ goto error_cleanup;++ /* NUL-terminated tree name */+ tree->name = git__strdup(name_start);+ if (++buffer >= buffer_end)+ goto error_cleanup;++ /* Blank-terminated ASCII decimal number of entries in this tree */+ tree->entries = strtol(buffer, (char **)&buffer, 10);+ if (*buffer != ' ' || ++buffer >= buffer_end)+ goto error_cleanup;++ /* Number of children of the tree, newline-terminated */+ tree->children_count = strtol(buffer, (char **)&buffer, 10);+ if (*buffer != '\n' || ++buffer >= buffer_end)+ goto error_cleanup;++ /* 160-bit SHA-1 for this tree and it's children */+ if (buffer + GIT_OID_RAWSZ > buffer_end)+ goto error_cleanup;++ git_oid_mkraw(&tree->oid, (const unsigned char *)buffer);+ buffer += GIT_OID_RAWSZ;++ /* Parse children: */+ if (tree->children_count > 0) {+ unsigned int i;++ tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *));+ if (tree->children == NULL)+ goto error_cleanup;++ for (i = 0; i < tree->children_count; ++i) {+ tree->children[i] = read_tree_internal(&buffer, buffer_end, tree);++ if (tree->children[i] == NULL)+ goto error_cleanup;+ }+ }++ *buffer_in = buffer;+ return tree;++error_cleanup:+ free_tree(tree);+ return NULL;+}++static int read_tree(git_index *index, const char *buffer, size_t buffer_size)+{+ const char *buffer_end = buffer + buffer_size;++ index->tree = read_tree_internal(&buffer, buffer_end, NULL);+ return (index->tree != NULL && buffer == buffer_end) ? GIT_SUCCESS : GIT_EOBJCORRUPTED;+}++static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size)+{+ size_t path_length, entry_size;+ uint16_t flags_raw;+ const char *path_ptr;+ const struct entry_short *source;++ if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)+ return 0;++ memset(dest, 0x0, sizeof(git_index_entry));++ source = (const struct entry_short *)(buffer);++ dest->ctime.seconds = (time_t)ntohl(source->ctime.seconds);+ dest->ctime.nanoseconds = (time_t)ntohl(source->ctime.nanoseconds);+ dest->mtime.seconds = (time_t)ntohl(source->mtime.seconds);+ dest->mtime.nanoseconds = (time_t)ntohl(source->mtime.nanoseconds);+ dest->dev = ntohl(source->dev);+ dest->ino = ntohl(source->ino);+ dest->mode = ntohl(source->mode);+ dest->uid = ntohl(source->uid);+ dest->gid = ntohl(source->gid);+ dest->file_size = ntohl(source->file_size);+ git_oid_cpy(&dest->oid, &source->oid);+ dest->flags = ntohs(source->flags);++ if (dest->flags & GIT_IDXENTRY_EXTENDED) {+ struct entry_long *source_l = (struct entry_long *)source;+ path_ptr = source_l->path;++ flags_raw = ntohs(source_l->flags_extended);+ memcpy(&dest->flags_extended, &flags_raw, 2);+ } else+ path_ptr = source->path;++ path_length = dest->flags & GIT_IDXENTRY_NAMEMASK;++ /* if this is a very long string, we must find its+ * real length without overflowing */+ if (path_length == 0xFFF) {+ const char *path_end;++ path_end = memchr(path_ptr, '\0', buffer_size);+ if (path_end == NULL)+ return 0;++ path_length = path_end - path_ptr;+ }++ if (dest->flags & GIT_IDXENTRY_EXTENDED)+ entry_size = long_entry_size(path_length);+ else+ entry_size = short_entry_size(path_length);++ if (INDEX_FOOTER_SIZE + entry_size > buffer_size)+ return 0;++ dest->path = git__strdup(path_ptr);+ assert(dest->path);++ return entry_size;+}++static int read_header(struct index_header *dest, const void *buffer)+{+ const struct index_header *source;+ source = (const struct index_header *)(buffer);++ dest->signature = ntohl(source->signature);+ if (dest->signature != INDEX_HEADER_SIG)+ return GIT_EOBJCORRUPTED;++ dest->version = ntohl(source->version);+ if (dest->version != INDEX_VERSION_NUMBER_EXT &&+ dest->version != INDEX_VERSION_NUMBER)+ return GIT_EOBJCORRUPTED;++ dest->entry_count = ntohl(source->entry_count);+ return GIT_SUCCESS;+}++static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size)+{+ const struct index_extension *source;+ struct index_extension dest;+ size_t total_size;++ source = (const struct index_extension *)(buffer);++ memcpy(dest.signature, source->signature, 4);+ dest.extension_size = ntohl(source->extension_size);++ total_size = dest.extension_size + sizeof(struct index_extension);++ if (buffer_size - total_size < INDEX_FOOTER_SIZE)+ return 0;++ /* optional extension */+ if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {+ /* tree cache */+ if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {++ if (read_tree(index, buffer + 8, dest.extension_size) < GIT_SUCCESS)+ return 0;+ }+ } else {+ /* we cannot handle non-ignorable extensions;+ * in fact they aren't even defined in the standard */+ return 0;+ }++ return total_size;+}++static int parse_index(git_index *index, const char *buffer, size_t buffer_size)+{+ unsigned int i;+ struct index_header header;+ git_oid checksum_calculated, checksum_expected;++#define seek_forward(_increase) { \+ if (_increase >= buffer_size) \+ return GIT_EOBJCORRUPTED; \+ buffer += _increase; \+ buffer_size -= _increase;\+}++ if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE)+ return GIT_EOBJCORRUPTED;++ /* Precalculate the SHA1 of the files's contents -- we'll match it to+ * the provided SHA1 in the footer */+ git_hash_buf(&checksum_calculated, (const void *)buffer, buffer_size - INDEX_FOOTER_SIZE);++ /* Parse header */+ if (read_header(&header, buffer) < GIT_SUCCESS)+ return GIT_EOBJCORRUPTED;++ seek_forward(INDEX_HEADER_SIZE);++ git_vector_clear(&index->entries);++ /* Parse all the entries */+ for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {+ size_t entry_size;+ git_index_entry *entry;++ entry = git__malloc(sizeof(git_index_entry));+ if (entry == NULL)+ return GIT_ENOMEM;++ entry_size = read_entry(entry, buffer, buffer_size);++ /* 0 bytes read means an object corruption */+ if (entry_size == 0)+ return GIT_EOBJCORRUPTED;++ if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS)+ return GIT_ENOMEM;++ seek_forward(entry_size);+ }++ if (i != header.entry_count)+ return GIT_EOBJCORRUPTED;++ /* There's still space for some extensions! */+ while (buffer_size > INDEX_FOOTER_SIZE) {+ size_t extension_size;++ extension_size = read_extension(index, buffer, buffer_size);++ /* see if we have read any bytes from the extension */+ if (extension_size == 0)+ return GIT_EOBJCORRUPTED;++ seek_forward(extension_size);+ }++ if (buffer_size != INDEX_FOOTER_SIZE)+ return GIT_EOBJCORRUPTED;++ /* 160-bit SHA-1 over the content of the index file before this checksum. */+ git_oid_mkraw(&checksum_expected, (const unsigned char *)buffer);++ if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0)+ return GIT_EOBJCORRUPTED;++#undef seek_forward++ /* force sorting in the vector: the entries are+ * assured to be sorted on the index */+ index->entries.sorted = 1;+ return GIT_SUCCESS;+}++static int write_disk_entry(git_filebuf *file, git_index_entry *entry)+{+ struct entry_short *ondisk;+ size_t path_len, disk_size;+ char *path;++ path_len = strlen(entry->path);++ if (entry->flags & GIT_IDXENTRY_EXTENDED)+ disk_size = long_entry_size(path_len);+ else+ disk_size = short_entry_size(path_len);++ if (git_filebuf_reserve(file, (void **)&ondisk, disk_size) < GIT_SUCCESS)+ return GIT_ENOMEM;++ memset(ondisk, 0x0, disk_size);++ ondisk->ctime.seconds = htonl((unsigned long)entry->ctime.seconds);+ ondisk->mtime.seconds = htonl((unsigned long)entry->mtime.seconds);+ ondisk->ctime.nanoseconds = htonl(entry->ctime.nanoseconds);+ ondisk->mtime.nanoseconds = htonl(entry->mtime.nanoseconds);+ ondisk->dev = htonl(entry->dev);+ ondisk->ino = htonl(entry->ino);+ ondisk->mode = htonl(entry->mode);+ ondisk->uid = htonl(entry->uid);+ ondisk->gid = htonl(entry->gid);+ ondisk->file_size = htonl((unsigned long)entry->file_size);++ git_oid_cpy(&ondisk->oid, &entry->oid);++ ondisk->flags = htons(entry->flags);++ if (entry->flags & GIT_IDXENTRY_EXTENDED) {+ struct entry_long *ondisk_ext;+ ondisk_ext = (struct entry_long *)ondisk;+ ondisk_ext->flags_extended = htons(entry->flags_extended);+ path = ondisk_ext->path;+ }+ else+ path = ondisk->path;++ memcpy(path, entry->path, path_len);++ return GIT_SUCCESS;+}++static int write_entries(git_index *index, git_filebuf *file)+{+ unsigned int i;++ for (i = 0; i < index->entries.length; ++i) {+ git_index_entry *entry;+ entry = git_vector_get(&index->entries, i);+ if (write_disk_entry(file, entry) < GIT_SUCCESS)+ return GIT_ENOMEM;+ }++ return GIT_SUCCESS;+}++static int write_index(git_index *index, git_filebuf *file)+{+ int error = GIT_SUCCESS;+ git_oid hash_final;++ struct index_header header;++ int is_extended = 1;++ assert(index && file);++ header.signature = htonl(INDEX_HEADER_SIG);+ header.version = htonl(is_extended ? INDEX_VERSION_NUMBER : INDEX_VERSION_NUMBER_EXT);+ header.entry_count = htonl(index->entries.length);++ git_filebuf_write(file, &header, sizeof(struct index_header));++ error = write_entries(index, file);+ if (error < GIT_SUCCESS)+ return error;++ /* TODO: write extensions (tree cache) */++ /* get out the hash for all the contents we've appended to the file */+ git_filebuf_hash(&hash_final, file);++ /* write it at the end of the file */+ git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ);++ return error;+}
+ libgit2/src/index.h view
@@ -0,0 +1,34 @@+#ifndef INCLUDE_index_h__+#define INCLUDE_index_h__++#include "fileops.h"+#include "filebuf.h"+#include "vector.h"+#include "git2/odb.h"+#include "git2/index.h"++struct git_index_tree {+ char *name;++ struct git_index_tree *parent;+ struct git_index_tree **children;+ size_t children_count;++ size_t entries;+ git_oid oid;+};++typedef struct git_index_tree git_index_tree;++struct git_index {+ git_repository *repository;+ char *index_file_path;++ time_t last_modified;+ git_vector entries;++ unsigned int on_disk:1;+ git_index_tree *tree;+};++#endif
+ libgit2/src/map.h view
@@ -0,0 +1,31 @@+#ifndef INCLUDE_map_h__+#define INCLUDE_map_h__++#include "common.h"+++/* git__mmap() prot values */+#define GIT_PROT_NONE 0x0+#define GIT_PROT_READ 0x1+#define GIT_PROT_WRITE 0x2+#define GIT_PROT_EXEC 0x4++/* git__mmmap() flags values */+#define GIT_MAP_FILE 0+#define GIT_MAP_SHARED 1+#define GIT_MAP_PRIVATE 2+#define GIT_MAP_TYPE 0xf+#define GIT_MAP_FIXED 0x10++typedef struct { /* memory mapped buffer */+ void *data; /* data bytes */+ size_t len; /* data length */+#ifdef GIT_WIN32+ HANDLE fmh; /* file mapping handle */+#endif+} git_map;++extern int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);+extern int git__munmap(git_map *map);++#endif /* INCLUDE_map_h__ */
+ libgit2/src/mingw-compat.h view
@@ -0,0 +1,13 @@+#ifndef INCLUDE_mingw_compat__+#define INCLUDE_mingw_compat__++#if defined(__MINGW32__)++/* use a 64-bit file offset type */+# define lseek _lseeki64+# define stat _stati64+# define fstat _fstati64++#endif++#endif /* INCLUDE_mingw_compat__ */
+ libgit2/src/msvc-compat.h view
@@ -0,0 +1,42 @@+#ifndef INCLUDE_msvc_compat__+#define INCLUDE_msvc_compat__++#if defined(_MSC_VER)++/* access() mode parameter #defines */+# define F_OK 0 /* existence check */+# define W_OK 2 /* write mode check */+# define R_OK 4 /* read mode check */++# define lseek _lseeki64+# define stat _stat64+# define fstat _fstat64++/* stat: file mode type testing macros */+# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)+# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)+# define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO)++#if (_MSC_VER >= 1600)+# include <stdint.h>+#else+/* add some missing <stdint.h> typedef's */+typedef signed char int8_t;+typedef unsigned char uint8_t;++typedef short int16_t;+typedef unsigned short uint16_t;++typedef long int32_t;+typedef unsigned long uint32_t;++typedef long long int64_t;+typedef unsigned long long uint64_t;++typedef long long intmax_t;+typedef unsigned long long uintmax_t;+#endif++#endif++#endif /* INCLUDE_msvc_compat__ */
+ libgit2/src/object.c view
@@ -0,0 +1,487 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#include <stdarg.h>++#include "git2/object.h"++#include "common.h"+#include "repository.h"++#include "commit.h"+#include "tree.h"+#include "blob.h"+#include "tag.h"++static const int OBJECT_BASE_SIZE = 4096;++static struct {+ const char *str; /* type name string */+ int loose; /* valid loose object type flag */+ size_t size; /* size in bytes of the object structure */+} git_objects_table[] = {+ /* 0 = GIT_OBJ__EXT1 */+ { "", 0, 0},++ /* 1 = GIT_OBJ_COMMIT */+ { "commit", 1, sizeof(struct git_commit)},++ /* 2 = GIT_OBJ_TREE */+ { "tree", 1, sizeof(struct git_tree) },++ /* 3 = GIT_OBJ_BLOB */+ { "blob", 1, sizeof(struct git_blob) },++ /* 4 = GIT_OBJ_TAG */+ { "tag", 1, sizeof(struct git_tag) },++ /* 5 = GIT_OBJ__EXT2 */+ { "", 0, 0 },++ /* 6 = GIT_OBJ_OFS_DELTA */+ { "OFS_DELTA", 0, 0 },++ /* 7 = GIT_OBJ_REF_DELTA */+ { "REF_DELTA", 0, 0 }+};++/*+ * Object source methods+ *+ * Abstract buffer methods that allow the writeback system+ * to prepare the contents of any git file in-memory before+ * writing them to disk.+ */+static int source_resize(git_odb_source *src)+{+ size_t write_offset, new_size;+ void *new_data;++ write_offset = (size_t)((char *)src->write_ptr - (char *)src->raw.data);++ new_size = src->raw.len * 2;+ if ((new_data = git__malloc(new_size)) == NULL)+ return GIT_ENOMEM;++ memcpy(new_data, src->raw.data, src->written_bytes);+ free(src->raw.data);++ src->raw.data = new_data;+ src->raw.len = new_size;+ src->write_ptr = (char *)new_data + write_offset;++ return GIT_SUCCESS;+}++int git__source_printf(git_odb_source *source, const char *format, ...)+{+ va_list arglist;+ int len;++ assert(source->open && source->write_ptr);++ va_start(arglist, format);++ len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);++ while (source->written_bytes + len >= source->raw.len) {+ if (source_resize(source) < GIT_SUCCESS)+ return GIT_ENOMEM;++ len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);+ }++ source->write_ptr = (char *)source->write_ptr + len;+ source->written_bytes += len;++ return GIT_SUCCESS;+}++int git__source_write(git_odb_source *source, const void *bytes, size_t len)+{+ assert(source);++ assert(source->open && source->write_ptr);++ while (source->written_bytes + len >= source->raw.len) {+ if (source_resize(source) < GIT_SUCCESS)+ return GIT_ENOMEM;+ }++ memcpy(source->write_ptr, bytes, len);+ source->write_ptr = (char *)source->write_ptr + len;+ source->written_bytes += len;++ return GIT_SUCCESS;+}++static void prepare_write(git_object *object)+{+ if (object->source.write_ptr != NULL || object->source.open)+ git_object__source_close(object);++ /* TODO: proper size calculation */+ object->source.raw.data = git__malloc(OBJECT_BASE_SIZE);+ object->source.raw.len = OBJECT_BASE_SIZE;++ object->source.write_ptr = object->source.raw.data;+ object->source.written_bytes = 0;++ object->source.open = 1;+}++static int write_back(git_object *object)+{+ int error;+ git_oid new_id;++ assert(object);++ assert(object->source.open);+ assert(object->modified);++ object->source.raw.len = object->source.written_bytes;++ if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < GIT_SUCCESS)+ return error;++ if (object->in_memory) {+ int idx = git_vector_search(&object->repo->memory_objects, object);+ git_vector_remove(&object->repo->memory_objects, idx);+ } else {+ git_hashtable_remove(object->repo->objects, &object->id);+ }++ git_oid_cpy(&object->id, &new_id);+ git_hashtable_insert(object->repo->objects, &object->id, object);++ object->source.write_ptr = NULL;+ object->source.written_bytes = 0;++ object->modified = 0;+ object->in_memory = 0;++ git_object__source_close(object);+ return GIT_SUCCESS;+}++int git_object__source_open(git_object *object)+{+ int error;++ assert(object && !object->in_memory);++ if (object->source.open)+ git_object__source_close(object);++ error = git_odb_read(&object->source.raw, object->repo->db, &object->id);+ if (error < GIT_SUCCESS)+ return error;++ object->source.open = 1;+ return GIT_SUCCESS;+}++void git_object__source_close(git_object *object)+{+ assert(object);++ if (object->source.open) {+ git_rawobj_close(&object->source.raw);+ object->source.open = 0;+ }+}++static int create_object(git_object **object_out, git_otype type)+{+ git_object *object = NULL;++ assert(object_out);++ *object_out = NULL;++ switch (type) {+ case GIT_OBJ_COMMIT:+ case GIT_OBJ_TAG:+ case GIT_OBJ_BLOB:+ object = git__malloc(git_object__size(type));+ if (object == NULL)+ return GIT_ENOMEM;+ memset(object, 0x0, git_object__size(type));+ break;+ + case GIT_OBJ_TREE:+ object = (git_object *)git_tree__new();+ if (object == NULL)+ return GIT_ENOMEM;+ break;++ default:+ return GIT_EINVALIDTYPE;+ }++ *object_out = object;+ return GIT_SUCCESS;+}++int git_object_new(git_object **object_out, git_repository *repo, git_otype type)+{+ git_object *object = NULL;+ int error;++ assert(object_out && repo);++ if ((error = create_object(&object, type)) < GIT_SUCCESS)+ return error;++ object->repo = repo;+ object->in_memory = 1;+ object->modified = 1;++ object->source.raw.type = type;++ object->lru = ++repo->lru_counter;+ *object_out = object;+ return GIT_SUCCESS;+}++int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)+{+ git_object *object = NULL;+ git_rawobj obj_file;+ int error = GIT_SUCCESS;++ assert(repo && object_out && id);++ object = git_hashtable_lookup(repo->objects, id);+ if (object != NULL) {+ if (type != GIT_OBJ_ANY && type != object->source.raw.type)+ return GIT_EINVALIDTYPE;++ *object_out = object;+ object->lru = ++repo->lru_counter;+ object->can_free = 0;+ return GIT_SUCCESS;+ }++ error = git_odb_read(&obj_file, repo->db, id);+ if (error < GIT_SUCCESS)+ return error;++ if (type != GIT_OBJ_ANY && type != obj_file.type) {+ git_rawobj_close(&obj_file);+ return GIT_EINVALIDTYPE;+ }++ type = obj_file.type;++ if ((error = create_object(&object, type)) < GIT_SUCCESS)+ return error;++ /* Initialize parent object */+ git_oid_cpy(&object->id, id);+ object->repo = repo;+ memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));+ object->source.open = 1;++ switch (type) {+ case GIT_OBJ_COMMIT:+ error = git_commit__parse((git_commit *)object);+ break;++ case GIT_OBJ_TREE:+ error = git_tree__parse((git_tree *)object);+ break;++ case GIT_OBJ_TAG:+ error = git_tag__parse((git_tag *)object);+ break;++ case GIT_OBJ_BLOB:+ error = git_blob__parse((git_blob *)object);+ break;++ default:+ break;+ }++ if (error < GIT_SUCCESS) {+ git_object__free(object);+ return error;+ }++ git_object__source_close(object);+ git_hashtable_insert(repo->objects, &object->id, object);++ object->lru = ++repo->lru_counter;+ *object_out = object;+ return GIT_SUCCESS;+}++int git_object_write(git_object *object)+{+ int error;+ git_odb_source *source;++ assert(object);++ if (object->modified == 0)+ return GIT_SUCCESS;++ prepare_write(object);+ source = &object->source;++ switch (source->raw.type) {+ case GIT_OBJ_COMMIT:+ error = git_commit__writeback((git_commit *)object, source);+ break;++ case GIT_OBJ_TREE:+ error = git_tree__writeback((git_tree *)object, source);+ break;++ case GIT_OBJ_TAG:+ error = git_tag__writeback((git_tag *)object, source);+ break;++ case GIT_OBJ_BLOB:+ error = git_blob__writeback((git_blob *)object, source);+ break;++ default:+ error = GIT_ERROR;+ break;+ }++ if (error < GIT_SUCCESS) {+ git_object__source_close(object);+ return error;+ }++ return write_back(object);+}++void git_object__free(git_object *object)+{+ assert(object);++ git_object__source_close(object);++ switch (object->source.raw.type) {+ case GIT_OBJ_COMMIT:+ git_commit__free((git_commit *)object);+ break;++ case GIT_OBJ_TREE:+ git_tree__free((git_tree *)object);+ break;++ case GIT_OBJ_TAG:+ git_tag__free((git_tag *)object);+ break;++ case GIT_OBJ_BLOB:+ git_blob__free((git_blob *)object);+ break;++ default:+ free(object);+ break;+ }+}++void git_object_close(git_object *object)+{+ if (object == NULL)+ return;++ if (object->in_memory) {+ int idx = git_vector_search(&object->repo->memory_objects, object);+ git_vector_remove(&object->repo->memory_objects, idx);+ git_object__free(object);+ } else {+ object->can_free = 1;+ }+}++const git_oid *git_object_id(const git_object *obj)+{+ assert(obj);++ if (obj->in_memory)+ return NULL;++ return &obj->id;+}++git_otype git_object_type(const git_object *obj)+{+ assert(obj);+ return obj->source.raw.type;+}++git_repository *git_object_owner(const git_object *obj)+{+ assert(obj);+ return obj->repo;+}++const char *git_object_type2string(git_otype type)+{+ if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))+ return "";++ return git_objects_table[type].str;+}++git_otype git_object_string2type(const char *str)+{+ size_t i;++ if (!str || !*str)+ return GIT_OBJ_BAD;++ for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)+ if (!strcmp(str, git_objects_table[i].str))+ return (git_otype)i;++ return GIT_OBJ_BAD;+}++int git_object_typeisloose(git_otype type)+{+ if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))+ return 0;++ return git_objects_table[type].loose;+}++size_t git_object__size(git_otype type)+{+ if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))+ return 0;++ return git_objects_table[type].size;+}+
+ libgit2/src/odb.c view
@@ -0,0 +1,396 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "git2/zlib.h"+#include "git2/object.h"+#include "fileops.h"+#include "hash.h"+#include "odb.h"+#include "delta-apply.h"++#include "git2/odb_backend.h"++#define GIT_ALTERNATES_FILE "info/alternates"++/* TODO: is this correct? */+#define GIT_LOOSE_PRIORITY 2+#define GIT_PACKED_PRIORITY 1++typedef struct+{+ git_odb_backend *backend;+ int priority;+ int is_alternate;+} backend_internal;++static int format_object_header(char *hdr, size_t n, git_rawobj *obj)+{+ const char *type_str = git_object_type2string(obj->type);+ int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj->len);++ assert(len > 0); /* otherwise snprintf() is broken */+ assert(((size_t) len) < n); /* otherwise the caller is broken! */++ if (len < 0 || ((size_t) len) >= n)+ return GIT_ERROR;+ return len+1;+}++int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *obj)+{+ git_buf_vec vec[2];+ int hdrlen;++ assert(id && hdr && len && obj);++ if (!git_object_typeisloose(obj->type))+ return GIT_ERROR;++ if (!obj->data && obj->len != 0)+ return GIT_ERROR;++ if ((hdrlen = format_object_header(hdr, n, obj)) < 0)+ return GIT_ERROR;++ *len = hdrlen;++ vec[0].data = hdr;+ vec[0].len = hdrlen;+ vec[1].data = obj->data;+ vec[1].len = obj->len;++ git_hash_vec(id, vec, 2);++ return GIT_SUCCESS;+}++void git_rawobj_close(git_rawobj *obj)+{+ free(obj->data);+ obj->data = NULL;+}++int git_rawobj_hash(git_oid *id, git_rawobj *obj)+{+ char hdr[64];+ int hdrlen;++ assert(id && obj);++ return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj);+}++int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)+{+ z_stream zs;+ int status = Z_OK;++ memset(&zs, 0x0, sizeof(zs));++ zs.next_out = out;+ zs.avail_out = outlen;++ zs.next_in = in;+ zs.avail_in = inlen;++ if (inflateInit(&zs) < Z_OK)+ return GIT_ERROR;++ while (status == Z_OK)+ status = inflate(&zs, Z_FINISH);++ inflateEnd(&zs);++ if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)+ return GIT_ERROR;++ if (zs.total_out != outlen)+ return GIT_ERROR;++ return GIT_SUCCESS;+}++++++/***********************************************************+ *+ * OBJECT DATABASE PUBLIC API+ *+ * Public calls for the ODB functionality+ *+ ***********************************************************/++int backend_sort_cmp(const void *a, const void *b)+{+ const backend_internal *backend_a = *(const backend_internal **)(a);+ const backend_internal *backend_b = *(const backend_internal **)(b);++ if (backend_a->is_alternate == backend_b->is_alternate)+ return (backend_b->priority - backend_a->priority);++ return backend_a->is_alternate ? 1 : -1;+}++int git_odb_new(git_odb **out)+{+ git_odb *db = git__calloc(1, sizeof(*db));+ if (!db)+ return GIT_ENOMEM;++ if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {+ free(db);+ return GIT_ENOMEM;+ }++ *out = db;+ return GIT_SUCCESS;+}++static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int priority, int is_alternate)+{+ backend_internal *internal;++ assert(odb && backend);++ if (backend->odb != NULL && backend->odb != odb)+ return GIT_EBUSY;++ internal = git__malloc(sizeof(backend_internal));+ if (internal == NULL)+ return GIT_ENOMEM;++ internal->backend = backend;+ internal->priority = priority;+ internal->is_alternate = is_alternate;++ if (git_vector_insert(&odb->backends, internal) < 0) {+ free(internal);+ return GIT_ENOMEM;+ }++ git_vector_sort(&odb->backends);+ internal->backend->odb = odb;+ return GIT_SUCCESS;+}++int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)+{+ return add_backend_internal(odb, backend, priority, 0);+}++int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)+{+ return add_backend_internal(odb, backend, priority, 1);+}++static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates)+{+ git_odb_backend *loose, *packed;+ int error;++ /* add the loose object backend */+ error = git_odb_backend_loose(&loose, objects_dir);+ if (error < GIT_SUCCESS)+ return error;++ error = add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates);+ if (error < GIT_SUCCESS)+ return error;++ /* add the packed file backend */+ error = git_odb_backend_pack(&packed, objects_dir);+ if (error < GIT_SUCCESS)+ return error;++ error = add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates);+ if (error < GIT_SUCCESS)+ return error;++ return GIT_SUCCESS;+}++static int load_alternates(git_odb *odb, const char *objects_dir)+{+ char alternates_path[GIT_PATH_MAX];+ char alternate[GIT_PATH_MAX];+ char *buffer;++ gitfo_buf alternates_buf = GITFO_BUF_INIT;+ int error;++ git__joinpath(alternates_path, objects_dir, GIT_ALTERNATES_FILE);++ if (gitfo_exists(alternates_path) < GIT_SUCCESS)+ return GIT_SUCCESS;++ if (gitfo_read_file(&alternates_buf, alternates_path) < GIT_SUCCESS)+ return GIT_EOSERR;++ buffer = (char *)alternates_buf.data;+ error = GIT_SUCCESS;++ /* add each alternate as a new backend; one alternate per line */+ while ((error == GIT_SUCCESS) && (buffer = git__strtok(alternate, buffer, "\r\n")) != NULL)+ error = add_default_backends(odb, alternate, 1);++ gitfo_free_buf(&alternates_buf);+ return error;+}++int git_odb_open(git_odb **out, const char *objects_dir)+{+ git_odb *db;+ int error;++ assert(out && objects_dir);++ *out = NULL;++ if ((error = git_odb_new(&db)) < 0)+ return error;++ if ((error = add_default_backends(db, objects_dir, 0)) < GIT_SUCCESS)+ goto cleanup;++ if ((error = load_alternates(db, objects_dir)) < GIT_SUCCESS)+ goto cleanup;++ *out = db;+ return GIT_SUCCESS;++cleanup:+ git_odb_close(db);+ return error;+}++void git_odb_close(git_odb *db)+{+ unsigned int i;++ if (db == NULL)+ return;++ for (i = 0; i < db->backends.length; ++i) {+ backend_internal *internal = git_vector_get(&db->backends, i);+ git_odb_backend *backend = internal->backend;++ if (backend->free) backend->free(backend);+ else free(backend);++ free(internal);+ }++ git_vector_free(&db->backends);+ free(db);+}++int git_odb_exists(git_odb *db, const git_oid *id)+{+ unsigned int i;+ int found = 0;++ assert(db && id);++ for (i = 0; i < db->backends.length && !found; ++i) {+ backend_internal *internal = git_vector_get(&db->backends, i);+ git_odb_backend *b = internal->backend;++ if (b->exists != NULL)+ found = b->exists(b, id);+ }++ return found;+}++int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)+{+ unsigned int i;+ int error = GIT_ENOTFOUND;++ assert(out && db && id);++ for (i = 0; i < db->backends.length && error < 0; ++i) {+ backend_internal *internal = git_vector_get(&db->backends, i);+ git_odb_backend *b = internal->backend;++ if (b->read_header != NULL)+ error = b->read_header(out, b, id);+ }++ /*+ * no backend could read only the header.+ * try reading the whole object and freeing the contents+ */+ if (error < 0) {+ error = git_odb_read(out, db, id);+ git_rawobj_close(out);+ }++ return error;+}++int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id)+{+ unsigned int i;+ int error = GIT_ENOTFOUND;++ assert(out && db && id);++ for (i = 0; i < db->backends.length && error < 0; ++i) {+ backend_internal *internal = git_vector_get(&db->backends, i);+ git_odb_backend *b = internal->backend;++ if (b->read != NULL)+ error = b->read(out, b, id);+ }++ return error;+}++int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)+{+ unsigned int i;+ int error = GIT_ERROR;++ assert(obj && db && id);++ for (i = 0; i < db->backends.length && error < 0; ++i) {+ backend_internal *internal = git_vector_get(&db->backends, i);+ git_odb_backend *b = internal->backend;++ /* we don't write in alternates! */+ if (internal->is_alternate)+ continue;++ if (b->write != NULL)+ error = b->write(id, b, obj);+ }++ return error;+}+
+ libgit2/src/odb.h view
@@ -0,0 +1,17 @@+#ifndef INCLUDE_odb_h__+#define INCLUDE_odb_h__++#include "git2/odb.h"+#include "git2/oid.h"++#include "vector.h"++struct git_odb {+ void *_internal;+ git_vector backends;+};++int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *obj);+int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen);++#endif
+ libgit2/src/odb_loose.c view
@@ -0,0 +1,658 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "git2/zlib.h"+#include "git2/object.h"+#include "fileops.h"+#include "hash.h"+#include "odb.h"+#include "delta-apply.h"++#include "git2/odb_backend.h"++typedef struct { /* object header data */+ git_otype type; /* object type */+ size_t size; /* object size */+} obj_hdr;++typedef struct loose_backend {+ git_odb_backend parent;++ int object_zlib_level; /** loose object zlib compression level. */+ int fsync_object_files; /** loose object file fsync flag. */+ char *objects_dir;+} loose_backend;+++/***********************************************************+ *+ * MISCELANEOUS HELPER FUNCTIONS+ *+ ***********************************************************/++static int make_temp_file(git_file *fd, char *tmp, size_t n, char *file)+{+ char *template = "/tmp_obj_XXXXXX";+ size_t tmplen = strlen(template);+ int dirlen;++ if ((dirlen = git__dirname_r(tmp, n, file)) < 0)+ return GIT_ERROR;++ if ((dirlen + tmplen) >= n)+ return GIT_ERROR;++ strcpy(tmp + dirlen, (dirlen) ? template : template + 1);++ *fd = gitfo_mkstemp(tmp);+ if (*fd < 0 && dirlen) {+ /* create directory if it doesn't exist */+ tmp[dirlen] = '\0';+ if ((gitfo_exists(tmp) < 0) && gitfo_mkdir(tmp, 0755))+ return GIT_ERROR;+ /* try again */+ strcpy(tmp + dirlen, template);+ *fd = gitfo_mkstemp(tmp);+ }+ if (*fd < 0)+ return GIT_ERROR;++ return GIT_SUCCESS;+}++++static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)+{+ size_t len = strlen(dir);++ /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */+ if (len+43 > n)+ return len+43;++ /* the object dir: eg $GIT_DIR/objects */+ strcpy(name, dir);+ if (name[len-1] != '/')+ name[len++] = '/';++ /* loose object filename: aa/aaa... (41 bytes) */+ git_oid_pathfmt(&name[len], id);+ name[len+41] = '\0';++ return 0;+}+++static size_t get_binary_object_header(obj_hdr *hdr, gitfo_buf *obj)+{+ unsigned char c;+ unsigned char *data = obj->data;+ size_t shift, size, used = 0;++ if (obj->len == 0)+ return 0;++ c = data[used++];+ hdr->type = (c >> 4) & 7;++ size = c & 15;+ shift = 4;+ while (c & 0x80) {+ if (obj->len <= used)+ return 0;+ if (sizeof(size_t) * 8 <= shift)+ return 0;+ c = data[used++];+ size += (c & 0x7f) << shift;+ shift += 7;+ }+ hdr->size = size;++ return used;+}++static size_t get_object_header(obj_hdr *hdr, unsigned char *data)+{+ char c, typename[10];+ size_t size, used = 0;++ /*+ * type name string followed by space.+ */+ while ((c = data[used]) != ' ') {+ typename[used++] = c;+ if (used >= sizeof(typename))+ return 0;+ }+ typename[used] = 0;+ if (used == 0)+ return 0;+ hdr->type = git_object_string2type(typename);+ used++; /* consume the space */++ /*+ * length follows immediately in decimal (without+ * leading zeros).+ */+ size = data[used++] - '0';+ if (size > 9)+ return 0;+ if (size) {+ while ((c = data[used]) != '\0') {+ size_t d = c - '0';+ if (d > 9)+ break;+ used++;+ size = size * 10 + d;+ }+ }+ hdr->size = size;++ /*+ * the length must be followed by a zero byte+ */+ if (data[used++] != '\0')+ return 0;++ return used;+}++++/***********************************************************+ *+ * ZLIB RELATED FUNCTIONS+ *+ ***********************************************************/++static void init_stream(z_stream *s, void *out, size_t len)+{+ memset(s, 0, sizeof(*s));+ s->next_out = out;+ s->avail_out = len;+}++static void set_stream_input(z_stream *s, void *in, size_t len)+{+ s->next_in = in;+ s->avail_in = len;+}++static void set_stream_output(z_stream *s, void *out, size_t len)+{+ s->next_out = out;+ s->avail_out = len;+}+++static int start_inflate(z_stream *s, gitfo_buf *obj, void *out, size_t len)+{+ int status;++ init_stream(s, out, len);+ set_stream_input(s, obj->data, obj->len);++ if ((status = inflateInit(s)) < Z_OK)+ return status;++ return inflate(s, 0);+}++static int finish_inflate(z_stream *s)+{+ int status = Z_OK;++ while (status == Z_OK)+ status = inflate(s, Z_FINISH);++ inflateEnd(s);++ if ((status != Z_STREAM_END) || (s->avail_in != 0))+ return GIT_ERROR;++ return GIT_SUCCESS;+}++static int deflate_buf(z_stream *s, void *in, size_t len, int flush)+{+ int status = Z_OK;++ set_stream_input(s, in, len);+ while (status == Z_OK) {+ status = deflate(s, flush);+ if (s->avail_in == 0)+ break;+ }+ return status;+}++static int deflate_obj(gitfo_buf *buf, char *hdr, int hdrlen, git_rawobj *obj, int level)+{+ z_stream zs;+ int status;+ size_t size;++ assert(buf && !buf->data && hdr && obj);+ assert(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));++ buf->data = NULL;+ buf->len = 0;+ init_stream(&zs, NULL, 0);++ if (deflateInit(&zs, level) < Z_OK)+ return GIT_ERROR;++ size = deflateBound(&zs, hdrlen + obj->len);++ if ((buf->data = git__malloc(size)) == NULL) {+ deflateEnd(&zs);+ return GIT_ERROR;+ }++ set_stream_output(&zs, buf->data, size);++ /* compress the header */+ status = deflate_buf(&zs, hdr, hdrlen, Z_NO_FLUSH);++ /* if header compressed OK, compress the object */+ if (status == Z_OK)+ status = deflate_buf(&zs, obj->data, obj->len, Z_FINISH);++ if (status != Z_STREAM_END) {+ deflateEnd(&zs);+ free(buf->data);+ buf->data = NULL;+ return GIT_ERROR;+ }++ buf->len = zs.total_out;+ deflateEnd(&zs);++ return GIT_SUCCESS;+}++static int is_zlib_compressed_data(unsigned char *data)+{+ unsigned int w;++ w = ((unsigned int)(data[0]) << 8) + data[1];+ return data[0] == 0x78 && !(w % 31);+}++static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)+{+ unsigned char *buf, *head = hb;+ size_t tail;++ /*+ * allocate a buffer to hold the inflated data and copy the+ * initial sequence of inflated data from the tail of the+ * head buffer, if any.+ */+ if ((buf = git__malloc(hdr->size + 1)) == NULL) {+ inflateEnd(s);+ return NULL;+ }+ tail = s->total_out - used;+ if (used > 0 && tail > 0) {+ if (tail > hdr->size)+ tail = hdr->size;+ memcpy(buf, head + used, tail);+ }+ used = tail;++ /*+ * inflate the remainder of the object data, if any+ */+ if (hdr->size < used)+ inflateEnd(s);+ else {+ set_stream_output(s, buf + used, hdr->size - used);+ if (finish_inflate(s)) {+ free(buf);+ return NULL;+ }+ }++ return buf;+}++/*+ * At one point, there was a loose object format that was intended to+ * mimic the format used in pack-files. This was to allow easy copying+ * of loose object data into packs. This format is no longer used, but+ * we must still read it.+ */+static int inflate_packlike_loose_disk_obj(git_rawobj *out, gitfo_buf *obj)+{+ unsigned char *in, *buf;+ obj_hdr hdr;+ size_t len, used;++ /*+ * read the object header, which is an (uncompressed)+ * binary encoding of the object type and size.+ */+ if ((used = get_binary_object_header(&hdr, obj)) == 0)+ return GIT_ERROR;++ if (!git_object_typeisloose(hdr.type))+ return GIT_ERROR;++ /*+ * allocate a buffer and inflate the data into it+ */+ buf = git__malloc(hdr.size + 1);+ if (!buf)+ return GIT_ERROR;++ in = ((unsigned char *)obj->data) + used;+ len = obj->len - used;+ if (git_odb__inflate_buffer(in, len, buf, hdr.size)) {+ free(buf);+ return GIT_ERROR;+ }+ buf[hdr.size] = '\0';++ out->data = buf;+ out->len = hdr.size;+ out->type = hdr.type;++ return GIT_SUCCESS;+}++static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)+{+ unsigned char head[64], *buf;+ z_stream zs;+ int z_status;+ obj_hdr hdr;+ size_t used;++ /*+ * check for a pack-like loose object+ */+ if (!is_zlib_compressed_data(obj->data))+ return inflate_packlike_loose_disk_obj(out, obj);++ /*+ * inflate the initial part of the io buffer in order+ * to parse the object header (type and size).+ */+ if ((z_status = start_inflate(&zs, obj, head, sizeof(head))) < Z_OK)+ return GIT_ERROR;++ if ((used = get_object_header(&hdr, head)) == 0)+ return GIT_ERROR;++ if (!git_object_typeisloose(hdr.type))+ return GIT_ERROR;++ /*+ * allocate a buffer and inflate the object data into it+ * (including the initial sequence in the head buffer).+ */+ if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)+ return GIT_ERROR;+ buf[hdr.size] = '\0';++ out->data = buf;+ out->len = hdr.size;+ out->type = hdr.type;++ return GIT_SUCCESS;+}+++++++/***********************************************************+ *+ * ODB OBJECT READING & WRITING+ *+ * Backend for the public API; read headers and full objects+ * from the ODB. Write raw data to the ODB.+ *+ ***********************************************************/++static int read_loose(git_rawobj *out, const char *loc)+{+ int error;+ gitfo_buf obj = GITFO_BUF_INIT;++ assert(out && loc);++ out->data = NULL;+ out->len = 0;+ out->type = GIT_OBJ_BAD;++ if (gitfo_read_file(&obj, loc) < 0)+ return GIT_ENOTFOUND;++ error = inflate_disk_obj(out, &obj);+ gitfo_free_buf(&obj);++ return error;+}++static int read_header_loose(git_rawobj *out, const char *loc)+{+ int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;+ git_file fd;+ z_stream zs;+ obj_hdr header_obj;+ unsigned char raw_buffer[16], inflated_buffer[64];++ assert(out && loc);++ out->data = NULL;++ if ((fd = gitfo_open(loc, O_RDONLY)) < 0)+ return GIT_ENOTFOUND;++ init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));++ if (inflateInit(&zs) < Z_OK) {+ error = GIT_EZLIB;+ goto cleanup;+ }++ do {+ if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {+ set_stream_input(&zs, raw_buffer, read_bytes);+ z_return = inflate(&zs, 0);+ }+ } while (z_return == Z_OK);++ if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)+ || get_object_header(&header_obj, inflated_buffer) == 0+ || git_object_typeisloose(header_obj.type) == 0) {+ error = GIT_EOBJCORRUPTED;+ goto cleanup;+ }++ out->len = header_obj.size;+ out->type = header_obj.type;++cleanup:+ finish_inflate(&zs);+ gitfo_close(fd);+ return error;+}++static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend)+{+ char file[GIT_PATH_MAX];+ char temp[GIT_PATH_MAX];+ git_file fd;++ if (object_file_name(file, sizeof(file), backend->objects_dir, id))+ return GIT_EOSERR;++ if (make_temp_file(&fd, temp, sizeof(temp), file) < 0)+ return GIT_EOSERR;++ if (gitfo_write(fd, buf->data, buf->len) < 0) {+ gitfo_close(fd);+ gitfo_unlink(temp);+ return GIT_EOSERR;+ }++ if (backend->fsync_object_files)+ gitfo_fsync(fd);+ gitfo_close(fd);+ gitfo_chmod(temp, 0444);++ if (gitfo_mv(temp, file) < 0) {+ gitfo_unlink(temp);+ return GIT_EOSERR;+ }++ return GIT_SUCCESS;+}++static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)+{+ object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);+ return gitfo_exists(object_location);+}++++++++++/***********************************************************+ *+ * LOOSE BACKEND PUBLIC API+ *+ * Implement the git_odb_backend API calls+ *+ ***********************************************************/++int loose_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)+{+ char object_path[GIT_PATH_MAX];++ assert(obj && backend && oid);++ if (locate_object(object_path, (loose_backend *)backend, oid) < 0)+ return GIT_ENOTFOUND;++ return read_header_loose(obj, object_path);+}+++int loose_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)+{+ char object_path[GIT_PATH_MAX];++ assert(obj && backend && oid);++ if (locate_object(object_path, (loose_backend *)backend, oid) < 0)+ return GIT_ENOTFOUND;++ return read_loose(obj, object_path);+}++int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)+{+ char object_path[GIT_PATH_MAX];++ assert(backend && oid);++ return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;+}+++int loose_backend__write(git_oid *id, git_odb_backend *_backend, git_rawobj *obj)+{+ char hdr[64];+ int hdrlen;+ gitfo_buf buf = GITFO_BUF_INIT;+ int error;+ loose_backend *backend;++ assert(id && _backend && obj);++ backend = (loose_backend *)_backend;++ if ((error = git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj)) < 0)+ return error;++ if (git_odb_exists(_backend->odb, id))+ return GIT_SUCCESS;++ if ((error = deflate_obj(&buf, hdr, hdrlen, obj, backend->object_zlib_level)) < 0)+ return error;++ error = write_obj(&buf, id, backend);++ gitfo_free_buf(&buf);+ return error;+}++void loose_backend__free(git_odb_backend *_backend)+{+ loose_backend *backend;+ assert(_backend);+ backend = (loose_backend *)_backend;++ free(backend->objects_dir);+ free(backend);+}++int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir)+{+ loose_backend *backend;++ backend = git__calloc(1, sizeof(loose_backend));+ if (backend == NULL)+ return GIT_ENOMEM;++ backend->objects_dir = git__strdup(objects_dir);+ if (backend->objects_dir == NULL) {+ free(backend);+ return GIT_ENOMEM;+ }++ backend->object_zlib_level = Z_BEST_SPEED;+ backend->fsync_object_files = 0;++ backend->parent.read = &loose_backend__read;+ backend->parent.read_header = &loose_backend__read_header;+ backend->parent.write = &loose_backend__write;+ backend->parent.exists = &loose_backend__exists;+ backend->parent.free = &loose_backend__free;++ *backend_out = (git_odb_backend *)backend;+ return GIT_SUCCESS;+}
+ libgit2/src/odb_pack.c view
@@ -0,0 +1,1406 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "git2/zlib.h"+#include "git2/repository.h"+#include "fileops.h"+#include "hash.h"+#include "odb.h"+#include "delta-apply.h"++#include "git2/odb_backend.h"++#define DEFAULT_WINDOW_SIZE \+ (sizeof(void*) >= 8 \+ ? 1 * 1024 * 1024 * 1024 \+ : 32 * 1024 * 1024)++#define DEFAULT_MAPPED_LIMIT \+ ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))++#define PACK_SIGNATURE 0x5041434b /* "PACK" */+#define PACK_VERSION 2+#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))+struct pack_header {+ uint32_t hdr_signature;+ uint32_t hdr_version;+ uint32_t hdr_entries;+};++/*+ * The first four bytes of index formats later than version 1 should+ * start with this signature, as all older git binaries would find this+ * value illegal and abort reading the file.+ *+ * This is the case because the number of objects in a packfile+ * cannot exceed 1,431,660,000 as every object would need at least+ * 3 bytes of data and the overall packfile cannot exceed 4 GiB with+ * version 1 of the index file due to the offsets limited to 32 bits.+ * Clearly the signature exceeds this maximum.+ *+ * Very old git binaries will also compare the first 4 bytes to the+ * next 4 bytes in the index and abort with a "non-monotonic index"+ * error if the second 4 byte word is smaller than the first 4+ * byte word. This would be true in the proposed future index+ * format as idx_signature would be greater than idx_version.+ */+#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */++struct pack_idx_header {+ uint32_t idx_signature;+ uint32_t idx_version;+};++struct pack_window {+ struct pack_window *next;+ git_map window_map;+ off_t offset;+ unsigned int last_used;+ unsigned int inuse_cnt;+};++struct pack_file {+ struct pack_window *windows;+ off_t pack_size;++ git_map index_map;++ uint32_t num_objects;+ uint32_t num_bad_objects;+ git_oid *bad_object_sha1; /* array of git_oid */++ int index_version;+ time_t mtime;+ int pack_fd;+ unsigned pack_local:1, pack_keep:1;+ git_oid sha1;++ /* something like ".git/objects/pack/xxxxx.pack" */+ char pack_name[GIT_FLEX_ARRAY]; /* more */+};++struct pack_entry {+ off_t offset;+ git_oid sha1;+ struct pack_file *p;+};++struct pack__dirent {+ struct pack_backend *backend;+ int is_pack_local;+};++struct pack_backend {+ git_odb_backend parent;+ git_vector packs;+ struct pack_file *last_found;++ size_t window_size; /* needs default value */++ size_t mapped_limit; /* needs default value */+ size_t peak_mapped;+ size_t mapped;++ size_t used_ctr;++ unsigned int peak_open_windows;+ unsigned int open_windows;++ unsigned int mmap_calls;+};++/**+ * The wonderful tale of a Packed Object lookup query+ * ===================================================+ * A riveting and epic story of epicness and ASCII+ * art, presented by yours truly,+ * Sir Vicent of Marti+ *+ *+ * Chapter 1: Once upon a time...+ * Initialization of the Pack Backend+ * --------------------------------------------------+ *+ * # git_odb_backend_pack+ * | Creates the pack backend structure, initializes the+ * | callback pointers to our default read() and exist() methods,+ * | and tries to preload all the known packfiles in the ODB.+ * |+ * |-# packfile_load_all+ * | Tries to find the `pack` folder, if it exists. ODBs without+ * | a pack folder are ignored altogether. If there's a `pack` folder+ * | we run a `dirent` callback through every file in the pack folder+ * | to find our packfiles. The packfiles are then sorted according+ * | to a sorting callback.+ * |+ * |-# packfile_load__cb+ * | | This callback is called from `dirent` with every single file+ * | | inside the pack folder. We find the packs by actually locating+ * | | their index (ends in ".idx"). From that index, we verify that+ * | | the corresponding packfile exists and is valid, and if so, we+ * | | add it to the pack list.+ * | |+ * | |-# packfile_check+ * | Make sure that there's a packfile to back this index, and store+ * | some very basic information regarding the packfile itself,+ * | such as the full path, the size, and the modification time.+ * | We don't actually open the packfile to check for internal consistency.+ * |+ * |-# packfile_sort__cb+ * Sort all the preloaded packs according to some specific criteria:+ * we prioritize the "newer" packs because it's more likely they+ * contain the objects we are looking for, and we prioritize local+ * packs over remote ones.+ *+ *+ *+ * Chapter 2: To be, or not to be...+ * A standard packed `exist` query for an OID+ * --------------------------------------------------+ *+ * # pack_backend__exists+ * | Check if the given SHA1 oid exists in any of the packs+ * | that have been loaded for our ODB.+ * |+ * |-# pack_entry_find+ * | Iterate through all the packs that have been preloaded+ * | (starting by the pack where the latest object was found)+ * | to try to find the OID in one of them.+ * |+ * |-# pack_entry_find1+ * | Check the index of an individual pack to see if the SHA1+ * | OID can be found. If we can find the offset to that SHA1+ * | inside of the index, that means the object is contained+ * | inside of the packfile and we can stop searching.+ * | Before returning, we verify that the packfile behing the+ * | index we are searching still exists on disk.+ * |+ * |-# pack_entry_find_offset+ * | | Mmap the actual index file to disk if it hasn't been opened+ * | | yet, and run a binary search through it to find the OID.+ * | | See <http://book.git-scm.com/7_the_packfile.html> for specifics+ * | | on the Packfile Index format and how do we find entries in it.+ * | |+ * | |-# pack_index_open+ * | | Guess the name of the index based on the full path to the+ * | | packfile, open it and verify its contents. Only if the index+ * | | has not been opened already.+ * | |+ * | |-# pack_index_check+ * | Mmap the index file and do a quick run through the header+ * | to guess the index version (right now we support v1 and v2),+ * | and to verify that the size of the index makes sense.+ * |+ * |-# packfile_open+ * See `packfile_open` in Chapter 3+ *+ *+ *+ * Chapter 3: The neverending story...+ * A standard packed `lookup` query for an OID+ * --------------------------------------------------+ * TODO+ *+ */++++ +/***********************************************************+ *+ * FORWARD DECLARATIONS+ *+ ***********************************************************/++static void pack_window_free_all(struct pack_backend *backend, struct pack_file *p);+static int pack_window_contains(struct pack_window *win, off_t offset);++static void pack_window_scan_lru(struct pack_file *p, struct pack_file **lru_p,+ struct pack_window **lru_w, struct pack_window **lru_l);++static int pack_window_close_lru( struct pack_backend *backend,+ struct pack_file *current, git_file keep_fd);++static void pack_window_close(struct pack_window **w_cursor);++static unsigned char *pack_window_open( struct pack_backend *backend,+ struct pack_file *p, struct pack_window **w_cursor, off_t offset,+ unsigned int *left);++static int packfile_sort__cb(const void *a_, const void *b_);++static void pack_index_free(struct pack_file *p);++static int pack_index_check(const char *path, struct pack_file *p);+static int pack_index_open(struct pack_file *p);++static struct pack_file *packfile_alloc(int extra);+static int packfile_open(struct pack_file *p);+static int packfile_check(struct pack_file **pack_out, const char *path, int local);+static int packfile_load__cb(void *_data, char *path);+static int packfile_load_all(struct pack_backend *backend, const char *odb_path, int local);++static off_t nth_packed_object_offset(const struct pack_file *p, uint32_t n);++static int pack_entry_find_offset(off_t *offset_out,+ struct pack_file *p, const git_oid *oid);++static int pack_entry_find1(struct pack_entry *e,+ struct pack_file *p, const git_oid *oid);++static int pack_entry_find(struct pack_entry *e,+ struct pack_backend *backend, const git_oid *oid);++static off_t get_delta_base(struct pack_backend *backend,+ struct pack_file *p, struct pack_window **w_curs,+ off_t *curpos, git_otype type,+ off_t delta_obj_offset);++static unsigned long packfile_unpack_header1(+ size_t *sizep,+ git_otype *type, + const unsigned char *buf,+ unsigned long len);++static int packfile_unpack_header(+ size_t *size_p,+ git_otype *type_p,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t *curpos);++static int packfile_unpack_compressed(+ git_rawobj *obj,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t curpos,+ size_t size,+ git_otype type);++static int packfile_unpack_delta(+ git_rawobj *obj,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t curpos,+ size_t delta_size,+ git_otype delta_type,+ off_t obj_offset);++static int packfile_unpack(git_rawobj *obj, struct pack_backend *backend,+ struct pack_file *p, off_t obj_offset);++++++/***********************************************************+ *+ * PACK WINDOW MANAGEMENT+ *+ ***********************************************************/++void pack_window_free_all(struct pack_backend *backend, struct pack_file *p)+{+ while (p->windows) {+ struct pack_window *w = p->windows;+ assert(w->inuse_cnt == 0);++ backend->mapped -= w->window_map.len;+ backend->open_windows--;++ gitfo_free_map(&w->window_map);++ p->windows = w->next;+ free(w);+ }+}++GIT_INLINE(int) pack_window_contains(struct pack_window *win, off_t offset)+{+ /* We must promise at least 20 bytes (one hash) after the+ * offset is available from this window, otherwise the offset+ * is not actually in this window and a different window (which+ * has that one hash excess) must be used. This is to support+ * the object header and delta base parsing routines below.+ */+ off_t win_off = win->offset;+ return win_off <= offset+ && (offset + 20) <= (off_t)(win_off + win->window_map.len);+}++static void pack_window_scan_lru(+ struct pack_file *p,+ struct pack_file **lru_p,+ struct pack_window **lru_w,+ struct pack_window **lru_l)+{+ struct pack_window *w, *w_l;++ for (w_l = NULL, w = p->windows; w; w = w->next) {+ if (!w->inuse_cnt) {+ if (!*lru_w || w->last_used < (*lru_w)->last_used) {+ *lru_p = p;+ *lru_w = w;+ *lru_l = w_l;+ }+ }+ w_l = w;+ }+}++static int pack_window_close_lru(+ struct pack_backend *backend,+ struct pack_file *current,+ git_file keep_fd)+{+ struct pack_file *lru_p = NULL;+ struct pack_window *lru_w = NULL, *lru_l = NULL;+ size_t i;++ if (current)+ pack_window_scan_lru(current, &lru_p, &lru_w, &lru_l);++ for (i = 0; i < backend->packs.length; ++i)+ pack_window_scan_lru(git_vector_get(&backend->packs, i), &lru_p, &lru_w, &lru_l);++ if (lru_p) {+ backend->mapped -= lru_w->window_map.len;+ gitfo_free_map(&lru_w->window_map);++ if (lru_l)+ lru_l->next = lru_w->next;+ else {+ lru_p->windows = lru_w->next;+ if (!lru_p->windows && lru_p->pack_fd != keep_fd) {+ gitfo_close(lru_p->pack_fd);+ lru_p->pack_fd = -1;+ }+ }++ free(lru_w);+ backend->open_windows--;+ return GIT_SUCCESS;+ }++ return GIT_ERROR;+}++static void pack_window_close(struct pack_window **w_cursor)+{+ struct pack_window *w = *w_cursor;+ if (w) {+ w->inuse_cnt--;+ *w_cursor = NULL;+ }+}++static unsigned char *pack_window_open(+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_cursor,+ off_t offset,+ unsigned int *left)+{+ struct pack_window *win = *w_cursor;++ if (p->pack_fd == -1 && packfile_open(p) < GIT_SUCCESS)+ return NULL;++ /* Since packfiles end in a hash of their content and it's+ * pointless to ask for an offset into the middle of that+ * hash, and the pack_window_contains function above wouldn't match+ * don't allow an offset too close to the end of the file.+ */+ if (offset > (p->pack_size - 20))+ return NULL;++ if (!win || !pack_window_contains(win, offset)) {++ if (win)+ win->inuse_cnt--;++ for (win = p->windows; win; win = win->next) {+ if (pack_window_contains(win, offset))+ break;+ }++ if (!win) {+ size_t window_align = backend->window_size / 2;+ size_t len;++ win = git__calloc(1, sizeof(*win));+ win->offset = (offset / window_align) * window_align;++ len = (size_t)(p->pack_size - win->offset);+ if (len > backend->window_size)+ len = backend->window_size;++ backend->mapped += len;++ while (backend->mapped_limit < backend->mapped &&+ pack_window_close_lru(backend, p, p->pack_fd) == GIT_SUCCESS) {}++ if (gitfo_map_ro(&win->window_map, p->pack_fd,+ win->offset, len) < GIT_SUCCESS)+ return NULL;++ backend->mmap_calls++;+ backend->open_windows++;++ if (backend->mapped > backend->peak_mapped)+ backend->peak_mapped = backend->mapped;++ if (backend->open_windows > backend->peak_open_windows)+ backend->peak_open_windows = backend->open_windows;++ win->next = p->windows;+ p->windows = win;+ }+ }++ if (win != *w_cursor) {+ win->last_used = backend->used_ctr++;+ win->inuse_cnt++;+ *w_cursor = win;+ }++ offset -= win->offset;+ assert(git__is_sizet(offset));++ if (left)+ *left = win->window_map.len - (size_t)offset;++ return (unsigned char *)win->window_map.data + offset;+}++++++++/***********************************************************+ *+ * PACK INDEX METHODS+ *+ ***********************************************************/++static void pack_index_free(struct pack_file *p)+{+ if (p->index_map.data) {+ gitfo_free_map(&p->index_map);+ p->index_map.data = NULL;+ }+}++static int pack_index_check(const char *path, struct pack_file *p)+{+ struct pack_idx_header *hdr;+ uint32_t version, nr, i, *index;++ void *idx_map;+ size_t idx_size;++ struct stat st;++ /* TODO: properly open the file without access time */+ git_file fd = gitfo_open(path, O_RDONLY /*| O_NOATIME */);++ int error;++ if (fd < 0)+ return GIT_EOSERR;++ if (gitfo_fstat(fd, &st) < GIT_SUCCESS) {+ gitfo_close(fd);+ return GIT_EOSERR;+ }++ if (!git__is_sizet(st.st_size))+ return GIT_ENOMEM;++ idx_size = (size_t)st.st_size;++ if (idx_size < 4 * 256 + 20 + 20) {+ gitfo_close(fd);+ return GIT_EOBJCORRUPTED;+ }++ error = gitfo_map_ro(&p->index_map, fd, 0, idx_size);+ gitfo_close(fd);++ if (error < GIT_SUCCESS)+ return error;++ hdr = idx_map = p->index_map.data;++ if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {+ version = ntohl(hdr->idx_version);++ if (version < 2 || version > 2) {+ gitfo_free_map(&p->index_map);+ return GIT_EOBJCORRUPTED; /* unsupported index version */+ }++ } else+ version = 1;++ nr = 0;+ index = idx_map;++ if (version > 1)+ index += 2; /* skip index header */++ for (i = 0; i < 256; i++) {+ uint32_t n = ntohl(index[i]);+ if (n < nr) {+ gitfo_free_map(&p->index_map);+ return GIT_EOBJCORRUPTED; /* non-monotonic index */+ }+ nr = n;+ }++ if (version == 1) {+ /*+ * Total size:+ * - 256 index entries 4 bytes each+ * - 24-byte entries * nr (20-byte sha1 + 4-byte offset)+ * - 20-byte SHA1 of the packfile+ * - 20-byte SHA1 file checksum+ */+ if (idx_size != 4*256 + nr * 24 + 20 + 20) {+ gitfo_free_map(&p->index_map);+ return GIT_EOBJCORRUPTED;+ }+ } else if (version == 2) {+ /*+ * Minimum size:+ * - 8 bytes of header+ * - 256 index entries 4 bytes each+ * - 20-byte sha1 entry * nr+ * - 4-byte crc entry * nr+ * - 4-byte offset entry * nr+ * - 20-byte SHA1 of the packfile+ * - 20-byte SHA1 file checksum+ * And after the 4-byte offset table might be a+ * variable sized table containing 8-byte entries+ * for offsets larger than 2^31.+ */+ unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;+ unsigned long max_size = min_size;++ if (nr)+ max_size += (nr - 1)*8;++ if (idx_size < min_size || idx_size > max_size) {+ gitfo_free_map(&p->index_map);+ return GIT_EOBJCORRUPTED;+ }++ /* Make sure that off_t is big enough to access the whole pack...+ * Is this an issue in libgit2? It shouldn't. */+ if (idx_size != min_size && (sizeof(off_t) <= 4)) {+ gitfo_free_map(&p->index_map);+ return GIT_EOSERR;+ }+ }++ p->index_version = version;+ p->num_objects = nr;+ return GIT_SUCCESS;+}++static int pack_index_open(struct pack_file *p)+{+ char *idx_name;+ int error;++ if (p->index_map.data)+ return GIT_SUCCESS;++ idx_name = git__strdup(p->pack_name);+ strcpy(idx_name + strlen(idx_name) - STRLEN(".pack"), ".idx");++ error = pack_index_check(idx_name, p);+ free(idx_name);++ return error;+}++++++++++/***********************************************************+ *+ * PACKFILE METHODS+ *+ ***********************************************************/++static int packfile_sort__cb(const void *a_, const void *b_)+{+ struct pack_file *a = *((struct pack_file **)a_);+ struct pack_file *b = *((struct pack_file **)b_);+ int st;++ /*+ * Local packs tend to contain objects specific to our+ * variant of the project than remote ones. In addition,+ * remote ones could be on a network mounted filesystem.+ * Favor local ones for these reasons.+ */+ st = a->pack_local - b->pack_local;+ if (st)+ return -st;++ /*+ * Younger packs tend to contain more recent objects,+ * and more recent objects tend to get accessed more+ * often.+ */+ if (a->mtime < b->mtime)+ return 1;+ else if (a->mtime == b->mtime)+ return 0;++ return -1;+}++static struct pack_file *packfile_alloc(int extra)+{+ struct pack_file *p = git__malloc(sizeof(*p) + extra);+ memset(p, 0, sizeof(*p));+ p->pack_fd = -1;+ return p;+}+++static void packfile_free(struct pack_backend *backend, struct pack_file *p)+{+ assert(p);++ /* clear_delta_base_cache(); */+ pack_window_free_all(backend, p);++ if (p->pack_fd != -1)+ gitfo_close(p->pack_fd);++ pack_index_free(p);++ free(p->bad_object_sha1);+ free(p);+}++static int packfile_open(struct pack_file *p)+{+ struct stat st;+ struct pack_header hdr;+ git_oid sha1;+ unsigned char *idx_sha1;++ if (!p->index_map.data && pack_index_open(p) < GIT_SUCCESS)+ return GIT_ENOTFOUND;++ /* TODO: open with noatime */+ p->pack_fd = gitfo_open(p->pack_name, O_RDONLY);+ if (p->pack_fd < 0 || gitfo_fstat(p->pack_fd, &st) < GIT_SUCCESS)+ return GIT_EOSERR;++ /* If we created the struct before we had the pack we lack size. */+ if (!p->pack_size) {+ if (!S_ISREG(st.st_mode))+ goto cleanup;+ p->pack_size = (off_t)st.st_size;+ } else if (p->pack_size != st.st_size)+ goto cleanup;++#if 0+ /* We leave these file descriptors open with sliding mmap;+ * there is no point keeping them open across exec(), though.+ */+ fd_flag = fcntl(p->pack_fd, F_GETFD, 0);+ if (fd_flag < 0)+ return error("cannot determine file descriptor flags");++ fd_flag |= FD_CLOEXEC;+ if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)+ return GIT_EOSERR;+#endif++ /* Verify we recognize this pack file format. */+ if (gitfo_read(p->pack_fd, &hdr, sizeof(hdr)) < GIT_SUCCESS)+ goto cleanup;++ if (hdr.hdr_signature != htonl(PACK_SIGNATURE))+ goto cleanup;++ if (!pack_version_ok(hdr.hdr_version))+ goto cleanup;++ /* Verify the pack matches its index. */+ if (p->num_objects != ntohl(hdr.hdr_entries))+ goto cleanup;++ if (gitfo_lseek(p->pack_fd, p->pack_size - GIT_OID_RAWSZ, SEEK_SET) == -1)+ goto cleanup;++ if (gitfo_read(p->pack_fd, sha1.id, GIT_OID_RAWSZ) < GIT_SUCCESS)+ goto cleanup;++ idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;++ if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) != 0)+ goto cleanup;++ return GIT_SUCCESS; ++cleanup:+ gitfo_close(p->pack_fd);+ p->pack_fd = -1;+ return GIT_EPACKCORRUPTED;+}++static int packfile_check(struct pack_file **pack_out, const char *path, int local)+{+ struct stat st;+ struct pack_file *p;+ size_t path_len;++ *pack_out = NULL;+ path_len = strlen(path);+ p = packfile_alloc(path_len + 2);++ /*+ * Make sure a corresponding .pack file exists and that+ * the index looks sane.+ */+ path_len -= STRLEN(".idx");+ if (path_len < 1) {+ free(p);+ return GIT_ENOTFOUND;+ }++ memcpy(p->pack_name, path, path_len);++ strcpy(p->pack_name + path_len, ".keep");+ if (gitfo_exists(p->pack_name) == GIT_SUCCESS)+ p->pack_keep = 1;++ strcpy(p->pack_name + path_len, ".pack");+ if (gitfo_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) {+ free(p);+ return GIT_ENOTFOUND;+ }++ /* ok, it looks sane as far as we can check without+ * actually mapping the pack file.+ */+ p->pack_size = (off_t)st.st_size;+ p->pack_local = local;+ p->mtime = st.st_mtime;++ /* see if we can parse the sha1 oid in the packfile name */+ if (path_len < 40 ||+ git_oid_mkstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < GIT_SUCCESS)+ memset(&p->sha1, 0x0, GIT_OID_RAWSZ);++ *pack_out = p;+ return GIT_SUCCESS;+}++static int packfile_load__cb(void *_data, char *path)+{+ struct pack__dirent *data = (struct pack__dirent *)_data;+ struct pack_file *pack;+ int error;++ if (git__suffixcmp(path, ".idx") != 0)+ return GIT_SUCCESS; /* not an index */++ /* FIXME: git.git checks for duplicate packs.+ * But that makes no fucking sense. Our dirent is not+ * going to generate dupicate entries */++ error = packfile_check(&pack, path, data->is_pack_local);+ if (error < GIT_SUCCESS)+ return error;++ if (git_vector_insert(&data->backend->packs, pack) < GIT_SUCCESS) {+ free(pack);+ return GIT_ENOMEM;+ }++ return GIT_SUCCESS;+}++static int packfile_load_all(struct pack_backend *backend, const char *odb_path, int local)+{+ int error;+ char path[GIT_PATH_MAX];+ struct pack__dirent data;++ data.backend = backend;+ data.is_pack_local = local;++ git__joinpath(path, odb_path, "pack");+ if (gitfo_isdir(path) < GIT_SUCCESS)+ return GIT_SUCCESS;++ error = gitfo_dirent(path, GIT_PATH_MAX, packfile_load__cb, (void *)&data);+ if (error < GIT_SUCCESS)+ return error;++ git_vector_sort(&backend->packs);+ backend->last_found = git_vector_get(&backend->packs, 0);++ return GIT_SUCCESS;+}+++++++++/***********************************************************+ *+ * PACKFILE ENTRY SEARCH INTERNALS+ *+ ***********************************************************/++static off_t nth_packed_object_offset(const struct pack_file *p, uint32_t n)+{+ const unsigned char *index = p->index_map.data;+ index += 4 * 256;+ if (p->index_version == 1) {+ return ntohl(*((uint32_t *)(index + 24 * n)));+ } else {+ uint32_t off;+ index += 8 + p->num_objects * (20 + 4);+ off = ntohl(*((uint32_t *)(index + 4 * n)));+ if (!(off & 0x80000000))+ return off;+ index += p->num_objects * 4 + (off & 0x7fffffff) * 8;+ return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |+ ntohl(*((uint32_t *)(index + 4)));+ }+}++static int pack_entry_find_offset(+ off_t *offset_out,+ struct pack_file *p,+ const git_oid *oid)+{+ const uint32_t *level1_ofs = p->index_map.data;+ const unsigned char *index = p->index_map.data;+ unsigned hi, lo, stride;++ *offset_out = 0;++ if (index == NULL) {+ int error;++ if ((error = pack_index_open(p)) < GIT_SUCCESS)+ return error;++ assert(p->index_map.data);++ index = p->index_map.data;+ level1_ofs = p->index_map.data;+ }++ if (p->index_version > 1) {+ level1_ofs += 2;+ index += 8;+ }++ index += 4 * 256;+ hi = ntohl(level1_ofs[(int)oid->id[0]]);+ lo = ((oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)oid->id[0] - 1]));++ if (p->index_version > 1) {+ stride = 20;+ } else {+ stride = 24;+ index += 4;+ }++#ifdef INDEX_DEBUG_LOOKUP+ printf("%02x%02x%02x... lo %u hi %u nr %d\n",+ oid->id[0], oid->id[1], oid->id[2], lo, hi, p->num_objects);+#endif++#ifdef GIT2_INDEX_LOOKUP /* TODO: use the advanced lookup method from git.git */++ int pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, oid);+ if (pos < 0)+ return GIT_ENOTFOUND;++ *offset_out = nth_packed_object_offset(p, pos);+ return GIT_SUCCESS;++#else /* use an old and boring binary search */++ do {+ unsigned mi = (lo + hi) / 2;+ int cmp = memcmp(index + mi * stride, oid->id, GIT_OID_RAWSZ);++ if (!cmp) {+ *offset_out = nth_packed_object_offset(p, mi);+ return GIT_SUCCESS;+ }++ if (cmp > 0)+ hi = mi;+ else+ lo = mi+1;++ } while (lo < hi);++ return GIT_ENOTFOUND;+#endif+}++static int pack_entry_find1(+ struct pack_entry *e,+ struct pack_file *p,+ const git_oid *oid)+{+ off_t offset;++ assert(p);++ if (p->num_bad_objects) {+ unsigned i;+ for (i = 0; i < p->num_bad_objects; i++)+ if (git_oid_cmp(oid, &p->bad_object_sha1[i]) == 0)+ return GIT_ERROR;+ }++ if (pack_entry_find_offset(&offset, p, oid) < GIT_SUCCESS)+ return GIT_ENOTFOUND;+ + /* we found an entry in the index;+ * make sure the packfile backing the index + * still exists on disk */+ if (p->pack_fd == -1 && packfile_open(p) < GIT_SUCCESS)+ return GIT_EOSERR;++ e->offset = offset;+ e->p = p;++ git_oid_cpy(&e->sha1, oid);+ return GIT_SUCCESS;+}++static int pack_entry_find(struct pack_entry *e, struct pack_backend *backend, const git_oid *oid)+{+ size_t i;++ if (backend->last_found &&+ pack_entry_find1(e, backend->last_found, oid) == GIT_SUCCESS)+ return GIT_SUCCESS;++ for (i = 0; i < backend->packs.length; ++i) {+ struct pack_file *p;++ p = git_vector_get(&backend->packs, i);+ if (p == backend->last_found)+ continue;++ if (pack_entry_find1(e, p, oid) == GIT_SUCCESS) {+ backend->last_found = p;+ return GIT_SUCCESS;+ }+ }++ return GIT_ENOTFOUND;+}+++++++++++++/***********************************************************+ *+ * PACKFILE ENTRY UNPACK INTERNALS+ *+ ***********************************************************/++static unsigned long packfile_unpack_header1(+ size_t *sizep,+ git_otype *type, + const unsigned char *buf,+ unsigned long len)+{+ unsigned shift;+ unsigned long size, c;+ unsigned long used = 0;++ c = buf[used++];+ *type = (c >> 4) & 7;+ size = c & 15;+ shift = 4;+ while (c & 0x80) {+ if (len <= used || bitsizeof(long) <= shift)+ return 0;++ c = buf[used++];+ size += (c & 0x7f) << shift;+ shift += 7;+ }++ *sizep = (size_t)size;+ return used;+}++static int packfile_unpack_header(+ size_t *size_p,+ git_otype *type_p,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t *curpos)+{+ unsigned char *base;+ unsigned int left;+ unsigned long used;++ /* pack_window_open() assures us we have [base, base + 20) available+ * as a range that we can look at at. (Its actually the hash+ * size that is assured.) With our object header encoding+ * the maximum deflated object size is 2^137, which is just+ * insane, so we know won't exceed what we have been given.+ */+ base = pack_window_open(backend, p, w_curs, *curpos, &left);+ if (base == NULL)+ return GIT_ENOMEM;++ used = packfile_unpack_header1(size_p, type_p, base, left);++ if (used == 0)+ return GIT_EOBJCORRUPTED;++ *curpos += used;+ return GIT_SUCCESS;+}++static int packfile_unpack_compressed(+ git_rawobj *obj,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t curpos,+ size_t size,+ git_otype type)+{+ int st;+ z_stream stream;+ unsigned char *buffer, *in;++ buffer = git__malloc(size);++ memset(&stream, 0, sizeof(stream));+ stream.next_out = buffer;+ stream.avail_out = size + 1;++ st = inflateInit(&stream);+ if (st != Z_OK) {+ free(buffer);+ return GIT_EZLIB;+ }++ do {+ in = pack_window_open(backend, p, w_curs, curpos, &stream.avail_in);+ stream.next_in = in;+ st = inflate(&stream, Z_FINISH);++ if (!stream.avail_out)+ break; /* the payload is larger than it should be */++ curpos += stream.next_in - in;+ } while (st == Z_OK || st == Z_BUF_ERROR);++ inflateEnd(&stream);++ if ((st != Z_STREAM_END) || stream.total_out != size) {+ free(buffer);+ return GIT_EZLIB;+ }++ obj->type = type;+ obj->len = size;+ obj->data = buffer;+ return GIT_SUCCESS;+}++static off_t get_delta_base(+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t *curpos,+ git_otype type,+ off_t delta_obj_offset)+{+ unsigned char *base_info = pack_window_open(backend, p, w_curs, *curpos, NULL);+ off_t base_offset;++ /* pack_window_open() assured us we have [base_info, base_info + 20)+ * as a range that we can look at without walking off the+ * end of the mapped window. Its actually the hash size+ * that is assured. An OFS_DELTA longer than the hash size+ * is stupid, as then a REF_DELTA would be smaller to store.+ */+ if (type == GIT_OBJ_OFS_DELTA) {+ unsigned used = 0;+ unsigned char c = base_info[used++];+ base_offset = c & 127;+ while (c & 128) {+ base_offset += 1;+ if (!base_offset || MSB(base_offset, 7))+ return 0; /* overflow */+ c = base_info[used++];+ base_offset = (base_offset << 7) + (c & 127);+ }+ base_offset = delta_obj_offset - base_offset;+ if (base_offset <= 0 || base_offset >= delta_obj_offset)+ return 0; /* out of bound */+ *curpos += used;+ } else if (type == GIT_OBJ_REF_DELTA) {+ /* The base entry _must_ be in the same pack */+ if (pack_entry_find_offset(&base_offset, p, (git_oid *)base_info) < GIT_SUCCESS)+ return GIT_EPACKCORRUPTED;+ *curpos += 20;+ } else+ return 0;++ return base_offset;+}++static int packfile_unpack_delta(+ git_rawobj *obj,+ struct pack_backend *backend,+ struct pack_file *p,+ struct pack_window **w_curs,+ off_t curpos,+ size_t delta_size,+ git_otype delta_type,+ off_t obj_offset)+{+ off_t base_offset;+ git_rawobj base, delta;+ int error;++ base_offset = get_delta_base(backend, p, w_curs, &curpos, delta_type, obj_offset);+ if (base_offset == 0)+ return GIT_EOBJCORRUPTED;++ pack_window_close(w_curs);+ error = packfile_unpack(&base, backend, p, base_offset);++ /* TODO: git.git tries to load the base from other packfiles+ * or loose objects */+ if (error < GIT_SUCCESS)+ return error;++ error = packfile_unpack_compressed(&delta, backend, p, w_curs, curpos, delta_size, delta_type);+ if (error < GIT_SUCCESS) {+ git_rawobj_close(&base);+ return error;+ }++ obj->type = base.type;+ error = git__delta_apply(obj,+ base.data, base.len,+ delta.data, delta.len);++ git_rawobj_close(&base);+ git_rawobj_close(&delta);++ /* TODO: we might want to cache this shit. eventually */+ //add_delta_base_cache(p, base_offset, base, base_size, *type);+ return error;+}++static int packfile_unpack(+ git_rawobj *obj,+ struct pack_backend *backend,+ struct pack_file *p,+ off_t obj_offset)+{+ struct pack_window *w_curs = NULL;+ off_t curpos = obj_offset;+ int error;++ size_t size;+ git_otype type;++ /* + * TODO: optionally check the CRC on the packfile+ */++ obj->data = NULL;+ obj->len = 0;+ obj->type = GIT_OBJ_BAD;++ error = packfile_unpack_header(&size, &type, backend, p, &w_curs, &curpos);+ if (error < GIT_SUCCESS)+ return error;++ switch (type) {+ case GIT_OBJ_OFS_DELTA:+ case GIT_OBJ_REF_DELTA:+ error = packfile_unpack_delta(+ obj, backend, p, &w_curs, curpos,+ size, type, obj_offset);+ break;++ case GIT_OBJ_COMMIT:+ case GIT_OBJ_TREE:+ case GIT_OBJ_BLOB:+ case GIT_OBJ_TAG:+ error = packfile_unpack_compressed(+ obj, backend, p, &w_curs, curpos,+ size, type);+ break;++ default:+ error = GIT_EOBJCORRUPTED;+ break;+ }++ pack_window_close(&w_curs);+ return error;+}++++++/***********************************************************+ *+ * PACKED BACKEND PUBLIC API+ *+ * Implement the git_odb_backend API calls+ *+ ***********************************************************/++/*+int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)+{+ pack_location location;++ assert(obj && backend && oid);++ if (locate_packfile(&location, (struct pack_backend *)backend, oid) < 0)+ return GIT_ENOTFOUND;++ return read_header_packed(obj, &location);+}+*/++int pack_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)+{+ struct pack_entry e;+ int error;++ if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS)+ return error;++ return packfile_unpack(obj, (struct pack_backend *)backend, e.p, e.offset);+}++int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)+{+ struct pack_entry e;+ return pack_entry_find(&e, (struct pack_backend *)backend, oid) == GIT_SUCCESS;+}++void pack_backend__free(git_odb_backend *_backend)+{+ struct pack_backend *backend;+ size_t i;++ assert(_backend);++ backend = (struct pack_backend *)_backend;++ for (i = 0; i < backend->packs.length; ++i) {+ struct pack_file *p = git_vector_get(&backend->packs, i);+ packfile_free(backend, p);+ }++ git_vector_free(&backend->packs);+ free(backend);+}++int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)+{+ int error;+ struct pack_backend *backend;++ backend = git__calloc(1, sizeof(struct pack_backend));+ if (backend == NULL)+ return GIT_ENOMEM;++ if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) {+ free(backend);+ return GIT_ENOMEM;+ }++ backend->window_size = DEFAULT_WINDOW_SIZE;+ backend->mapped_limit = DEFAULT_MAPPED_LIMIT;++ error = packfile_load_all(backend, objects_dir, 1);+ if (error < GIT_SUCCESS) {+ pack_backend__free((git_odb_backend *)backend);+ return error;+ }++ backend->parent.read = &pack_backend__read;+ backend->parent.read_header = NULL;+ backend->parent.write = NULL;+ backend->parent.exists = &pack_backend__exists;+ backend->parent.free = &pack_backend__free;++ *backend_out = (git_odb_backend *)backend;+ return GIT_SUCCESS;+}
+ libgit2/src/oid.c view
@@ -0,0 +1,346 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "git2/oid.h"+#include "repository.h"+#include <string.h>+#include <limits.h>++static signed char from_hex[] = {+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */+-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */+-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */+-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */+};+static char to_hex[] = "0123456789abcdef";++int git_oid_mkstr(git_oid *out, const char *str)+{+ size_t p;+ for (p = 0; p < sizeof(out->id); p++, str += 2) {+ int v = (from_hex[(unsigned char)str[0]] << 4)+ | from_hex[(unsigned char)str[1]];+ if (v < 0)+ return GIT_ENOTOID;+ out->id[p] = (unsigned char)v;+ }+ return GIT_SUCCESS;+}++GIT_INLINE(char) *fmt_one(char *str, unsigned int val)+{+ *str++ = to_hex[val >> 4];+ *str++ = to_hex[val & 0xf];+ return str;+}++void git_oid_fmt(char *str, const git_oid *oid)+{+ size_t i;++ for (i = 0; i < sizeof(oid->id); i++)+ str = fmt_one(str, oid->id[i]);+}++void git_oid_pathfmt(char *str, const git_oid *oid)+{+ size_t i;++ str = fmt_one(str, oid->id[0]);+ *str++ = '/';+ for (i = 1; i < sizeof(oid->id); i++)+ str = fmt_one(str, oid->id[i]);+}++char *git_oid_allocfmt(const git_oid *oid)+{+ char *str = git__malloc(GIT_OID_HEXSZ + 1);+ if (!str)+ return NULL;+ git_oid_fmt(str, oid);+ str[GIT_OID_HEXSZ] = '\0';+ return str;+}++char *git_oid_to_string(char *out, size_t n, const git_oid *oid)+{+ char str[GIT_OID_HEXSZ];++ if (!out || n == 0 || !oid)+ return "";++ n--; /* allow room for terminating NUL */++ if (n > 0) {+ git_oid_fmt(str, oid);+ if (n > GIT_OID_HEXSZ)+ n = GIT_OID_HEXSZ;+ memcpy(out, str, n);+ }++ out[n] = '\0';++ return out;+}++int git__parse_oid(git_oid *oid, char **buffer_out,+ const char *buffer_end, const char *header)+{+ const size_t sha_len = GIT_OID_HEXSZ;+ const size_t header_len = strlen(header);++ char *buffer = *buffer_out;++ if (buffer + (header_len + sha_len + 1) > buffer_end)+ return GIT_EOBJCORRUPTED;++ if (memcmp(buffer, header, header_len) != 0)+ return GIT_EOBJCORRUPTED;++ if (buffer[header_len + sha_len] != '\n')+ return GIT_EOBJCORRUPTED;++ if (git_oid_mkstr(oid, buffer + header_len) < GIT_SUCCESS)+ return GIT_EOBJCORRUPTED;++ *buffer_out = buffer + (header_len + sha_len + 1);++ return GIT_SUCCESS;+}++int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid)+{+ char hex_oid[41];++ git_oid_fmt(hex_oid, oid);+ hex_oid[40] = 0;++ return git__source_printf(src, "%s %s\n", header, hex_oid);+}++void git_oid_mkraw(git_oid *out, const unsigned char *raw)+{+ memcpy(out->id, raw, sizeof(out->id));+}++void git_oid_cpy(git_oid *out, const git_oid *src)+{+ memcpy(out->id, src->id, sizeof(out->id));+}++int git_oid_cmp(const git_oid *a, const git_oid *b)+{+ return memcmp(a->id, b->id, sizeof(a->id));+}+++typedef short node_index;++typedef union {+ const char *tail;+ node_index children[16];+} trie_node;++struct git_oid_shorten {+ trie_node *nodes;+ size_t node_count, size;+ int min_length, full;+};++static int resize_trie(git_oid_shorten *self, size_t new_size)+{+ self->nodes = realloc(self->nodes, new_size * sizeof(trie_node));+ if (self->nodes == NULL)+ return GIT_ENOMEM;++ if (new_size > self->size) {+ memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(trie_node));+ }++ self->size = new_size;+ return GIT_SUCCESS;+}++static trie_node *push_leaf(git_oid_shorten *os, node_index idx, int push_at, const char *oid)+{+ trie_node *node, *leaf;+ node_index idx_leaf;++ if (os->node_count >= os->size) {+ if (resize_trie(os, os->size * 2) < GIT_SUCCESS)+ return NULL;+ }++ idx_leaf = (node_index)os->node_count++;++ if (os->node_count == SHRT_MAX)+ os->full = 1;++ node = &os->nodes[idx];+ node->children[push_at] = -idx_leaf;++ leaf = &os->nodes[idx_leaf];+ leaf->tail = oid;++ return node;+}++git_oid_shorten *git_oid_shorten_new(size_t min_length)+{+ git_oid_shorten *os;++ os = git__malloc(sizeof(git_oid_shorten));+ if (os == NULL)+ return NULL;++ memset(os, 0x0, sizeof(git_oid_shorten));++ if (resize_trie(os, 16) < GIT_SUCCESS) {+ free(os);+ return NULL;+ }++ os->node_count = 1;+ os->min_length = min_length;++ return os;+}++void git_oid_shorten_free(git_oid_shorten *os)+{+ free(os->nodes);+ free(os);+}+++/*+ * What wizardry is this?+ *+ * This is just a memory-optimized trie: basically a very fancy+ * 16-ary tree, which is used to store the prefixes of the OID+ * strings.+ *+ * Read more: http://en.wikipedia.org/wiki/Trie+ *+ * Magic that happens in this method:+ *+ * - Each node in the trie is an union, so it can work both as+ * a normal node, or as a leaf.+ *+ * - Each normal node points to 16 children (one for each possible+ * character in the oid). This is *not* stored in an array of+ * pointers, because in a 64-bit arch this would be sucking + * 16*sizeof(void*) = 128 bytes of memory per node, which is fucking+ * insane. What we do is store Node Indexes, and use these indexes+ * to look up each node in the om->index array. These indexes are+ * signed shorts, so this limits the amount of unique OIDs that+ * fit in the structure to about 20000 (assuming a more or less uniform+ * distribution).+ *+ * - All the nodes in om->index array are stored contiguously in+ * memory, and each of them is 32 bytes, so we fit 2x nodes per+ * cache line. Convenient for speed.+ *+ * - To differentiate the leafs from the normal nodes, we store all+ * the indexes towards a leaf as a negative index (indexes to normal+ * nodes are positives). When we find that one of the children for+ * a node has a negative value, that means it's going to be a leaf.+ * This reduces the amount of indexes we have by two, but also reduces+ * the size of each node by 1-4 bytes (the amount we would need to+ * add a `is_leaf` field): this is good because it allows the nodes+ * to fit cleanly in cache lines.+ *+ * - Once we reach an empty children, instead of continuing to insert+ * new nodes for each remaining character of the OID, we store a pointer+ * to the tail in the leaf; if the leaf is reached again, we turn it+ * into a normal node and use the tail to create a new leaf.+ *+ * This is a pretty good balance between performance and memory usage.+ */+int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)+{+ int i, is_leaf;+ node_index idx;++ if (os->full)+ return GIT_ENOMEM;++ idx = 0;+ is_leaf = 0;++ for (i = 0; i < GIT_OID_HEXSZ; ++i) {+ int c = from_hex[(int)text_oid[i]];+ trie_node *node;++ if (c == -1)+ return GIT_ENOTOID;++ node = &os->nodes[idx];++ if (is_leaf) {+ const char *tail;++ tail = node->tail;+ node->tail = NULL;++ node = push_leaf(os, idx, from_hex[(int)tail[0]], &tail[1]);+ if (node == NULL)+ return GIT_ENOMEM;+ }++ if (node->children[c] == 0) {+ if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL)+ return GIT_ENOMEM;+ break;+ }++ idx = node->children[c];+ is_leaf = 0;++ if (idx < 0) {+ node->children[c] = idx = -idx;+ is_leaf = 1;+ }+ }++ if (++i > os->min_length)+ os->min_length = i;++ return os->min_length;+}+
+ libgit2/src/pqueue.c view
@@ -0,0 +1,157 @@+/*+ * BORING COPYRIGHT NOTICE:+ *+ * This file is a heavily modified version of the priority queue found+ * in the Apache project and the libpqueue library.+ *+ * https://github.com/vy/libpqueue+ *+ * These are the original authors:+ *+ * Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com>+ * Copyright 2006-2010 The Apache Software Foundation+ *+ * This file is licensed under the Apache 2.0 license, which + * supposedly makes it compatible with the GPLv2 that libgit2 uses.+ *+ * Check the Apache license at:+ *+ * http://www.apache.org/licenses/LICENSE-2.0+ *+ * So much licensing trouble for a binary heap. Oh well.+ */++#include "common.h"+#include "pqueue.h"++#define left(i) ((i) << 1)+#define right(i) (((i) << 1) + 1)+#define parent(i) ((i) >> 1)++int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri)+{+ assert(q);++ /* Need to allocate n+1 elements since element 0 isn't used. */+ if ((q->d = malloc((n + 1) * sizeof(void *))) == NULL)+ return GIT_ENOMEM;++ q->size = 1;+ q->avail = q->step = (n + 1); /* see comment above about n+1 */+ q->cmppri = cmppri;++ return GIT_SUCCESS;+}+++void git_pqueue_free(git_pqueue *q)+{+ free(q->d);+ q->d = NULL;+}++void git_pqueue_clear(git_pqueue *q)+{+ q->size = 1;+}++size_t git_pqueue_size(git_pqueue *q)+{+ /* queue element 0 exists but doesn't count since it isn't used. */+ return (q->size - 1);+}+++static void bubble_up(git_pqueue *q, size_t i)+{+ size_t parent_node;+ void *moving_node = q->d[i];++ for (parent_node = parent(i);+ ((i > 1) && q->cmppri(q->d[parent_node], moving_node));+ i = parent_node, parent_node = parent(i)) {+ q->d[i] = q->d[parent_node];+ }++ q->d[i] = moving_node;+}+++static size_t maxchild(git_pqueue *q, size_t i)+{+ size_t child_node = left(i);++ if (child_node >= q->size)+ return 0;++ if ((child_node + 1) < q->size &&+ q->cmppri(q->d[child_node], q->d[child_node + 1]))+ child_node++; /* use right child instead of left */++ return child_node;+}+++static void percolate_down(git_pqueue *q, size_t i)+{+ size_t child_node;+ void *moving_node = q->d[i];++ while ((child_node = maxchild(q, i)) != 0 &&+ q->cmppri(moving_node, q->d[child_node])) {+ q->d[i] = q->d[child_node];+ i = child_node;+ }++ q->d[i] = moving_node;+}+++int git_pqueue_insert(git_pqueue *q, void *d)+{+ void *tmp;+ size_t i;+ size_t newsize;++ if (!q) return 1;++ /* allocate more memory if necessary */+ if (q->size >= q->avail) {+ newsize = q->size + q->step;+ if ((tmp = realloc(q->d, sizeof(void *) * newsize)) == NULL)+ return GIT_ENOMEM;++ q->d = tmp;+ q->avail = newsize;+ }++ /* insert item */+ i = q->size++;+ q->d[i] = d;+ bubble_up(q, i);++ return GIT_SUCCESS;+}+++void *git_pqueue_pop(git_pqueue *q)+{+ void *head;++ if (!q || q->size == 1)+ return NULL;++ head = q->d[1];+ q->d[1] = q->d[--q->size];+ percolate_down(q, 1);++ return head;+}+++void *git_pqueue_peek(git_pqueue *q)+{+ if (!q || q->size == 1)+ return NULL;+ return q->d[1];+}
+ libgit2/src/pqueue.h view
@@ -0,0 +1,97 @@+/*+ * BORING COPYRIGHT NOTICE:+ *+ * This file is a heavily modified version of the priority queue found+ * in the Apache project and the libpqueue library.+ *+ * https://github.com/vy/libpqueue+ *+ * These are the original authors:+ *+ * Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com>+ * Copyright 2006-2010 The Apache Software Foundation+ *+ * This file is licensed under the Apache 2.0 license, which + * supposedly makes it compatible with the GPLv2 that libgit2 uses.+ *+ * Check the Apache license at:+ *+ * http://www.apache.org/licenses/LICENSE-2.0+ *+ * So much licensing trouble for a binary heap. Oh well.+ */++#ifndef INCLUDE_pqueue_h__+#define INCLUDE_pqueue_h__++/** callback functions to get/set/compare the priority of an element */+typedef int (*git_pqueue_cmp)(void *a, void *b);++/** the priority queue handle */+typedef struct {+ size_t size, avail, step;+ git_pqueue_cmp cmppri;+ void **d;+} git_pqueue;+++/**+ * initialize the queue+ *+ * @param n the initial estimate of the number of queue items for which memory+ * should be preallocated+ * @param cmppri the callback function to compare two nodes of the queue+ *+ * @Return the handle or NULL for insufficent memory+ */+int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri);+++/**+ * free all memory used by the queue+ * @param q the queue+ */+void git_pqueue_free(git_pqueue *q);++/**+ * clear all the elements in the queue+ * @param q the queue+ */+void git_pqueue_clear(git_pqueue *q);++/**+ * return the size of the queue.+ * @param q the queue+ */+size_t git_pqueue_size(git_pqueue *q);+++/**+ * insert an item into the queue.+ * @param q the queue+ * @param d the item+ * @return 0 on success+ */+int git_pqueue_insert(git_pqueue *q, void *d);+++/**+ * pop the highest-ranking item from the queue.+ * @param p the queue+ * @param d where to copy the entry to+ * @return NULL on error, otherwise the entry+ */+void *git_pqueue_pop(git_pqueue *q);+++/**+ * access highest-ranking item without removing it.+ * @param q the queue+ * @param d the entry+ * @return NULL on error, otherwise the entry+ */+void *git_pqueue_peek(git_pqueue *q);++#endif /* PQUEUE_H */+/** @} */+
+ libgit2/src/refs.c view
@@ -0,0 +1,1594 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "refs.h"+#include "hash.h"+#include "repository.h"+#include "fileops.h"++#include <git2/tag.h>+#include <git2/object.h>++#define MAX_NESTING_LEVEL 5++typedef struct {+ git_reference ref;+ git_oid oid;+ git_oid peel_target;+} reference_oid;++typedef struct {+ git_reference ref;+ char *target;+} reference_symbolic;++static const int default_table_size = 32;++static uint32_t reftable_hash(const void *key, int hash_id)+{+ static uint32_t hash_seeds[GIT_HASHTABLE_HASHES] = {+ 2147483647,+ 0x5d20bb23,+ 0x7daaab3c + };++ return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]);+}++static void reference_free(git_reference *reference);+static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type);+static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name);++/* loose refs */+static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content);+static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content);+static int loose_lookup(git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic);+static int loose_write(git_reference *ref);+static int loose_update(git_reference *ref);++/* packed refs */+static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end);+static int packed_parse_oid(reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end);+static int packed_load(git_repository *repo);+static int packed_loadloose(git_repository *repository);+static int packed_write_ref(reference_oid *ref, git_filebuf *file);+static int packed_find_peel(reference_oid *ref);+static int packed_remove_loose(git_repository *repo, git_vector *packing_list);+static int packed_sort(const void *a, const void *b);+static int packed_write(git_repository *repo);++/* name normalization */+static int check_valid_ref_char(char ch);+static int normalize_name(char *buffer_out, const char *name, int is_oid_ref);++/*****************************************+ * Internal methods - Constructor/destructor+ *****************************************/+static void reference_free(git_reference *reference)+{+ if (reference == NULL)+ return;++ if (reference->name)+ free(reference->name);++ if (reference->type == GIT_REF_SYMBOLIC)+ free(((reference_symbolic *)reference)->target);++ free(reference);+}++static int reference_create(+ git_reference **ref_out,+ git_repository *repo,+ const char *name,+ git_rtype type)+{+ char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];+ int error = GIT_SUCCESS, size;+ git_reference *reference = NULL;++ assert(ref_out && repo && name);++ if (type == GIT_REF_SYMBOLIC)+ size = sizeof(reference_symbolic);+ else if (type == GIT_REF_OID)+ size = sizeof(reference_oid);+ else+ return GIT_EINVALIDREFSTATE;++ reference = git__malloc(size);+ if (reference == NULL)+ return GIT_ENOMEM;++ memset(reference, 0x0, size);+ reference->owner = repo;+ reference->type = type;++ error = normalize_name(normalized, name, (type & GIT_REF_OID));+ if (error < GIT_SUCCESS)+ goto cleanup;++ reference->name = git__strdup(normalized);+ if (reference->name == NULL) {+ error = GIT_ENOMEM;+ goto cleanup;+ }++ *ref_out = reference;++ return error;++cleanup:+ reference_free(reference);+ return error;+}++static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name)+{+ struct stat st;+ char path[GIT_PATH_MAX];++ /* Determine the full path of the file */+ git__joinpath(path, repo_path, ref_name);++ if (gitfo_stat(path, &st) < 0)+ return GIT_ENOTFOUND;++ if (S_ISDIR(st.st_mode))+ return GIT_EOBJCORRUPTED;++ if (mtime)+ *mtime = st.st_mtime;++ if (file_content)+ return gitfo_read_file(file_content, path);++ return GIT_SUCCESS;+}+++++/*****************************************+ * Internal methods - Loose references+ *****************************************/+static int loose_update(git_reference *ref)+{+ int error;+ time_t ref_time;+ gitfo_buf ref_file = GITFO_BUF_INIT;++ if (ref->type & GIT_REF_PACKED)+ return packed_load(ref->owner);++ error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name);+ if (error < GIT_SUCCESS)+ goto cleanup;++ if (ref_time == ref->mtime)+ return GIT_SUCCESS;++ error = reference_read(&ref_file, &ref->mtime, ref->owner->path_repository, ref->name);+ if (error < GIT_SUCCESS)+ goto cleanup;++ if (ref->type == GIT_REF_SYMBOLIC)+ error = loose_parse_symbolic(ref, &ref_file);+ else if (ref->type == GIT_REF_OID)+ error = loose_parse_oid(ref, &ref_file);+ else+ error = GIT_EINVALIDREFSTATE;++ gitfo_free_buf(&ref_file);++cleanup:+ if (error != GIT_SUCCESS) {+ reference_free(ref);+ git_hashtable_remove(ref->owner->references.loose_cache, ref->name);+ }++ return error;+}++static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content)+{+ const unsigned int header_len = strlen(GIT_SYMREF);+ const char *refname_start;+ char *eol;+ reference_symbolic *ref_sym;++ refname_start = (const char *)file_content->data;+ ref_sym = (reference_symbolic *)ref;++ if (file_content->len < (header_len + 1))+ return GIT_EREFCORRUPTED;++ /* + * Assume we have already checked for the header+ * before calling this function + */++ refname_start += header_len;++ free(ref_sym->target);+ ref_sym->target = git__strdup(refname_start);+ if (ref_sym->target == NULL)+ return GIT_ENOMEM;++ /* remove newline at the end of file */+ eol = strchr(ref_sym->target, '\n');+ if (eol == NULL)+ return GIT_EREFCORRUPTED;++ *eol = '\0';+ if (eol[-1] == '\r')+ eol[-1] = '\0';++ return GIT_SUCCESS;+}++static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content)+{+ reference_oid *ref_oid;+ char *buffer;++ buffer = (char *)file_content->data;+ ref_oid = (reference_oid *)ref;++ /* File format: 40 chars (OID) + newline */+ if (file_content->len < GIT_OID_HEXSZ + 1)+ return GIT_EREFCORRUPTED;++ if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS)+ return GIT_EREFCORRUPTED;++ buffer = buffer + GIT_OID_HEXSZ;+ if (*buffer == '\r')+ buffer++;++ if (*buffer != '\n')+ return GIT_EREFCORRUPTED;++ return GIT_SUCCESS;+}+++static git_rtype loose_guess_rtype(const char *full_path)+{+ gitfo_buf ref_file = GITFO_BUF_INIT;+ git_rtype type;++ type = GIT_REF_INVALID;++ if (gitfo_read_file(&ref_file, full_path) == GIT_SUCCESS) {+ if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)+ type = GIT_REF_SYMBOLIC;+ else+ type = GIT_REF_OID;+ }++ gitfo_free_buf(&ref_file);+ return type;+}++static int loose_lookup(+ git_reference **ref_out, + git_repository *repo, + const char *name,+ int skip_symbolic)+{+ int error = GIT_SUCCESS;+ gitfo_buf ref_file = GITFO_BUF_INIT;+ git_reference *ref = NULL;+ time_t ref_time;++ *ref_out = NULL;++ error = reference_read(&ref_file, &ref_time, repo->path_repository, name);+ if (error < GIT_SUCCESS)+ goto cleanup;++ if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) {+ if (skip_symbolic)+ return GIT_SUCCESS;++ error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = loose_parse_symbolic(ref, &ref_file);+ } else {+ error = reference_create(&ref, repo, name, GIT_REF_OID);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = loose_parse_oid(ref, &ref_file);+ }++ if (error < GIT_SUCCESS)+ goto cleanup;++ ref->mtime = ref_time;+ *ref_out = ref;+ return GIT_SUCCESS;++cleanup:+ gitfo_free_buf(&ref_file);+ reference_free(ref);+ return error;+}++static int loose_write(git_reference *ref)+{+ git_filebuf file;+ char ref_path[GIT_PATH_MAX];+ int error, contents_size;+ char *ref_contents = NULL;+ struct stat st;++ assert((ref->type & GIT_REF_PACKED) == 0);++ git__joinpath(ref_path, ref->owner->path_repository, ref->name);++ if ((error = git_filebuf_open(&file, ref_path, GIT_FILEBUF_FORCE)) < GIT_SUCCESS)+ return error;++ if (ref->type & GIT_REF_OID) {+ reference_oid *ref_oid = (reference_oid *)ref;++ contents_size = GIT_OID_HEXSZ + 1;+ ref_contents = git__malloc(contents_size);+ if (ref_contents == NULL) {+ error = GIT_ENOMEM;+ goto unlock;+ }++ git_oid_fmt(ref_contents, &ref_oid->oid);++ } else if (ref->type & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */+ reference_symbolic *ref_sym = (reference_symbolic *)ref;++ contents_size = strlen(GIT_SYMREF) + strlen(ref_sym->target) + 1;+ ref_contents = git__malloc(contents_size);+ if (ref_contents == NULL) {+ error = GIT_ENOMEM;+ goto unlock;+ }++ strcpy(ref_contents, GIT_SYMREF);+ strcat(ref_contents, ref_sym->target);+ } else {+ error = GIT_EINVALIDREFSTATE;+ goto unlock;+ }++ /* TODO: win32 carriage return when writing references in Windows? */+ ref_contents[contents_size - 1] = '\n';++ if ((error = git_filebuf_write(&file, ref_contents, contents_size)) < GIT_SUCCESS)+ goto unlock;++ error = git_filebuf_commit(&file);++ if (gitfo_stat(ref_path, &st) == GIT_SUCCESS)+ ref->mtime = st.st_mtime;++ free(ref_contents);+ return error;++unlock:+ git_filebuf_cleanup(&file);+ free(ref_contents);+ return error;+}+++++++/*****************************************+ * Internal methods - Packed references+ *****************************************/++static int packed_parse_peel(+ reference_oid *tag_ref,+ const char **buffer_out, + const char *buffer_end)+{+ const char *buffer = *buffer_out + 1;++ assert(buffer[-1] == '^');++ /* Ensure it's not the first entry of the file */+ if (tag_ref == NULL)+ return GIT_EPACKEDREFSCORRUPTED;++ /* Ensure reference is a tag */+ if (git__prefixcmp(tag_ref->ref.name, GIT_REFS_TAGS_DIR) != 0)+ return GIT_EPACKEDREFSCORRUPTED;++ if (buffer + GIT_OID_HEXSZ >= buffer_end)+ return GIT_EPACKEDREFSCORRUPTED;++ /* Is this a valid object id? */+ if (git_oid_mkstr(&tag_ref->peel_target, buffer) < GIT_SUCCESS)+ return GIT_EPACKEDREFSCORRUPTED;++ buffer = buffer + GIT_OID_HEXSZ;+ if (*buffer == '\r')+ buffer++;++ if (*buffer != '\n')+ return GIT_EPACKEDREFSCORRUPTED;++ *buffer_out = buffer + 1;+ tag_ref->ref.type |= GIT_REF_HAS_PEEL;++ return GIT_SUCCESS;+}++static int packed_parse_oid(+ reference_oid **ref_out,+ git_repository *repo,+ const char **buffer_out,+ const char *buffer_end)+{+ reference_oid *ref = NULL;++ const char *buffer = *buffer_out;+ const char *refname_begin, *refname_end;++ int error = GIT_SUCCESS;+ int refname_len;+ char refname[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];+ git_oid id;++ refname_begin = (buffer + GIT_OID_HEXSZ + 1);+ if (refname_begin >= buffer_end ||+ refname_begin[-1] != ' ') {+ error = GIT_EPACKEDREFSCORRUPTED;+ goto cleanup;+ }++ /* Is this a valid object id? */+ if ((error = git_oid_mkstr(&id, buffer)) < GIT_SUCCESS)+ goto cleanup;++ refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin);+ if (refname_end == NULL) {+ error = GIT_EPACKEDREFSCORRUPTED;+ goto cleanup;+ }++ refname_len = refname_end - refname_begin;++ memcpy(refname, refname_begin, refname_len);+ refname[refname_len] = 0;++ if (refname[refname_len - 1] == '\r')+ refname[refname_len - 1] = 0;++ error = reference_create((git_reference **)&ref, repo, refname, GIT_REF_OID);+ if (error < GIT_SUCCESS)+ goto cleanup;++ git_oid_cpy(&ref->oid, &id);+ ref->ref.type |= GIT_REF_PACKED;++ *ref_out = ref;+ *buffer_out = refname_end + 1;++ return GIT_SUCCESS;++cleanup:+ reference_free((git_reference *)ref);+ return error;+}++static int packed_load(git_repository *repo)+{+ int error = GIT_SUCCESS;+ gitfo_buf packfile = GITFO_BUF_INIT;+ const char *buffer_start, *buffer_end;+ git_refcache *ref_cache = &repo->references;++ /* already loaded */+ if (repo->references.packfile != NULL) {+ time_t packed_time;++ /* check if we can read the time of the index;+ * if we can read it and it matches the time of the+ * index we had previously loaded, we don't need to do+ * anything else.+ *+ * if we cannot load the time (e.g. the packfile+ * has disappeared) or the time is different, we+ * have to reload the packfile */++ if (!reference_read(NULL, &packed_time, repo->path_repository, GIT_PACKEDREFS_FILE) &&+ packed_time == ref_cache->packfile_time)+ return GIT_SUCCESS;++ git_hashtable_clear(repo->references.packfile);+ } else {+ ref_cache->packfile = git_hashtable_alloc(+ default_table_size, + reftable_hash,+ (git_hash_keyeq_ptr)strcmp);++ if (ref_cache->packfile == NULL)+ return GIT_ENOMEM;+ }++ /* read the packfile from disk;+ * store its modification time to check for future reloads */+ error = reference_read(+ &packfile,+ &ref_cache->packfile_time,+ repo->path_repository,+ GIT_PACKEDREFS_FILE);++ /* there is no packfile on disk; that's ok */+ if (error == GIT_ENOTFOUND)+ return GIT_SUCCESS;++ if (error < GIT_SUCCESS)+ goto cleanup;++ buffer_start = (const char *)packfile.data;+ buffer_end = (const char *)(buffer_start) + packfile.len;++ while (buffer_start < buffer_end && buffer_start[0] == '#') {+ buffer_start = strchr(buffer_start, '\n');+ if (buffer_start == NULL) {+ error = GIT_EPACKEDREFSCORRUPTED;+ goto cleanup;+ }+ buffer_start++;+ }++ while (buffer_start < buffer_end) {+ reference_oid *ref = NULL;++ error = packed_parse_oid(&ref, repo, &buffer_start, buffer_end);+ if (error < GIT_SUCCESS)+ goto cleanup;++ if (buffer_start[0] == '^') {+ error = packed_parse_peel(ref, &buffer_start, buffer_end);+ if (error < GIT_SUCCESS)+ goto cleanup;+ }++ error = git_hashtable_insert(ref_cache->packfile, ref->ref.name, ref);+ if (error < GIT_SUCCESS) {+ reference_free((git_reference *)ref);+ goto cleanup;+ }+ }++ gitfo_free_buf(&packfile);+ return GIT_SUCCESS;++cleanup:+ git_hashtable_free(ref_cache->packfile);+ ref_cache->packfile = NULL;+ gitfo_free_buf(&packfile);+ return error;+}+++++struct dirent_list_data {+ git_vector ref_list;+ git_repository *repo;+ size_t repo_path_len;+ unsigned int list_flags;+};++static int _dirent_loose_listall(void *_data, char *full_path)+{+ struct dirent_list_data *data = (struct dirent_list_data *)_data;+ char *file_path = full_path + data->repo_path_len;++ if (gitfo_isdir(full_path) == GIT_SUCCESS)+ return gitfo_dirent(full_path, GIT_PATH_MAX, _dirent_loose_listall, _data);++ /* do not add twice a reference that exists already in the packfile */+ if ((data->list_flags & GIT_REF_PACKED) != 0 &&+ git_hashtable_lookup(data->repo->references.packfile, file_path) != NULL)+ return GIT_SUCCESS;++ if ((data->list_flags & loose_guess_rtype(full_path)) == 0)+ return GIT_SUCCESS; /* we are filtering out this reference */++ return git_vector_insert(&data->ref_list, git__strdup(file_path));+}++static int _dirent_loose_load(void *data, char *full_path)+{+ git_repository *repository = (git_repository *)data;+ git_reference *reference, *old_ref;+ char *file_path;+ int error;++ if (gitfo_isdir(full_path) == GIT_SUCCESS)+ return gitfo_dirent(full_path, GIT_PATH_MAX, _dirent_loose_load, repository);++ file_path = full_path + strlen(repository->path_repository);+ error = loose_lookup(&reference, repository, file_path, 1);+ if (error == GIT_SUCCESS && reference != NULL) {+ reference->type |= GIT_REF_PACKED;++ if (git_hashtable_insert2(repository->references.packfile, reference->name, reference, (void **)&old_ref) < GIT_SUCCESS) {+ reference_free(reference);+ return GIT_ENOMEM;+ }++ if (old_ref != NULL)+ reference_free(old_ref);+ }++ return error;+}++/*+ * Load all the loose references from the repository+ * into the in-memory Packfile, and build a vector with+ * all the references so it can be written back to+ * disk.+ */+static int packed_loadloose(git_repository *repository)+{+ char refs_path[GIT_PATH_MAX];++ /* the packfile must have been previously loaded! */+ assert(repository->references.packfile);++ git__joinpath(refs_path, repository->path_repository, GIT_REFS_DIR);++ /* Remove any loose references from the cache */+ {+ const void *_unused;+ git_reference *reference;++ GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference,+ reference_free(reference);+ );+ }++ git_hashtable_clear(repository->references.loose_cache);++ /*+ * Load all the loose files from disk into the Packfile table.+ * This will overwrite any old packed entries with their+ * updated loose versions + */+ return gitfo_dirent(refs_path, GIT_PATH_MAX, _dirent_loose_load, repository);+}++/*+ * Write a single reference into a packfile+ */+static int packed_write_ref(reference_oid *ref, git_filebuf *file)+{+ int error;+ char oid[GIT_OID_HEXSZ + 1];++ git_oid_fmt(oid, &ref->oid);+ oid[GIT_OID_HEXSZ] = 0;++ /* + * For references that peel to an object in the repo, we must+ * write the resulting peel on a separate line, e.g.+ *+ * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4+ * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100+ *+ * This obviously only applies to tags.+ * The required peels have already been loaded into `ref->peel_target`.+ */+ if (ref->ref.type & GIT_REF_HAS_PEEL) {+ char peel[GIT_OID_HEXSZ + 1];+ git_oid_fmt(peel, &ref->peel_target);+ peel[GIT_OID_HEXSZ] = 0;++ error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->ref.name, peel);+ } else {+ error = git_filebuf_printf(file, "%s %s\n", oid, ref->ref.name);+ }++ return error;+}++/*+ * Find out what object this reference resolves to.+ *+ * For references that point to a 'big' tag (e.g. an + * actual tag object on the repository), we need to+ * cache on the packfile the OID of the object to+ * which that 'big tag' is pointing to.+ */+static int packed_find_peel(reference_oid *ref)+{+ git_tag *tag;+ int error;++ if (ref->ref.type & GIT_REF_HAS_PEEL)+ return GIT_SUCCESS;++ /*+ * Only applies to tags, i.e. references+ * in the /refs/tags folder+ */+ if (git__prefixcmp(ref->ref.name, GIT_REFS_TAGS_DIR) != 0)+ return GIT_SUCCESS;++ /*+ * Find the tag in the repository. The tag must exist,+ * otherwise this reference is broken and we shouldn't+ * pack it.+ */+ error = git_tag_lookup(&tag, ref->ref.owner, &ref->oid);+ if (error < GIT_SUCCESS)+ return GIT_EOBJCORRUPTED;++ /*+ * Find the object pointed at by this tag+ */+ git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag));+ ref->ref.type |= GIT_REF_HAS_PEEL;++ /* + * The reference has now cached the resolved OID, and is+ * marked at such. When written to the packfile, it'll be+ * accompanied by this resolved oid+ */++ return GIT_SUCCESS;+}++/*+ * Remove all loose references+ *+ * Once we have successfully written a packfile,+ * all the loose references that were packed must be+ * removed from disk.+ *+ * This is a dangerous method; make sure the packfile+ * is well-written, because we are destructing references+ * here otherwise.+ */+static int packed_remove_loose(git_repository *repo, git_vector *packing_list)+{+ unsigned int i;+ char full_path[GIT_PATH_MAX];+ int error = GIT_SUCCESS;+ git_reference *reference;++ for (i = 0; i < packing_list->length; ++i) {+ git_reference *ref = git_vector_get(packing_list, i);++ /* Ensure the packed reference doesn't exist+ * in a (more up-to-date?) state as a loose reference+ */+ reference = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name);+ if (reference != NULL)+ continue;++ git__joinpath(full_path, repo->path_repository, ref->name);++ if (gitfo_exists(full_path) == GIT_SUCCESS &&+ gitfo_unlink(full_path) < GIT_SUCCESS)+ error = GIT_EOSERR;++ /*+ * if we fail to remove a single file, this is *not* good,+ * but we should keep going and remove as many as possible.+ * After we've removed as many files as possible, we return+ * the error code anyway.+ *+ * TODO: mark this with a very special error code?+ * GIT_EFAILTORMLOOSE+ */+ }++ return error;+}++static int packed_sort(const void *a, const void *b)+{+ const git_reference *ref_a = *(const git_reference **)a;+ const git_reference *ref_b = *(const git_reference **)b;++ return strcmp(ref_a->name, ref_b->name);+}++/*+ * Write all the contents in the in-memory packfile to disk.+ */+static int packed_write(git_repository *repo)+{+ git_filebuf pack_file;+ int error;+ unsigned int i;+ char pack_file_path[GIT_PATH_MAX];++ git_vector packing_list;+ size_t total_refs;++ assert(repo && repo->references.packfile);++ total_refs = repo->references.packfile->key_count;+ if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)+ return error;++ /* Load all the packfile into a vector */+ {+ git_reference *reference;+ const void *_unused;++ GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference,+ git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */+ );+ }++ /* sort the vector so the entries appear sorted on the packfile */+ git_vector_sort(&packing_list);++ /* Now we can open the file! */+ git__joinpath(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);+ if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS)+ return error;++ /* Packfiles have a header... apparently+ * This is in fact not required, but we might as well print it+ * just for kicks */+ if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)+ return error;++ for (i = 0; i < packing_list.length; ++i) {+ reference_oid *ref = (reference_oid *)git_vector_get(&packing_list, i);++ /* only direct references go to the packfile; otherwise+ * this is a disaster */+ assert(ref->ref.type & GIT_REF_OID);++ if ((error = packed_find_peel(ref)) < GIT_SUCCESS)+ goto cleanup;++ if ((error = packed_write_ref(ref, &pack_file)) < GIT_SUCCESS)+ goto cleanup;+ }++cleanup:+ /* if we've written all the references properly, we can commit+ * the packfile to make the changes effective */+ if (error == GIT_SUCCESS) {+ error = git_filebuf_commit(&pack_file);++ /* when and only when the packfile has been properly written,+ * we can go ahead and remove the loose refs */+ if (error == GIT_SUCCESS) {+ struct stat st;++ error = packed_remove_loose(repo, &packing_list);++ if (gitfo_stat(pack_file_path, &st) == GIT_SUCCESS)+ repo->references.packfile_time = st.st_mtime;+ }+ }+ else git_filebuf_cleanup(&pack_file);++ git_vector_free(&packing_list);++ return error;+}+++++/*****************************************+ * External Library API+ *****************************************/++/**+ * Constructors+ */+int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name)+{+ int error;+ char normalized_name[GIT_PATH_MAX];++ assert(ref_out && repo && name);++ *ref_out = NULL;++ error = normalize_name(normalized_name, name, 0);+ if (error < GIT_SUCCESS)+ return error;++ /* First, check has been previously loaded and cached */+ *ref_out = git_hashtable_lookup(repo->references.loose_cache, normalized_name);+ if (*ref_out != NULL)+ return loose_update(*ref_out);++ /* Then check if there is a loose file for that reference.*/+ error = loose_lookup(ref_out, repo, normalized_name, 0);++ /* If the file exists, we store it on the cache */+ if (error == GIT_SUCCESS)+ return git_hashtable_insert(repo->references.loose_cache, (*ref_out)->name, (*ref_out));++ /* The loose lookup has failed, but not because the reference wasn't found;+ * probably the loose reference is corrupted. this is bad. */+ if (error != GIT_ENOTFOUND)+ return error;++ /*+ * If we cannot find a loose reference, we look into the packfile+ * Load the packfile first if it hasn't been loaded + */+ /* load all the packed references */+ error = packed_load(repo);+ if (error < GIT_SUCCESS)+ return error;++ /* Look up on the packfile */+ *ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name);+ if (*ref_out != NULL)+ return GIT_SUCCESS;++ /* The reference doesn't exist anywhere */+ return GIT_ENOTFOUND;+}++int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target)+{+ char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];+ int error = GIT_SUCCESS;+ git_reference *ref = NULL;++ error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* The target can aither be the name of an object id reference or the name of another symbolic reference */+ error = normalize_name(normalized, target, 0);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* set the target; this will write the reference on disk */+ error = git_reference_set_target(ref, normalized);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref);+ if (error < GIT_SUCCESS)+ goto cleanup;++ *ref_out = ref;++ return error;++cleanup:+ reference_free(ref);+ return error;+}++int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id)+{+ int error = GIT_SUCCESS;+ git_reference *ref = NULL;++ error = reference_create(&ref, repo, name, GIT_REF_OID);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* set the oid; this will write the reference on disk */+ error = git_reference_set_oid(ref, id);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref);+ if (error < GIT_SUCCESS)+ goto cleanup;++ *ref_out = ref;++ return error;++cleanup:+ reference_free(ref);+ return error;+}+++/**+ * Getters+ */+git_rtype git_reference_type(git_reference *ref)+{+ assert(ref);++ if (ref->type & GIT_REF_OID)+ return GIT_REF_OID;++ if (ref->type & GIT_REF_SYMBOLIC)+ return GIT_REF_SYMBOLIC;++ return GIT_REF_INVALID;+}++const char *git_reference_name(git_reference *ref)+{+ assert(ref);+ return ref->name;+}++git_repository *git_reference_owner(git_reference *ref)+{+ assert(ref);+ return ref->owner;+}++const git_oid *git_reference_oid(git_reference *ref)+{+ assert(ref);++ if ((ref->type & GIT_REF_OID) == 0)+ return NULL;++ if (loose_update(ref) < GIT_SUCCESS)+ return NULL;++ return &((reference_oid *)ref)->oid;+}++const char *git_reference_target(git_reference *ref)+{+ assert(ref);++ if ((ref->type & GIT_REF_SYMBOLIC) == 0)+ return NULL;++ if (loose_update(ref) < GIT_SUCCESS)+ return NULL;++ return ((reference_symbolic *)ref)->target;+}++/**+ * Setters+ */++/*+ * Change the OID target of a reference.+ *+ * For loose references, just change the oid in memory+ * and overwrite the file in disk.+ *+ * For packed files, this is not pretty:+ * For performance reasons, we write the new reference+ * loose on disk (it replaces the old on the packfile),+ * but we cannot invalidate the pointer to the reference,+ * and most importantly, the `packfile` object must stay+ * consistent with the representation of the packfile+ * on disk. This is what we need to:+ *+ * 1. Copy the reference+ * 2. Change the oid on the original+ * 3. Write the original to disk+ * 4. Write the original to the loose cache+ * 5. Replace the original with the copy (old reference) in the packfile cache+ */+int git_reference_set_oid(git_reference *ref, const git_oid *id)+{+ reference_oid *ref_oid;+ reference_oid *ref_old = NULL;+ int error = GIT_SUCCESS;++ if ((ref->type & GIT_REF_OID) == 0)+ return GIT_EINVALIDREFSTATE;++ ref_oid = (reference_oid *)ref;++ /* duplicate the reference;+ * this copy will stay on the packfile cache */+ if (ref->type & GIT_REF_PACKED) {+ ref_old = git__malloc(sizeof(reference_oid));+ if (ref_old == NULL)+ return GIT_ENOMEM;++ ref_old->ref.name = git__strdup(ref->name);+ if (ref_old->ref.name == NULL) {+ free(ref_old);+ return GIT_ENOMEM;+ }+ }++ git_oid_cpy(&ref_oid->oid, id);+ ref->type &= ~GIT_REF_HAS_PEEL;++ error = loose_write(ref); + if (error < GIT_SUCCESS)+ goto cleanup;++ if (ref->type & GIT_REF_PACKED) {+ /* insert the original on the loose cache */+ error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref);+ if (error < GIT_SUCCESS)+ goto cleanup;++ ref->type &= ~GIT_REF_PACKED;++ /* replace the original in the packfile with the copy */+ error = git_hashtable_insert(ref->owner->references.packfile, ref_old->ref.name, ref_old);+ if (error < GIT_SUCCESS)+ goto cleanup;+ }++ return GIT_SUCCESS;++cleanup:+ reference_free((git_reference *)ref_old);+ return error;+}++/*+ * Change the target of a symbolic reference.+ *+ * This is easy because symrefs cannot be inside+ * a pack. We just change the target in memory+ * and overwrite the file on disk.+ */+int git_reference_set_target(git_reference *ref, const char *target)+{+ reference_symbolic *ref_sym;++ if ((ref->type & GIT_REF_SYMBOLIC) == 0)+ return GIT_EINVALIDREFSTATE;++ ref_sym = (reference_symbolic *)ref;++ free(ref_sym->target);+ ref_sym->target = git__strdup(target);+ if (ref_sym->target == NULL)+ return GIT_ENOMEM;++ return loose_write(ref);+}++/**+ * Other+ */++/*+ * Delete a reference.+ *+ * If the reference is packed, this is an expensive+ * operation. We need to remove the reference from+ * the memory cache and then rewrite the whole pack+ *+ * If the reference is loose, we remove it on+ * the filesystem and update the in-memory cache+ * accordingly. We also make sure that an older version+ * of it doesn't exist as a packed reference. If this+ * is the case, this packed reference is removed as well.+ *+ * This obviously invalidates the `ref` pointer.+ */+int git_reference_delete(git_reference *ref)+{+ int error;+ git_reference *reference;++ assert(ref);++ if (ref->type & GIT_REF_PACKED) {+ git_hashtable_remove(ref->owner->references.packfile, ref->name);+ error = packed_write(ref->owner);+ } else {+ char full_path[GIT_PATH_MAX];+ git__joinpath(full_path, ref->owner->path_repository, ref->name);+ git_hashtable_remove(ref->owner->references.loose_cache, ref->name);+ error = gitfo_unlink(full_path);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* When deleting a loose reference, we have to ensure that an older+ * packed version of it doesn't exist+ */+ if (!git_reference_lookup(&reference, ref->owner, ref->name)) {+ assert((reference->type & GIT_REF_PACKED) != 0);+ error = git_reference_delete(reference);+ }+ }++cleanup:+ reference_free(ref);+ return error;+}++/*+ * Rename a reference+ *+ * If the reference is packed, we need to rewrite the+ * packfile to remove the reference from it and create+ * the reference back as a loose one.+ *+ * If the reference is loose, we just rename it on+ * the filesystem.+ *+ * We also need to re-insert the reference on its corresponding+ * in-memory cache, since the caches are indexed by refname.+ */+int git_reference_rename(git_reference *ref, const char *new_name)+{+ int error;+ char *old_name;+ char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];+ git_reference *looked_up_ref;++ assert(ref);++ /* Ensure the name is valid */+ error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID);+ if (error < GIT_SUCCESS)+ return error;++ /* Ensure we're not going to overwrite an existing reference */+ error = git_reference_lookup(&looked_up_ref, ref->owner, new_name);+ if (error == GIT_SUCCESS)+ return GIT_EINVALIDREFNAME;++ if (error != GIT_ENOTFOUND)+ return error;+++ old_name = ref->name;+ ref->name = git__strdup(new_name);++ if (ref->name == NULL) {+ ref->name = old_name;+ return GIT_ENOMEM;+ }++ if (ref->type & GIT_REF_PACKED) {+ /* write the packfile to disk; note+ * that the state of the in-memory cache is not+ * consistent, because the reference is indexed+ * by its old name but it already has the new one.+ * This doesn't affect writing, though, and allows+ * us to rollback if writing fails+ */++ ref->type &= ~GIT_REF_PACKED;++ /* Create the loose ref under its new name */+ error = loose_write(ref);+ if (error < GIT_SUCCESS) {+ ref->type |= GIT_REF_PACKED;+ goto cleanup;+ }++ /* Remove from the packfile cache in order to avoid packing it back+ * Note : we do not rely on git_reference_delete() because this would+ * invalidate the reference.+ */+ git_hashtable_remove(ref->owner->references.packfile, old_name);++ /* Recreate the packed-refs file without the reference */+ error = packed_write(ref->owner);+ if (error < GIT_SUCCESS)+ goto rename_loose_to_old_name;++ } else {+ git__joinpath(old_path, ref->owner->path_repository, old_name);+ git__joinpath(new_path, ref->owner->path_repository, ref->name);++ error = gitfo_mv_force(old_path, new_path);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* Once succesfully renamed, remove from the cache the reference known by its old name*/+ git_hashtable_remove(ref->owner->references.loose_cache, old_name);+ }++ /* Store the renamed reference into the loose ref cache */+ error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref);++ free(old_name);+ return error;++cleanup:+ /* restore the old name if this failed */+ free(ref->name);+ ref->name = old_name;+ return error;++rename_loose_to_old_name:+ /* If we hit this point. Something *bad* happened! Think "Ghostbusters+ * crossing the streams" definition of bad.+ * Either the packed-refs has been correctly generated and something else+ * has gone wrong, or the writing of the new packed-refs has failed, and+ * we're stuck with the old one. As a loose ref always takes priority over+ * a packed ref, we'll eventually try and rename the generated loose ref to+ * its former name. It even that fails, well... we might have lost the reference+ * for good. :-/+ */++ git__joinpath(old_path, ref->owner->path_repository, ref->name);+ git__joinpath(new_path, ref->owner->path_repository, old_name);++ /* No error checking. We'll return the initial error */+ gitfo_mv_force(old_path, new_path);++ /* restore the old name */+ free(ref->name);+ ref->name = old_name;++ return error;+}++int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)+{+ git_repository *repo;+ int error, i;++ assert(resolved_ref && ref);+ *resolved_ref = NULL;++ if ((error = loose_update(ref)) < GIT_SUCCESS)+ return error;+ + repo = ref->owner;++ for (i = 0; i < MAX_NESTING_LEVEL; ++i) {+ reference_symbolic *ref_sym;++ if (ref->type & GIT_REF_OID) {+ *resolved_ref = ref;+ return GIT_SUCCESS;+ }++ ref_sym = (reference_symbolic *)ref;+ if ((error = git_reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS)+ return error;+ }++ return GIT_ETOONESTEDSYMREF;+}++int git_reference_packall(git_repository *repo)+{+ int error;++ /* load the existing packfile */+ if ((error = packed_load(repo)) < GIT_SUCCESS)+ return error;++ /* update it in-memory with all the loose references */+ if ((error = packed_loadloose(repo)) < GIT_SUCCESS)+ return error;++ /* write it back to disk */+ return packed_write(repo);+}++int git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags)+{+ int error;+ struct dirent_list_data data;+ char refs_path[GIT_PATH_MAX];++ array->strings = NULL;+ array->count = 0;++ git_vector_init(&data.ref_list, 8, NULL);+ data.repo_path_len = strlen(repo->path_repository);+ data.list_flags = list_flags;+ data.repo = repo;++ /* list all the packed references first */+ if (list_flags & GIT_REF_PACKED) {+ const char *ref_name;+ void *_unused;++ if ((error = packed_load(repo)) < GIT_SUCCESS) {+ git_vector_free(&data.ref_list);+ return error;+ }++ GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused,+ git_vector_insert(&data.ref_list, git__strdup(ref_name));+ );+ }++ /* now list the loose references, trying not to+ * duplicate the ref names already in the packed-refs file */+ git__joinpath(refs_path, repo->path_repository, GIT_REFS_DIR);+ error = gitfo_dirent(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data);++ if (error < GIT_SUCCESS) {+ git_vector_free(&data.ref_list);+ return error;+ }++ array->strings = (char **)data.ref_list.contents;+ array->count = data.ref_list.length;+ return GIT_SUCCESS;+}+++++/*****************************************+ * Init/free (repository API)+ *****************************************/+int git_repository__refcache_init(git_refcache *refs)+{+ assert(refs);++ refs->loose_cache = git_hashtable_alloc(+ default_table_size,+ reftable_hash,+ (git_hash_keyeq_ptr)strcmp);++ /* packfile loaded lazily */+ refs->packfile = NULL;++ return (refs->loose_cache) ? GIT_SUCCESS : GIT_ENOMEM;+}++void git_repository__refcache_free(git_refcache *refs)+{+ git_reference *reference;+ const void *_unused;++ assert(refs);++ GIT_HASHTABLE_FOREACH(refs->loose_cache, _unused, reference,+ reference_free(reference);+ );++ git_hashtable_free(refs->loose_cache);++ if (refs->packfile) {+ GIT_HASHTABLE_FOREACH(refs->packfile, _unused, reference,+ reference_free(reference);+ );++ git_hashtable_free(refs->packfile);+ }+}++++/*****************************************+ * Name normalization+ *****************************************/+static int check_valid_ref_char(char ch)+{+ if (ch <= ' ')+ return GIT_ERROR;++ switch (ch) {+ case '~':+ case '^':+ case ':':+ case '\\':+ case '?':+ case '[':+ case '*':+ return GIT_ERROR;+ break;++ default:+ return GIT_SUCCESS;+ }+}++static int normalize_name(char *buffer_out, const char *name, int is_oid_ref)+{+ int error = GIT_SUCCESS;+ const char *name_end, *buffer_out_start;+ char *current;+ int contains_a_slash = 0;++ assert(name && buffer_out);++ buffer_out_start = buffer_out;+ current = (char *)name;+ name_end = name + strlen(name);++ /* A refname can not be empty */+ if (name_end == name)+ return GIT_EINVALIDREFNAME;++ /* A refname can not end with a dot or a slash */+ if (*(name_end - 1) == '.' || *(name_end - 1) == '/')+ return GIT_EINVALIDREFNAME;++ while (current < name_end) {+ if (check_valid_ref_char(*current))+ return GIT_EINVALIDREFNAME;++ if (buffer_out > buffer_out_start) {+ char prev = *(buffer_out - 1);++ /* A refname can not start with a dot nor contain a double dot */+ if (*current == '.' && ((prev == '.') || (prev == '/')))+ return GIT_EINVALIDREFNAME;++ /* '@{' is forbidden within a refname */+ if (*current == '{' && prev == '@')+ return GIT_EINVALIDREFNAME;++ /* Prevent multiple slashes from being added to the output */+ if (*current == '/' && prev == '/') {+ current++;+ continue;+ }+ }++ if (*current == '/')+ contains_a_slash = 1;++ *buffer_out++ = *current++;+ }++ /* Object id refname have to contain at least one slash */+ if (is_oid_ref && !contains_a_slash)+ return GIT_EINVALIDREFNAME;++ /* A refname can not end with ".lock" */+ if (!git__suffixcmp(name, GIT_FILELOCK_EXTENSION))+ return GIT_EINVALIDREFNAME;++ *buffer_out = '\0';++ /* For object id references, name has to start with refs/(heads|tags|remotes) */+ if (is_oid_ref && !(!git__prefixcmp(buffer_out_start, GIT_REFS_HEADS_DIR) ||+ !git__prefixcmp(buffer_out_start, GIT_REFS_TAGS_DIR) || !git__prefixcmp(buffer_out_start, GIT_REFS_REMOTES_DIR)))+ return GIT_EINVALIDREFNAME;++ return error;+}++int git_reference__normalize_name(char *buffer_out, const char *name)+{+ return normalize_name(buffer_out, name, 0);+}++int git_reference__normalize_name_oid(char *buffer_out, const char *name)+{+ return normalize_name(buffer_out, name, 1);+}++
+ libgit2/src/refs.h view
@@ -0,0 +1,42 @@+#ifndef INCLUDE_refs_h__+#define INCLUDE_refs_h__++#include "common.h"+#include "git2/oid.h"+#include "git2/refs.h"+#include "hashtable.h"++#define GIT_REFS_DIR "refs/"+#define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"+#define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"+#define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/"++#define GIT_SYMREF "ref: "+#define GIT_PACKEDREFS_FILE "packed-refs"+#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled "+#define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100++#define GIT_HEAD_FILE "HEAD"+#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"++struct git_reference {+ git_repository *owner;+ char *name;+ unsigned int type;+ time_t mtime;+};++typedef struct {+ git_hashtable *packfile;+ git_hashtable *loose_cache;+ time_t packfile_time;+} git_refcache;+++void git_repository__refcache_free(git_refcache *refs);+int git_repository__refcache_init(git_refcache *refs);++int git_reference__normalize_name(char *buffer_out, const char *name);+int git_reference__normalize_name_oid(char *buffer_out, const char *name);++#endif
+ libgit2/src/repository.c view
@@ -0,0 +1,541 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */+#include <stdarg.h>++#include "git2/object.h"++#include "common.h"+#include "repository.h"+#include "commit.h"+#include "tag.h"+#include "blob.h"+#include "fileops.h"++#include "refs.h"++#define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"+#define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"++#define GIT_BRANCH_MASTER "master"++static const int OBJECT_TABLE_SIZE = 32;++typedef struct {+ char *path_repository;+ unsigned is_bare:1, has_been_reinit:1;+} repo_init;++/*+ * Hash table methods+ *+ * Callbacks for the ODB cache, implemented+ * as a hash table+ */+static uint32_t object_table_hash(const void *key, int hash_id)+{+ uint32_t r;+ git_oid *id;++ id = (git_oid *)key;+ memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));+ return r;+}++/*+ * Git repository open methods+ *+ * Open a repository object from its path+ */+static int assign_repository_dirs(+ git_repository *repo,+ const char *git_dir,+ const char *git_object_directory,+ const char *git_index_file,+ const char *git_work_tree)+{+ char path_aux[GIT_PATH_MAX];+ size_t git_dir_path_len;+ int error = GIT_SUCCESS;++ assert(repo);++ if (git_dir == NULL)+ return GIT_ENOTFOUND;++ error = gitfo_prettify_dir_path(path_aux, git_dir);+ if (error < GIT_SUCCESS)+ return error;++ git_dir_path_len = strlen(path_aux);++ /* store GIT_DIR */+ repo->path_repository = git__strdup(path_aux);+ if (repo->path_repository == NULL)+ return GIT_ENOMEM;++ /* path to GIT_OBJECT_DIRECTORY */+ if (git_object_directory == NULL)+ git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);+ else {+ error = gitfo_prettify_dir_path(path_aux, git_object_directory);+ if (error < GIT_SUCCESS)+ return error;+ }++ /* Store GIT_OBJECT_DIRECTORY */+ repo->path_odb = git__strdup(path_aux);+ if (repo->path_odb == NULL)+ return GIT_ENOMEM;++ /* path to GIT_WORK_TREE */+ if (git_work_tree == NULL)+ repo->is_bare = 1;+ else {+ error = gitfo_prettify_dir_path(path_aux, git_work_tree);+ if (error < GIT_SUCCESS)+ return error;++ /* Store GIT_WORK_TREE */+ repo->path_workdir = git__strdup(path_aux);+ if (repo->path_workdir == NULL)+ return GIT_ENOMEM;++ /* Path to GIT_INDEX_FILE */+ if (git_index_file == NULL)+ git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);+ else {+ error = gitfo_prettify_file_path(path_aux, git_index_file);+ if (error < GIT_SUCCESS)+ return error;+ }++ /* store GIT_INDEX_FILE */+ repo->path_index = git__strdup(path_aux);+ if (repo->path_index == NULL)+ return GIT_ENOMEM;+ }+ + return GIT_SUCCESS;+}++static int check_repository_dirs(git_repository *repo)+{+ char path_aux[GIT_PATH_MAX];++ if (gitfo_isdir(repo->path_repository) < GIT_SUCCESS)+ return GIT_ENOTAREPO;++ /* Ensure GIT_OBJECT_DIRECTORY exists */+ if (gitfo_isdir(repo->path_odb) < GIT_SUCCESS)+ return GIT_ENOTAREPO;++ /* Ensure HEAD file exists */+ git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE);+ if (gitfo_exists(path_aux) < 0)+ return GIT_ENOTAREPO;++ return GIT_SUCCESS;+}++static int guess_repository_dirs(git_repository *repo, const char *repository_path)+{+ char buffer[GIT_PATH_MAX];+ const char *path_work_tree = NULL;++ /* Git directory name */+ if (git__basename_r(buffer, sizeof(buffer), repository_path) < 0)+ return GIT_EINVALIDPATH;++ if (strcmp(buffer, DOT_GIT) == 0) {+ /* Path to working dir */+ if (git__dirname_r(buffer, sizeof(buffer), repository_path) < 0)+ return GIT_EINVALIDPATH;+ path_work_tree = buffer;+ }++ return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);+}++static git_repository *repository_alloc()+{+ git_repository *repo = git__malloc(sizeof(git_repository));+ if (!repo)+ return NULL;++ memset(repo, 0x0, sizeof(git_repository));++ repo->objects = git_hashtable_alloc(+ OBJECT_TABLE_SIZE, + object_table_hash,+ (git_hash_keyeq_ptr)git_oid_cmp);++ if (repo->objects == NULL) { + free(repo);+ return NULL;+ }++ if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {+ git_hashtable_free(repo->objects);+ free(repo);+ return NULL;+ }++ if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) {+ git_hashtable_free(repo->objects);+ git_repository__refcache_free(&repo->references);+ free(repo);+ return NULL;+ }++ return repo;+}++static int init_odb(git_repository *repo)+{+ return git_odb_open(&repo->db, repo->path_odb);+}++int git_repository_open3(git_repository **repo_out,+ const char *git_dir,+ git_odb *object_database,+ const char *git_index_file,+ const char *git_work_tree)+{+ git_repository *repo;+ int error = GIT_SUCCESS;++ assert(repo_out);++ if (object_database == NULL)+ return GIT_ERROR;++ repo = repository_alloc();+ if (repo == NULL)+ return GIT_ENOMEM;++ error = assign_repository_dirs(repo, + git_dir, + NULL,+ git_index_file,+ git_work_tree);++ if (error < GIT_SUCCESS)+ goto cleanup;++ error = check_repository_dirs(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ repo->db = object_database;++ *repo_out = repo;+ return GIT_SUCCESS;++cleanup:+ git_repository_free(repo);+ return error;+}+++int git_repository_open2(git_repository **repo_out,+ const char *git_dir,+ const char *git_object_directory,+ const char *git_index_file,+ const char *git_work_tree)+{+ git_repository *repo;+ int error = GIT_SUCCESS;++ assert(repo_out);++ repo = repository_alloc();+ if (repo == NULL)+ return GIT_ENOMEM;++ error = assign_repository_dirs(repo,+ git_dir, + git_object_directory,+ git_index_file,+ git_work_tree);++ if (error < GIT_SUCCESS)+ goto cleanup;++ error = check_repository_dirs(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = init_odb(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ *repo_out = repo;+ return GIT_SUCCESS;++cleanup:+ git_repository_free(repo);+ return error;+}++int git_repository_open(git_repository **repo_out, const char *path)+{+ git_repository *repo;+ int error = GIT_SUCCESS;++ assert(repo_out && path);++ repo = repository_alloc();+ if (repo == NULL)+ return GIT_ENOMEM;++ error = guess_repository_dirs(repo, path);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = check_repository_dirs(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = init_odb(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ *repo_out = repo;+ return GIT_SUCCESS;++cleanup:+ git_repository_free(repo);+ return error;+}++int git_repository_gc(git_repository *repo)+{+ int collected = 0;+ git_object *object;+ const void *_unused;++ GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,+ if (object->can_free) {+ git_object__free(object);+ collected++;+ }+ );++ return collected;+}++void git_repository_free(git_repository *repo)+{+ git_object *object;+ const void *_unused;+ unsigned int i;++ if (repo == NULL)+ return;++ /* force free all the objects */+ GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,+ git_object__free(object);+ );++ for (i = 0; i < repo->memory_objects.length; ++i) {+ object = git_vector_get(&repo->memory_objects, i);+ git_object__free(object);+ }++ free(repo->path_workdir);+ free(repo->path_index);+ free(repo->path_repository);+ free(repo->path_odb);++ git_hashtable_free(repo->objects);+ git_vector_free(&repo->memory_objects);++ git_repository__refcache_free(&repo->references);++ if (repo->db != NULL)+ git_odb_close(repo->db);++ if (repo->index != NULL)+ git_index_free(repo->index);++ free(repo);+}++int git_repository_index(git_index **index_out, git_repository *repo)+{+ int error;++ assert(index_out && repo);++ if (repo->index == NULL) {+ error = git_index_open_inrepo(&repo->index, repo);+ if (error < GIT_SUCCESS)+ return error;++ assert(repo->index != NULL);+ }++ *index_out = repo->index;+ return GIT_SUCCESS;+}++git_odb *git_repository_database(git_repository *repo)+{+ assert(repo);+ return repo->db;+}++static int repo_init_reinit(repo_init *results)+{+ /* TODO: reinit the repository */+ results->has_been_reinit = 1;+ return GIT_SUCCESS;+}++static int repo_init_createhead(git_repository *repo)+{+ git_reference *head_reference;+ return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE);+}++static int repo_init_check_head_existence(char * repository_path)+{+ char temp_path[GIT_PATH_MAX];++ git__joinpath(temp_path, repository_path, GIT_HEAD_FILE);+ return gitfo_exists(temp_path);+}++static int repo_init_structure(repo_init *results)+{+ const int mode = 0755; /* or 0777 ? */++ char temp_path[GIT_PATH_MAX];+ char *git_dir = results->path_repository;++ if (gitfo_mkdir_recurs(git_dir, mode))+ return GIT_ERROR;++ /* Creates the '/objects/info/' directory */+ git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);+ if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS)+ return GIT_ERROR;++ /* Creates the '/objects/pack/' directory */+ git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);+ if (gitfo_mkdir(temp_path, mode))+ return GIT_ERROR;++ /* Creates the '/refs/heads/' directory */+ git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR);+ if (gitfo_mkdir_recurs(temp_path, mode))+ return GIT_ERROR;++ /* Creates the '/refs/tags/' directory */+ git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR);+ if (gitfo_mkdir(temp_path, mode))+ return GIT_ERROR;++ /* TODO: what's left? templates? */++ return GIT_SUCCESS;+}++static int repo_init_find_dir(repo_init *results, const char* path)+{+ char temp_path[GIT_PATH_MAX];+ int error = GIT_SUCCESS;++ error = gitfo_prettify_dir_path(temp_path, path);+ if (error < GIT_SUCCESS)+ return error;++ if (!results->is_bare) {+ git__joinpath(temp_path, temp_path, GIT_DIR);+ }++ results->path_repository = git__strdup(temp_path);+ if (results->path_repository == NULL)+ return GIT_ENOMEM;++ return GIT_SUCCESS;+}++int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)+{+ int error = GIT_SUCCESS;+ git_repository *repo = NULL;+ repo_init results;+ + assert(repo_out && path);++ results.path_repository = NULL;+ results.is_bare = is_bare;++ error = repo_init_find_dir(&results, path);+ if (error < GIT_SUCCESS)+ goto cleanup;++ if (!repo_init_check_head_existence(results.path_repository))+ return repo_init_reinit(&results);++ error = repo_init_structure(&results);+ if (error < GIT_SUCCESS)+ goto cleanup;++ repo = repository_alloc();+ if (repo == NULL) {+ error = GIT_ENOMEM;+ goto cleanup;+ }++ error = guess_repository_dirs(repo, results.path_repository);+ if (error < GIT_SUCCESS)+ goto cleanup;++ assert(repo->is_bare == is_bare);++ error = init_odb(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ error = repo_init_createhead(repo);+ if (error < GIT_SUCCESS)+ goto cleanup;++ /* should never fail */+ assert(check_repository_dirs(repo) == GIT_SUCCESS);++ free(results.path_repository);+ *repo_out = repo;+ return GIT_SUCCESS;++cleanup:+ free(results.path_repository);+ git_repository_free(repo);+ return error;+}+
+ libgit2/src/repository.h view
@@ -0,0 +1,65 @@+#ifndef INCLUDE_repository_h__+#define INCLUDE_repository_h__++#include "git2/common.h"+#include "git2/oid.h"+#include "git2/odb.h"+#include "git2/repository.h"+#include "git2/object.h"++#include "hashtable.h"+#include "index.h"+#include "refs.h"++#define DOT_GIT ".git"+#define GIT_DIR DOT_GIT "/"+#define GIT_OBJECTS_DIR "objects/"+#define GIT_INDEX_FILE "index"++typedef struct {+ git_rawobj raw;+ void *write_ptr;+ size_t written_bytes;+ int open:1;+} git_odb_source;++struct git_object {+ git_oid id;+ git_repository *repo;+ git_odb_source source;+ unsigned int lru;+ unsigned char in_memory, modified, can_free, _pad;+};++struct git_repository {+ git_odb *db;+ git_index *index;++ git_hashtable *objects;+ git_vector memory_objects;++ git_refcache references;++ char *path_repository;+ char *path_index;+ char *path_odb;+ char *path_workdir;++ unsigned is_bare:1;+ unsigned int lru_counter;+};++int git_object__source_open(git_object *object);+void git_object__source_close(git_object *object);++/* fully free the object; internal method, do not+ * export */+void git_object__free(git_object *object);++int git__source_printf(git_odb_source *source, const char *format, ...);+int git__source_write(git_odb_source *source, const void *bytes, size_t len);++int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);+int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid);++#endif
+ libgit2/src/revwalk.c view
@@ -0,0 +1,565 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "commit.h"+#include "hashtable.h"+#include "pqueue.h"++#include "git2/revwalk.h"++typedef struct commit_object {+ git_oid oid;+ uint32_t time;+ unsigned int seen:1,+ uninteresting:1,+ topo_delay:1,+ parsed:1;++ unsigned short in_degree;+ unsigned short out_degree;++ struct commit_object **parents;+} commit_object;++typedef struct commit_list {+ commit_object *item;+ struct commit_list *next;+} commit_list;++struct git_revwalk {+ git_repository *repo;++ git_hashtable *commits;++ commit_list *iterator_topo;+ commit_list *iterator_rand;+ commit_list *iterator_reverse;+ git_pqueue iterator_time;++ int (*get_next)(commit_object **, git_revwalk *);+ int (*enqueue)(git_revwalk *, commit_object *);++ git_vector memory_alloc;+ size_t chunk_size;++ unsigned walking:1;+ unsigned int sorting;+};++commit_list *commit_list_insert(commit_object *item, commit_list **list_p)+{+ commit_list *new_list = git__malloc(sizeof(commit_list));+ new_list->item = item;+ new_list->next = *list_p;+ *list_p = new_list;+ return new_list;+}++void commit_list_free(commit_list **list_p)+{+ commit_list *list = *list_p;++ while (list) {+ commit_list *temp = list;+ list = temp->next;+ free(temp);+ }++ *list_p = NULL;+}++commit_object *commit_list_pop(commit_list **stack)+{+ commit_list *top = *stack;+ commit_object *item = top ? top->item : NULL;++ if (top) {+ *stack = top->next;+ free(top);+ }+ return item;+}++static int commit_time_cmp(void *a, void *b)+{+ commit_object *commit_a = (commit_object *)a;+ commit_object *commit_b = (commit_object *)b;++ return (commit_a->time < commit_b->time);+}++static uint32_t object_table_hash(const void *key, int hash_id)+{+ uint32_t r;+ git_oid *id;++ id = (git_oid *)key;+ memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));+ return r;+}++#define COMMITS_PER_CHUNK 128+#define CHUNK_STEP 64+#define PARENTS_PER_COMMIT ((CHUNK_STEP - sizeof(commit_object)) / sizeof(commit_object *))++static int alloc_chunk(git_revwalk *walk)+{+ void *chunk;++ chunk = git__calloc(COMMITS_PER_CHUNK, CHUNK_STEP);+ if (chunk == NULL)+ return GIT_ENOMEM;++ walk->chunk_size = 0;+ return git_vector_insert(&walk->memory_alloc, chunk);+}++static commit_object *alloc_commit(git_revwalk *walk)+{+ unsigned char *chunk;++ if (walk->chunk_size == COMMITS_PER_CHUNK)+ alloc_chunk(walk);++ chunk = git_vector_get(&walk->memory_alloc, walk->memory_alloc.length - 1);+ chunk += (walk->chunk_size * CHUNK_STEP);+ walk->chunk_size++;++ return (commit_object *)chunk;+}++static commit_object **alloc_parents(commit_object *commit, size_t n_parents)+{+ if (n_parents <= PARENTS_PER_COMMIT)+ return (commit_object **)((unsigned char *)commit + sizeof(commit_object));++ return git__malloc(n_parents * sizeof(commit_object *));+}+++static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid)+{+ commit_object *commit;++ if ((commit = git_hashtable_lookup(walk->commits, oid)) != NULL)+ return commit;++ commit = alloc_commit(walk);+ if (commit == NULL)+ return NULL;++ git_oid_cpy(&commit->oid, oid);++ if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) {+ free(commit);+ return NULL;+ }++ return commit;+}++static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawobj *raw)+{+ const int parent_len = STRLEN("parent ") + GIT_OID_HEXSZ + 1;++ unsigned char *buffer = raw->data;+ unsigned char *buffer_end = buffer + raw->len;+ unsigned char *parents_start;++ int i, parents = 0;++ buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1;++ parents_start = buffer;+ while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", STRLEN("parent ")) == 0) {+ parents++;+ buffer += parent_len;+ }++ commit->parents = alloc_parents(commit, parents);+ if (commit->parents == NULL)+ return GIT_ENOMEM;++ buffer = parents_start;+ for (i = 0; i < parents; ++i) {+ git_oid oid;++ if (git_oid_mkstr(&oid, (char *)buffer + STRLEN("parent ")) < GIT_SUCCESS)+ return GIT_EOBJCORRUPTED;++ commit->parents[i] = commit_lookup(walk, &oid);+ if (commit->parents[i] == NULL)+ return GIT_ENOMEM;++ buffer += parent_len;+ }++ commit->out_degree = (unsigned short)parents;++ if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)+ return GIT_EOBJCORRUPTED;++ buffer = memchr(buffer, '>', buffer_end - buffer);+ if (buffer == NULL)+ return GIT_EOBJCORRUPTED;++ commit->time = strtol((char *)buffer + 2, NULL, 10);+ if (commit->time == 0)+ return GIT_EOBJCORRUPTED;++ commit->parsed = 1;+ return GIT_SUCCESS;+}++static int commit_parse(git_revwalk *walk, commit_object *commit)+{+ git_rawobj data;+ int error;++ if (commit->parsed)+ return GIT_SUCCESS;++ if ((error = git_odb_read(&data, walk->repo->db, &commit->oid)) < GIT_SUCCESS)+ return error;++ if (data.type != GIT_OBJ_COMMIT) {+ git_rawobj_close(&data);+ return GIT_EOBJTYPE;+ }++ error = commit_quick_parse(walk, commit, &data);+ git_rawobj_close(&data);+ return error;+}++static void mark_uninteresting(commit_object *commit)+{+ unsigned short i;+ assert(commit);++ commit->uninteresting = 1;++ for (i = 0; i < commit->out_degree; ++i)+ if (!commit->parents[i]->uninteresting)+ mark_uninteresting(commit->parents[i]);+}++static int process_commit(git_revwalk *walk, commit_object *commit)+{+ int error;++ if (commit->seen)+ return GIT_SUCCESS;++ commit->seen = 1;++ if ((error = commit_parse(walk, commit)) < GIT_SUCCESS)+ return error;++ if (commit->uninteresting)+ mark_uninteresting(commit);++ return walk->enqueue(walk, commit);+}++static int process_commit_parents(git_revwalk *walk, commit_object *commit)+{+ unsigned short i;+ int error = GIT_SUCCESS;++ for (i = 0; i < commit->out_degree && error == GIT_SUCCESS; ++i) {+ error = process_commit(walk, commit->parents[i]);+ }++ return error;+}++static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)+{+ commit_object *commit;++ commit = commit_lookup(walk, oid);+ if (commit == NULL)+ return GIT_ENOTFOUND;++ commit->uninteresting = uninteresting;++ return process_commit(walk, commit);+}++int git_revwalk_push(git_revwalk *walk, const git_oid *oid)+{+ assert(walk && oid);+ return push_commit(walk, oid, 0);+}++int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)+{+ assert(walk && oid);+ return push_commit(walk, oid, 1);+}++static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit)+{+ return git_pqueue_insert(&walk->iterator_time, commit);+}++static int revwalk_enqueue_unsorted(git_revwalk *walk, commit_object *commit)+{+ return commit_list_insert(commit, &walk->iterator_rand) ? GIT_SUCCESS : GIT_ENOMEM;+}++static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk)+{+ int error;+ commit_object *next;++ while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) {+ if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS)+ return error;++ if (!next->uninteresting) {+ *object_out = next;+ return GIT_SUCCESS;+ }+ }++ return GIT_EREVWALKOVER;+}++static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)+{+ int error;+ commit_object *next;++ while ((next = commit_list_pop(&walk->iterator_rand)) != NULL) {+ if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS)+ return error;++ if (!next->uninteresting) {+ *object_out = next;+ return GIT_SUCCESS;+ }+ }++ return GIT_EREVWALKOVER;+}++static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)+{+ commit_object *next;+ unsigned short i;++ for (;;) {+ next = commit_list_pop(&walk->iterator_topo);+ if (next == NULL)+ return GIT_EREVWALKOVER;++ if (next->in_degree > 0) {+ next->topo_delay = 1;+ continue;+ }++ for (i = 0; i < next->out_degree; ++i) {+ commit_object *parent = next->parents[i];++ if (--parent->in_degree == 0 && parent->topo_delay) {+ parent->topo_delay = 0;+ commit_list_insert(parent, &walk->iterator_topo);+ }+ }++ *object_out = next;+ return GIT_SUCCESS;+ }+}++static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk)+{+ *object_out = commit_list_pop(&walk->iterator_reverse);+ return *object_out ? GIT_SUCCESS : GIT_EREVWALKOVER;+}+++static int prepare_walk(git_revwalk *walk)+{+ int error;+ commit_object *next;++ if (walk->sorting & GIT_SORT_TOPOLOGICAL) {+ unsigned short i;++ while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) {+ for (i = 0; i < next->out_degree; ++i) {+ commit_object *parent = next->parents[i];+ parent->in_degree++;+ }++ commit_list_insert(next, &walk->iterator_topo);+ }++ if (error != GIT_EREVWALKOVER)+ return error;++ walk->get_next = &revwalk_next_toposort;+ }++ if (walk->sorting & GIT_SORT_REVERSE) {++ while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS)+ commit_list_insert(next, &walk->iterator_reverse);++ if (error != GIT_EREVWALKOVER)+ return error;++ walk->get_next = &revwalk_next_reverse;+ }++ walk->walking = 1;+ return GIT_SUCCESS;+}++++++int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)+{+ git_revwalk *walk;++ walk = git__malloc(sizeof(git_revwalk));+ if (walk == NULL)+ return GIT_ENOMEM;++ memset(walk, 0x0, sizeof(git_revwalk));++ walk->commits = git_hashtable_alloc(64,+ object_table_hash,+ (git_hash_keyeq_ptr)git_oid_cmp);++ if (walk->commits == NULL) {+ free(walk);+ return GIT_ENOMEM;+ }++ git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp);+ git_vector_init(&walk->memory_alloc, 8, NULL);+ alloc_chunk(walk);++ walk->get_next = &revwalk_next_unsorted;+ walk->enqueue = &revwalk_enqueue_unsorted;++ walk->repo = repo;++ *revwalk_out = walk;+ return GIT_SUCCESS;+}++void git_revwalk_free(git_revwalk *walk)+{+ unsigned int i;++ if (walk == NULL)+ return;++ git_revwalk_reset(walk);+ git_hashtable_free(walk->commits);+ git_pqueue_free(&walk->iterator_time);++ for (i = 0; i < walk->memory_alloc.length; ++i)+ free(git_vector_get(&walk->memory_alloc, i));++ git_vector_free(&walk->memory_alloc);+ free(walk);+}++git_repository *git_revwalk_repository(git_revwalk *walk)+{+ assert(walk);+ return walk->repo;+}++void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)+{+ assert(walk);++ if (walk->walking)+ git_revwalk_reset(walk);++ walk->sorting = sort_mode;++ if (walk->sorting & GIT_SORT_TIME) {+ walk->get_next = &revwalk_next_timesort;+ walk->enqueue = &revwalk_enqueue_timesort;+ } else {+ walk->get_next = &revwalk_next_unsorted;+ walk->enqueue = &revwalk_enqueue_unsorted;+ }+}++int git_revwalk_next(git_oid *oid, git_revwalk *walk)+{+ int error;+ commit_object *next;++ assert(walk && oid);++ if (!walk->walking) {+ if ((error = prepare_walk(walk)) < GIT_SUCCESS)+ return error;+ }++ error = walk->get_next(&next, walk);+ if (error < GIT_SUCCESS) {+ if (error == GIT_EREVWALKOVER)+ git_revwalk_reset(walk);+ return error;+ }++ git_oid_cpy(oid, &next->oid);+ return GIT_SUCCESS;+}++void git_revwalk_reset(git_revwalk *walk)+{+ const void *_unused;+ commit_object *commit;++ assert(walk);++ GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit,+ commit->seen = 0;+ commit->in_degree = 0;+ commit->topo_delay = 0;+ );++ git_pqueue_clear(&walk->iterator_time);+ commit_list_free(&walk->iterator_topo);+ commit_list_free(&walk->iterator_rand);+ commit_list_free(&walk->iterator_reverse);+ walk->walking = 0;+}+
+ libgit2/src/signature.c view
@@ -0,0 +1,199 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "signature.h"+#include "repository.h"+#include "git2/common.h"++void git_signature_free(git_signature *sig)+{+ if (sig == NULL)+ return;++ free(sig->name);+ free(sig->email);+ free(sig);+}++git_signature *git_signature_new(const char *name, const char *email, time_t time, int offset)+{+ git_signature *p = NULL;++ if ((p = git__malloc(sizeof(git_signature))) == NULL)+ goto cleanup;++ p->name = git__strdup(name);+ if (p->name == NULL)+ goto cleanup;++ p->email = git__strdup(email);+ if (p->email == NULL)+ goto cleanup;++ p->when.time = time;+ p->when.offset = offset;++ if (p->name == NULL || p->email == NULL)+ goto cleanup;++ return p;++cleanup:+ git_signature_free(p);+ return NULL;+}++git_signature *git_signature_dup(const git_signature *sig)+{+ return git_signature_new(sig->name, sig->email, sig->when.time, sig->when.offset);+}+++static int parse_timezone_offset(const char *buffer, int *offset_out)+{+ int offset, dec_offset;+ int mins, hours;++ const char* offset_start;+ char* offset_end;++ offset_start = buffer + 1;++ if (*offset_start == '\n') {+ *offset_out = 0;+ return GIT_SUCCESS;+ }++ if (offset_start[0] != '-' && offset_start[0] != '+')+ return GIT_EOBJCORRUPTED;++ dec_offset = strtol(offset_start + 1, &offset_end, 10);++ if (offset_end - offset_start != 5)+ return GIT_EOBJCORRUPTED;++ hours = dec_offset / 100;+ mins = dec_offset % 100;++ if (hours > 14) // see http://www.worldtimezone.com/faq.html + return GIT_EOBJCORRUPTED;++ if (mins > 59)+ return GIT_EOBJCORRUPTED;++ offset = (hours * 60) + mins;++ if (offset_start[0] == '-')+ offset *= -1;+ + *offset_out = offset;++ return GIT_SUCCESS;+}+++int git_signature__parse(git_signature *sig, char **buffer_out,+ const char *buffer_end, const char *header)+{+ const size_t header_len = strlen(header);++ int name_length, email_length;+ char *buffer = *buffer_out;+ char *line_end, *name_end, *email_end;+ int offset = 0;++ memset(sig, 0x0, sizeof(git_signature));++ line_end = memchr(buffer, '\n', buffer_end - buffer);+ if (!line_end)+ return GIT_EOBJCORRUPTED;++ if (buffer + (header_len + 1) > line_end)+ return GIT_EOBJCORRUPTED;++ if (memcmp(buffer, header, header_len) != 0)+ return GIT_EOBJCORRUPTED;++ buffer += header_len;++ /* Parse name */+ if ((name_end = memchr(buffer, '<', buffer_end - buffer)) == NULL)+ return GIT_EOBJCORRUPTED;++ name_length = name_end - buffer - 1;+ sig->name = git__malloc(name_length + 1);+ memcpy(sig->name, buffer, name_length);+ sig->name[name_length] = 0;+ buffer = name_end + 1;++ if (buffer >= line_end)+ return GIT_EOBJCORRUPTED;++ /* Parse email */+ if ((email_end = memchr(buffer, '>', buffer_end - buffer)) == NULL)+ return GIT_EOBJCORRUPTED;++ email_length = email_end - buffer;+ sig->email = git__malloc(email_length + 1);+ memcpy(sig->email, buffer, email_length);+ sig->email[email_length] = 0;+ buffer = email_end + 1;++ if (buffer >= line_end)+ return GIT_EOBJCORRUPTED;++ sig->when.time = strtol(buffer, &buffer, 10);++ if (sig->when.time == 0)+ return GIT_EOBJCORRUPTED;++ if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)+ return GIT_EOBJCORRUPTED;+ + sig->when.offset = offset;++ *buffer_out = (line_end + 1);+ return GIT_SUCCESS;+}++int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig)+{+ char sign;+ int offset, hours, mins;++ offset = sig->when.offset;+ sign = (sig->when.offset < 0) ? '-' : '+';+ + if (offset < 0)+ offset = -offset;++ hours = offset / 60;+ mins = offset % 60;++ return git__source_printf(src, "%s %s <%s> %u %c%02d%02d\n", header, sig->name, sig->email, (unsigned)sig->when.time, sign, hours, mins);+}++
+ libgit2/src/signature.h view
@@ -0,0 +1,12 @@+#ifndef INCLUDE_signature_h__+#define INCLUDE_signature_h__++#include "git2/common.h"+#include "git2/signature.h"+#include "repository.h"+#include <time.h>++int git_signature__parse(git_signature *sig, char **buffer_out, const char *buffer_end, const char *header);+int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig);++#endif
+ libgit2/src/t03-data.h view
@@ -0,0 +1,344 @@++typedef struct object_data {+ char *id; /* object id (sha1) */+ char *dir; /* object store (fan-out) directory name */+ char *file; /* object store filename */+} object_data;++static object_data commit = {+ "3d7f8a6af076c8c3f20071a8935cdbe8228594d1",+ "test-objects/3d",+ "test-objects/3d/7f8a6af076c8c3f20071a8935cdbe8228594d1",+};++static unsigned char commit_data[] = {+ 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66,+ 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35,+ 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38,+ 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32,+ 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33,+ 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75,+ 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55,+ 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61,+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78,+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,+ 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38,+ 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30,+ 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,+ 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20,+ 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,+ 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,+ 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,+ 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,+ 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,+ 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,+ 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65,+ 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f,+ 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d,+ 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68,+ 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f,+ 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,+ 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73,+ 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f,+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67,+ 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72,+ 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61,+ 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20,+ 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70,+ 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74,+ 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67,+ 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f,+ 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79,+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d,+ 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69,+ 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d,+ 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20,+ 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75,+ 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61,+ 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,+ 0x3e, 0x0a,+};++static git_rawobj commit_obj = {+ commit_data,+ sizeof(commit_data),+ GIT_OBJ_COMMIT+};++static object_data tree = {+ "dff2da90b254e1beb889d1f1f1288be1803782df",+ "test-objects/df",+ "test-objects/df/f2da90b254e1beb889d1f1f1288be1803782df",+};++static unsigned char tree_data[] = {+ 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f,+ 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79,+ 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b,+ 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31,+ 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f,+ 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86,+ 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8,+ 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31,+ 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77,+ 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b,+ 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd,+ 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30,+ 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72,+ 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1,+ 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a,+ 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91,+};++static git_rawobj tree_obj = {+ tree_data,+ sizeof(tree_data),+ GIT_OBJ_TREE+};++static object_data tag = {+ "09d373e1dfdc16b129ceec6dd649739911541e05",+ "test-objects/09",+ "test-objects/09/d373e1dfdc16b129ceec6dd649739911541e05",+};++static unsigned char tag_data[] = {+ 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33,+ 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66,+ 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66,+ 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39,+ 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32,+ 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a,+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d,+ 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20,+ 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74,+ 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20,+ 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,+ 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,+ 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,+ 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,+ 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,+ 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,+ 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20,+ 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74,+ 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63,+ 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65,+ 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30,+ 0x2e, 0x30, 0x2e, 0x31, 0x0a,+};++static git_rawobj tag_obj = {+ tag_data,+ sizeof(tag_data),+ GIT_OBJ_TAG+};++static object_data zero = {+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",+ "test-objects/e6",+ "test-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391",+};++static unsigned char zero_data[] = {+ 0x00 /* dummy data */+};++static git_rawobj zero_obj = {+ zero_data,+ 0,+ GIT_OBJ_BLOB+};++static object_data one = {+ "8b137891791fe96927ad78e64b0aad7bded08bdc",+ "test-objects/8b",+ "test-objects/8b/137891791fe96927ad78e64b0aad7bded08bdc",+};++static unsigned char one_data[] = {+ 0x0a,+};++static git_rawobj one_obj = {+ one_data,+ sizeof(one_data),+ GIT_OBJ_BLOB+};++static object_data two = {+ "78981922613b2afb6025042ff6bd878ac1994e85",+ "test-objects/78",+ "test-objects/78/981922613b2afb6025042ff6bd878ac1994e85",+};++static unsigned char two_data[] = {+ 0x61, 0x0a,+};++static git_rawobj two_obj = {+ two_data,+ sizeof(two_data),+ GIT_OBJ_BLOB+};++static object_data some = {+ "fd8430bc864cfcd5f10e5590f8a447e01b942bfe",+ "test-objects/fd",+ "test-objects/fd/8430bc864cfcd5f10e5590f8a447e01b942bfe",+};++static unsigned char some_data[] = {+ 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68,+ 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20,+ 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20,+ 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,+ 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61,+ 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74,+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69,+ 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72,+ 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a,+ 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e,+ 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,+ 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66,+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c,+ 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,+ 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61,+ 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,+ 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,+ 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,+ 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,+ 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,+ 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a,+ 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64,+ 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74,+ 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65,+ 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,+ 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,+ 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e,+ 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62,+ 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65,+ 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20,+ 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68,+ 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65,+ 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c,+ 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70,+ 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,+ 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e,+ 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,+ 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20,+ 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,+ 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,+ 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69,+ 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62,+ 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74,+ 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67,+ 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a,+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20,+ 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,+ 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65,+ 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61,+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69,+ 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e,+ 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69,+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a,+ 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20,+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65,+ 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,+ 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65,+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,+ 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72,+ 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,+ 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,+ 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65,+ 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63,+ 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20,+ 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c,+ 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f,+ 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d,+ 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,+ 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74,+ 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c,+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73,+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f,+ 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e,+ 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65,+ 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20,+ 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62,+ 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65,+ 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e,+ 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20,+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,+ 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73,+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64,+ 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,+ 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61,+ 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c,+ 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65,+ 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74,+ 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48,+ 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20,+ 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59,+ 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75,+ 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74,+ 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69,+ 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61,+ 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20,+ 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41,+ 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54,+ 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54,+ 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52,+ 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49,+ 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55,+ 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20,+ 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,+ 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47,+ 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50,+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69,+ 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f,+ 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64,+ 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a,+ 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f,+ 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,+ 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65,+ 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61,+ 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66,+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,+ 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67,+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68,+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,+ 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20,+ 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65,+ 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47,+ 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f,+ 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65,+ 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74,+ 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,+ 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,+ 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,+ 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20,+ 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e,+ 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c,+ 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46,+ 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a,+ 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c,+ 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31,+ 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20,+ 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f,+ 0x0a,+};++static git_rawobj some_obj = {+ some_data,+ sizeof(some_data),+ GIT_OBJ_BLOB+};
+ libgit2/src/tag.c view
@@ -0,0 +1,232 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "commit.h"+#include "tag.h"+#include "signature.h"+#include "git2/object.h"+#include "git2/repository.h"+#include "git2/signature.h"++void git_tag__free(git_tag *tag)+{+ git_signature_free(tag->tagger);+ free(tag->message);+ free(tag->tag_name);+ free(tag);+}++const git_oid *git_tag_id(git_tag *c)+{+ return git_object_id((git_object *)c);+}++int git_tag_target(git_object **target, git_tag *t)+{+ assert(t);+ return git_object_lookup(target, t->object.repo, &t->target, t->type);+}++const git_oid *git_tag_target_oid(git_tag *t)+{+ assert(t);+ return &t->target;+}++int git_tag_set_target(git_tag *tag, git_object *target)+{+ const git_oid *oid;++ assert(tag && target);++ if ((oid = git_object_id(target)) == NULL)+ return GIT_EMISSINGOBJDATA;++ tag->object.modified = 1;+ git_oid_cpy(&tag->target, oid);+ tag->type = git_object_type(target);+ return GIT_SUCCESS;+}++git_otype git_tag_type(git_tag *t)+{+ assert(t);+ return t->type;+}++const char *git_tag_name(git_tag *t)+{+ assert(t);+ return t->tag_name;+}++void git_tag_set_name(git_tag *tag, const char *name)+{+ assert(tag && name);++ tag->object.modified = 1;++ if (tag->tag_name)+ free(tag->tag_name);++ tag->tag_name = git__strdup(name);+}++const git_signature *git_tag_tagger(git_tag *t)+{+ return t->tagger;+}++void git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig)+{+ assert(tag && tagger_sig);+ tag->object.modified = 1;++ git_signature_free(tag->tagger);+ tag->tagger = git_signature_dup(tagger_sig);+}++const char *git_tag_message(git_tag *t)+{+ assert(t);+ return t->message;+}++void git_tag_set_message(git_tag *tag, const char *message)+{+ assert(tag && message);++ tag->object.modified = 1;++ if (tag->message)+ free(tag->message);++ tag->message = git__strdup(message);+}++static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)+{+ static const char *tag_types[] = {+ NULL, "commit\n", "tree\n", "blob\n", "tag\n"+ };++ unsigned int i, text_len;+ char *search;+ int error;++ if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)+ return error;++ if (buffer + 5 >= buffer_end)+ return GIT_EOBJCORRUPTED;++ if (memcmp(buffer, "type ", 5) != 0)+ return GIT_EOBJCORRUPTED;+ buffer += 5;++ tag->type = GIT_OBJ_BAD;++ for (i = 1; i < ARRAY_SIZE(tag_types); ++i) {+ size_t type_length = strlen(tag_types[i]);++ if (buffer + type_length >= buffer_end)+ return GIT_EOBJCORRUPTED;++ if (memcmp(buffer, tag_types[i], type_length) == 0) {+ tag->type = i;+ buffer += type_length;+ break;+ }+ }++ if (tag->type == GIT_OBJ_BAD)+ return GIT_EOBJCORRUPTED;++ if (buffer + 4 >= buffer_end)+ return GIT_EOBJCORRUPTED;++ if (memcmp(buffer, "tag ", 4) != 0)+ return GIT_EOBJCORRUPTED;+ buffer += 4;++ search = memchr(buffer, '\n', buffer_end - buffer);+ if (search == NULL)+ return GIT_EOBJCORRUPTED;++ text_len = search - buffer;++ if (tag->tag_name != NULL)+ free(tag->tag_name);++ tag->tag_name = git__malloc(text_len + 1);+ memcpy(tag->tag_name, buffer, text_len);+ tag->tag_name[text_len] = '\0';++ buffer = search + 1;++ if (tag->tagger != NULL)+ git_signature_free(tag->tagger);++ tag->tagger = git__malloc(sizeof(git_signature));++ if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0)+ return error;++ text_len = buffer_end - ++buffer;++ if (tag->message != NULL)+ free(tag->message);++ tag->message = git__malloc(text_len + 1);+ memcpy(tag->message, buffer, text_len);+ tag->message[text_len] = '\0';++ return GIT_SUCCESS;+}++int git_tag__writeback(git_tag *tag, git_odb_source *src)+{+ if (tag->tag_name == NULL || tag->tagger == NULL)+ return GIT_EMISSINGOBJDATA;++ git__write_oid(src, "object", &tag->target);+ git__source_printf(src, "type %s\n", git_object_type2string(tag->type));+ git__source_printf(src, "tag %s\n", tag->tag_name);+ git_signature__write(src, "tagger", tag->tagger);++ if (tag->message != NULL)+ git__source_printf(src, "\n%s", tag->message);++ return GIT_SUCCESS;+}+++int git_tag__parse(git_tag *tag)+{+ assert(tag && tag->object.source.open);+ return parse_tag_buffer(tag, tag->object.source.raw.data, (char *)tag->object.source.raw.data + tag->object.source.raw.len);+}+
+ libgit2/src/tag.h view
@@ -0,0 +1,22 @@+#ifndef INCLUDE_tag_h__+#define INCLUDE_tag_h__++#include "git2/tag.h"+#include "repository.h"++struct git_tag {+ git_object object;++ git_oid target;+ git_otype type;++ char *tag_name;+ git_signature *tagger;+ char *message;+};++void git_tag__free(git_tag *tag);+int git_tag__parse(git_tag *tag);+int git_tag__writeback(git_tag *tag, git_odb_source *src);++#endif
+ libgit2/src/thread-utils.c view
@@ -0,0 +1,49 @@+#include "common.h"+#include "thread-utils.h"++#ifdef _WIN32+# define WIN32_LEAN_AND_MEAN+# include <windows.h>+#elif defined(hpux) || defined(__hpux) || defined(_hpux)+# include <sys/pstat.h>+#endif++/*+ * By doing this in two steps we can at least get+ * the function to be somewhat coherent, even+ * with this disgusting nest of #ifdefs.+ */+#ifndef _SC_NPROCESSORS_ONLN+# ifdef _SC_NPROC_ONLN+# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN+# elif defined _SC_CRAY_NCPU+# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU+# endif+#endif++int git_online_cpus(void)+{+#ifdef _SC_NPROCESSORS_ONLN+ long ncpus;+#endif++#ifdef _WIN32+ SYSTEM_INFO info;+ GetSystemInfo(&info);++ if ((int)info.dwNumberOfProcessors > 0)+ return (int)info.dwNumberOfProcessors;+#elif defined(hpux) || defined(__hpux) || defined(_hpux)+ struct pst_dynamic psd;++ if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))+ return (int)psd.psd_proc_cnt;+#endif++#ifdef _SC_NPROCESSORS_ONLN+ if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)+ return (int)ncpus;+#endif++ return 1;+}
+ libgit2/src/thread-utils.h view
@@ -0,0 +1,28 @@+#ifndef INCLUDE_thread_utils_h__+#define INCLUDE_thread_utils_h__+++#define git_thread pthread_t+#define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)+#define git_thread_kill(thread) pthread_cancel(thread)+#define git_thread_exit(status) pthread_exit(status)+#define git_thread_join(id, status) pthread_join(id, status)++/* Pthreads Mutex */+#define git_mutex pthread_mutex_t+#define git_mutex_init(a) pthread_mutex_init(a, NULL)+#define git_mutex_lock(a) pthread_mutex_lock(a)+#define git_mutex_unlock(a) pthread_mutex_unlock(a)+#define git_mutex_free(a) pthread_mutex_destroy(a)++/* Pthreads condition vars */+#define git_cond pthread_cond_t+#define git_cond_init(c, a) pthread_cond_init(c, a)+#define git_cond_free(c) pthread_cond_destroy(c)+#define git_cond_wait(c, l) pthread_cond_wait(c, l)+#define git_cond_signal(c) pthread_cond_signal(c)+#define git_cond_broadcast(c) pthread_cond_broadcast(c)++extern int git_online_cpus(void);++#endif /* INCLUDE_thread_utils_h__ */
+ libgit2/src/tree.c view
@@ -0,0 +1,351 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "commit.h"+#include "tree.h"+#include "git2/repository.h"+#include "git2/object.h"++#define DEFAULT_TREE_SIZE 16+#define MAX_FILEMODE 0777777+#define MAX_FILEMODE_BYTES 6++int entry_search_cmp(const void *key, const void *array_member)+{+ const char *filename = (const char *)key;+ const git_tree_entry *entry = *(const git_tree_entry **)(array_member);++ return strcmp(filename, entry->filename);+}++static int valid_attributes(const int attributes) {+ return attributes >= 0 && attributes <= MAX_FILEMODE; +}++int entry_sort_cmp(const void *a, const void *b)+{+ const git_tree_entry *entry_a = *(const git_tree_entry **)(a);+ const git_tree_entry *entry_b = *(const git_tree_entry **)(b);++ return gitfo_cmp_path(entry_a->filename, strlen(entry_a->filename),+ entry_a->attr & 040000,+ entry_b->filename, strlen(entry_b->filename),+ entry_b->attr & 040000);+}++void git_tree_clear_entries(git_tree *tree)+{+ unsigned int i;++ if (tree == NULL)+ return;++ for (i = 0; i < tree->entries.length; ++i) {+ git_tree_entry *e;+ e = git_vector_get(&tree->entries, i);++ free(e->filename);+ free(e);+ }++ git_vector_clear(&tree->entries);+ tree->object.modified = 1;+}+++git_tree *git_tree__new(void)+{+ git_tree *tree;++ tree = git__malloc(sizeof(struct git_tree));+ if (tree == NULL)+ return NULL;++ memset(tree, 0x0, sizeof(struct git_tree));++ if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) {+ free(tree);+ return NULL;+ }++ return tree;+}++void git_tree__free(git_tree *tree)+{+ git_tree_clear_entries(tree);+ git_vector_free(&tree->entries);+ free(tree);+}++const git_oid *git_tree_id(git_tree *c)+{+ return git_object_id((git_object *)c);+}++int git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr)+{+ assert(entry && entry->owner);+ + if (!valid_attributes(attr)) {+ return GIT_ERROR;+ }++ entry->attr = attr;+ entry->owner->object.modified = 1;+ return GIT_SUCCESS;+}++void git_tree_entry_set_name(git_tree_entry *entry, const char *name)+{+ assert(entry && entry->owner);++ free(entry->filename);+ entry->filename = git__strdup(name);+ git_vector_sort(&entry->owner->entries);+ entry->owner->object.modified = 1;+}++void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid)+{+ assert(entry && entry->owner);++ git_oid_cpy(&entry->oid, oid);+ entry->owner->object.modified = 1;+}++unsigned int git_tree_entry_attributes(git_tree_entry *entry)+{+ return entry->attr;+}++const char *git_tree_entry_name(git_tree_entry *entry)+{+ assert(entry);+ return entry->filename;+}++const git_oid *git_tree_entry_id(git_tree_entry *entry)+{+ assert(entry);+ return &entry->oid;+}++int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry)+{+ assert(entry && object_out);+ return git_object_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);+}++static void sort_entries(git_tree *tree)+{+ git_vector_sort(&tree->entries);+}++git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)+{+ int idx;++ assert(tree && filename);++ sort_entries(tree);++ idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);+ if (idx == GIT_ENOTFOUND)+ return NULL;++ return git_vector_get(&tree->entries, idx);+}++git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)+{+ assert(tree);++ sort_entries(tree);++ return git_vector_get(&tree->entries, (unsigned int)idx);+}++size_t git_tree_entrycount(git_tree *tree)+{+ assert(tree);+ return tree->entries.length;+}++int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)+{+ git_tree_entry *entry;++ assert(tree && id && filename);+ if (!valid_attributes(attributes)) {+ return GIT_ERROR;+ }++ if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)+ return GIT_ENOMEM;++ memset(entry, 0x0, sizeof(git_tree_entry));++ entry->filename = git__strdup(filename);+ git_oid_cpy(&entry->oid, id);+ entry->attr = attributes;+ entry->owner = tree;++ if (git_vector_insert(&tree->entries, entry) < 0)+ return GIT_ENOMEM;++ if (entry_out != NULL)+ *entry_out = entry;++ tree->object.modified = 1;+ return GIT_SUCCESS;+}++int git_tree_remove_entry_byindex(git_tree *tree, int idx)+{+ git_tree_entry *remove_ptr;++ assert(tree);++ sort_entries(tree);++ remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx);+ if (remove_ptr == NULL)+ return GIT_ENOTFOUND;++ free(remove_ptr->filename);+ free(remove_ptr);++ tree->object.modified = 1;++ return git_vector_remove(&tree->entries, (unsigned int)idx);+}++int git_tree_remove_entry_byname(git_tree *tree, const char *filename)+{+ int idx;++ assert(tree && filename);++ sort_entries(tree);++ idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);+ if (idx == GIT_ENOTFOUND)+ return GIT_ENOTFOUND;++ return git_tree_remove_entry_byindex(tree, idx);+}++int git_tree__writeback(git_tree *tree, git_odb_source *src)+{+ size_t i;+ char filemode[MAX_FILEMODE_BYTES + 1 + 1];++ assert(tree && src);++ if (tree->entries.length == 0)+ return GIT_EMISSINGOBJDATA;++ sort_entries(tree);++ for (i = 0; i < tree->entries.length; ++i) {+ git_tree_entry *entry;++ entry = git_vector_get(&tree->entries, i);+ + snprintf(filemode, sizeof(filemode), "%o ", entry->attr);+ + git__source_write(src, filemode, strlen(filemode));+ git__source_write(src, entry->filename, strlen(entry->filename) + 1);+ git__source_write(src, entry->oid.id, GIT_OID_RAWSZ);+ } ++ return GIT_SUCCESS;+}+++static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)+{+ static const size_t avg_entry_size = 40;+ unsigned int expected_size;+ int error = GIT_SUCCESS;++ expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;++ git_tree_clear_entries(tree);++ while (buffer < buffer_end) {+ git_tree_entry *entry;++ entry = git__malloc(sizeof(git_tree_entry));+ if (entry == NULL) {+ error = GIT_ENOMEM;+ break;+ }++ if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)+ return GIT_ENOMEM;++ entry->owner = tree;+ entry->attr = strtol(buffer, &buffer, 8);++ if (*buffer++ != ' ') {+ error = GIT_EOBJCORRUPTED;+ break;+ }++ if (memchr(buffer, 0, buffer_end - buffer) == NULL) {+ error = GIT_EOBJCORRUPTED;+ break;+ }++ entry->filename = git__strdup(buffer);++ while (buffer < buffer_end && *buffer != 0)+ buffer++;++ buffer++;++ git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);+ buffer += GIT_OID_RAWSZ;+ }++ return error;+}++int git_tree__parse(git_tree *tree)+{+ char *buffer, *buffer_end;++ assert(tree && tree->object.source.open);+ assert(!tree->object.in_memory);++ buffer = tree->object.source.raw.data;+ buffer_end = buffer + tree->object.source.raw.len;++ return tree_parse_buffer(tree, buffer, buffer_end);+}+
+ libgit2/src/tree.h view
@@ -0,0 +1,26 @@+#ifndef INCLUDE_tree_h__+#define INCLUDE_tree_h__++#include "git2/tree.h"+#include "repository.h"+#include "vector.h"++struct git_tree_entry {+ unsigned int attr;+ char *filename;+ git_oid oid;++ git_tree *owner;+};++struct git_tree {+ git_object object;+ git_vector entries;+};++void git_tree__free(git_tree *tree);+git_tree *git_tree__new(void);+int git_tree__parse(git_tree *tree);+int git_tree__writeback(git_tree *tree, git_odb_source *src);++#endif
+ libgit2/src/unix/map.c view
@@ -0,0 +1,61 @@++#include "map.h"+#include <sys/mman.h>+#include <errno.h>+++int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)+{+ int mprot = 0;+ int mflag = 0;++ assert((out != NULL) && (len > 0));++ if ((out == NULL) || (len == 0)) {+ errno = EINVAL;+ return GIT_ERROR;+ }++ out->data = NULL;+ out->len = 0;++ if (prot & GIT_PROT_WRITE)+ mprot = PROT_WRITE;+ else if (prot & GIT_PROT_READ)+ mprot = PROT_READ;+ else {+ errno = EINVAL;+ return GIT_ERROR;+ }++ if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)+ mflag = MAP_SHARED;+ else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)+ mflag = MAP_PRIVATE;++ if (flags & GIT_MAP_FIXED) {+ errno = EINVAL;+ return GIT_ERROR;+ }++ out->data = mmap(NULL, len, mprot, mflag, fd, offset);+ if (!out->data || out->data == MAP_FAILED)+ return GIT_EOSERR;+ out->len = len;++ return GIT_SUCCESS;+}++int git__munmap(git_map *map)+{+ assert(map != NULL);++ if (!map)+ return GIT_ERROR;++ munmap(map->data, map->len);++ return GIT_SUCCESS;+}++
+ libgit2/src/util.c view
@@ -0,0 +1,406 @@+#define GIT__NO_HIDE_MALLOC+#include "common.h"+#include <stdarg.h>+#include <stdio.h>++void git_strarray_free(git_strarray *array)+{+ size_t i;+ for (i = 0; i < array->count; ++i)+ free(array->strings[i]);++ free(array->strings);+}++int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)+{+ va_list va;+ int r;++ va_start(va, fmt);+ r = vsnprintf(buf, buf_sz, fmt, va);+ va_end(va);+ if (r < 0 || ((size_t) r) >= buf_sz)+ return GIT_ERROR;+ return r;+}++int git__prefixcmp(const char *str, const char *prefix)+{+ for (;;) {+ char p = *(prefix++), s;+ if (!p)+ return 0;+ if ((s = *(str++)) != p)+ return s - p;+ }+}++int git__suffixcmp(const char *str, const char *suffix)+{+ size_t a = strlen(str);+ size_t b = strlen(suffix);+ if (a < b)+ return -1;+ return strcmp(str + (a - b), suffix);+}++/*+ * Based on the Android implementation, BSD licensed.+ * Check http://android.git.kernel.org/+ */+int git__basename_r(char *buffer, size_t bufflen, const char *path)+{+ const char *endp, *startp;+ int len, result;++ /* Empty or NULL string gets treated as "." */+ if (path == NULL || *path == '\0') {+ startp = ".";+ len = 1;+ goto Exit;+ }++ /* Strip trailing slashes */+ endp = path + strlen(path) - 1;+ while (endp > path && *endp == '/')+ endp--;++ /* All slashes becomes "/" */+ if (endp == path && *endp == '/') {+ startp = "/";+ len = 1;+ goto Exit;+ }++ /* Find the start of the base */+ startp = endp;+ while (startp > path && *(startp - 1) != '/')+ startp--;++ len = endp - startp +1;++Exit:+ result = len;+ if (buffer == NULL) {+ return result;+ }+ if (len > (int)bufflen-1) {+ len = (int)bufflen-1;+ result = GIT_ENOMEM;+ }++ if (len >= 0) {+ memmove(buffer, startp, len);+ buffer[len] = 0;+ }+ return result;+}++/*+ * Based on the Android implementation, BSD licensed.+ * Check http://android.git.kernel.org/+ */+int git__dirname_r(char *buffer, size_t bufflen, const char *path)+{+ const char *endp;+ int result, len;++ /* Empty or NULL string gets treated as "." */+ if (path == NULL || *path == '\0') {+ path = ".";+ len = 1;+ goto Exit;+ }++ /* Strip trailing slashes */+ endp = path + strlen(path) - 1;+ while (endp > path && *endp == '/')+ endp--;++ /* Find the start of the dir */+ while (endp > path && *endp != '/')+ endp--;++ /* Either the dir is "/" or there are no slashes */+ if (endp == path) {+ path = (*endp == '/') ? "/" : ".";+ len = 1;+ goto Exit;+ }++ do {+ endp--;+ } while (endp > path && *endp == '/');++ len = endp - path +1;++Exit:+ result = len;+ if (len+1 > GIT_PATH_MAX) {+ return GIT_ENOMEM;+ }+ if (buffer == NULL)+ return result;++ if (len > (int)bufflen-1) {+ len = (int)bufflen-1;+ result = GIT_ENOMEM;+ }++ if (len >= 0) {+ memmove(buffer, path, len);+ buffer[len] = 0;+ }+ return result;+}+++char *git__dirname(const char *path)+{+ char *dname = NULL;+ int len;++ len = (path ? strlen(path) : 0) + 2;+ dname = (char *)git__malloc(len);+ if (dname == NULL)+ return NULL;++ if (git__dirname_r(dname, len, path) < GIT_SUCCESS) {+ free(dname);+ return NULL;+ }++ return dname;+}++char *git__basename(const char *path)+{+ char *bname = NULL;+ int len;++ len = (path ? strlen(path) : 0) + 2;+ bname = (char *)git__malloc(len);+ if (bname == NULL)+ return NULL;++ if (git__basename_r(bname, len, path) < GIT_SUCCESS) {+ free(bname);+ return NULL;+ }++ return bname;+}+++const char *git__topdir(const char *path)+{+ size_t len;+ int i;++ assert(path);+ len = strlen(path);++ if (!len || path[len - 1] != '/')+ return NULL;++ for (i = len - 2; i >= 0; --i)+ if (path[i] == '/')+ break;++ return &path[i + 1];+}++void git__joinpath_n(char *buffer_out, int count, ...)+{+ va_list ap;+ int i;+ char *buffer_start = buffer_out;++ va_start(ap, count);+ for (i = 0; i < count; ++i) {+ const char *path;+ int len;++ path = va_arg(ap, const char *);+ if (i > 0 && *path == '/' && buffer_out > buffer_start && buffer_out[-1] == '/')+ path++;++ if (!*path)+ continue;++ len = strlen(path);+ memmove(buffer_out, path, len);+ buffer_out = buffer_out + len;++ if (i < count - 1 && buffer_out[-1] != '/')+ *buffer_out++ = '/';+ }+ va_end(ap);++ *buffer_out = '\0';+}++static char *strtok_raw(char *output, char *src, char *delimit, int keep)+{+ while (*src && strchr(delimit, *src) == NULL)+ *output++ = *src++;++ *output = 0;++ if (keep)+ return src;+ else+ return *src ? src+1 : src;+}++char *git__strtok(char *output, char *src, char *delimit)+{+ return strtok_raw(output, src, delimit, 0);+}++char *git__strtok_keep(char *output, char *src, char *delimit)+{+ return strtok_raw(output, src, delimit, 1);+}++void git__hexdump(const char *buffer, size_t len)+{+ static const size_t LINE_WIDTH = 16;++ size_t line_count, last_line, i, j;+ const char *line;++ line_count = (len / LINE_WIDTH);+ last_line = (len % LINE_WIDTH);++ for (i = 0; i < line_count; ++i) {+ line = buffer + (i * LINE_WIDTH);+ for (j = 0; j < LINE_WIDTH; ++j, ++line)+ printf("%02X ", (unsigned char)*line & 0xFF);++ printf("| ");++ line = buffer + (i * LINE_WIDTH);+ for (j = 0; j < LINE_WIDTH; ++j, ++line)+ printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');++ printf("\n");+ }++ if (last_line > 0) {++ line = buffer + (line_count * LINE_WIDTH);+ for (j = 0; j < last_line; ++j, ++line)+ printf("%02X ", (unsigned char)*line & 0xFF);++ for (j = 0; j < (LINE_WIDTH - last_line); ++j)+ printf(" ");++ printf("| ");++ line = buffer + (line_count * LINE_WIDTH);+ for (j = 0; j < last_line; ++j, ++line)+ printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');++ printf("\n");+ }++ printf("\n");+}++#ifdef GIT_LEGACY_HASH+uint32_t git__hash(const void *key, int len, unsigned int seed)+{+ const uint32_t m = 0x5bd1e995;+ const int r = 24;+ uint32_t h = seed ^ len;++ const unsigned char *data = (const unsigned char *)key;++ while(len >= 4) {+ uint32_t k = *(uint32_t *)data;++ k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k;++ data += 4;+ len -= 4;+ }+ + switch(len) {+ case 3: h ^= data[2] << 16;+ case 2: h ^= data[1] << 8;+ case 1: h ^= data[0];+ h *= m;+ };++ h ^= h >> 13;+ h *= m;+ h ^= h >> 15;++ return h;+} +#else+/*+ Cross-platform version of Murmurhash3+ http://code.google.com/p/smhasher/wiki/MurmurHash3+ by Austin Appleby (aappleby@gmail.com)++ This code is on the public domain.+*/+uint32_t git__hash(const void *key, int len, uint32_t seed)+{++#define MURMUR_BLOCK() {\+ k1 *= c1; \+ k1 = git__rotl(k1,11);\+ k1 *= c2;\+ h1 ^= k1;\+ h1 = h1*3 + 0x52dce729;\+ c1 = c1*5 + 0x7b7d159c;\+ c2 = c2*5 + 0x6bce6396;\+}++ const uint8_t *data = (const uint8_t*)key;+ const int nblocks = len / 4;++ const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);+ const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);++ uint32_t h1 = 0x971e137b ^ seed;+ uint32_t k1;++ uint32_t c1 = 0x95543787;+ uint32_t c2 = 0x2ad7eb25;++ int i;++ for (i = -nblocks; i; i++) {+ k1 = blocks[i];+ MURMUR_BLOCK();+ }++ k1 = 0;++ switch(len & 3) {+ case 3: k1 ^= tail[2] << 16;+ case 2: k1 ^= tail[1] << 8;+ case 1: k1 ^= tail[0];+ MURMUR_BLOCK();+ }++ h1 ^= len;+ h1 ^= h1 >> 16;+ h1 *= 0x85ebca6b;+ h1 ^= h1 >> 13;+ h1 *= 0xc2b2ae35;+ h1 ^= h1 >> 16;++ return h1;+} +#endif
+ libgit2/src/util.h view
@@ -0,0 +1,119 @@+#ifndef INCLUDE_util_h__+#define INCLUDE_util_h__++#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))+#define bitsizeof(x) (CHAR_BIT * sizeof(x))+#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))++/* + * Don't wrap malloc/calloc.+ * Use the default versions in glibc, and make+ * sure that any methods that allocate memory+ * return a GIT_ENOMEM error when allocation+ * fails.+ */+#define git__malloc malloc+#define git__calloc calloc+#define git__strdup strdup++extern int git__fmt(char *, size_t, const char *, ...)+ GIT_FORMAT_PRINTF(3, 4);+extern int git__prefixcmp(const char *str, const char *prefix);+extern int git__suffixcmp(const char *str, const char *suffix);++/*+ * The dirname() function shall take a pointer to a character string+ * that contains a pathname, and return a pointer to a string that is a+ * pathname of the parent directory of that file. Trailing '/' characters+ * in the path are not counted as part of the path.+ *+ * If path does not contain a '/', then dirname() shall return a pointer to+ * the string ".". If path is a null pointer or points to an empty string,+ * dirname() shall return a pointer to the string "." .+ *+ * The `git__dirname` implementation is thread safe. The returned + * string must be manually free'd.+ *+ * The `git__dirname_r` implementation expects a string allocated+ * by the user with big enough size.+ */+extern char *git__dirname(const char *path);+extern int git__dirname_r(char *buffer, size_t bufflen, const char *path);++/*+ * This function returns the basename of the file, which is the last+ * part of its full name given by fname, with the drive letter and+ * leading directories stripped off. For example, the basename of+ * c:/foo/bar/file.ext is file.ext, and the basename of a:foo is foo.+ *+ * Trailing slashes and backslashes are significant: the basename of+ * c:/foo/bar/ is an empty string after the rightmost slash.+ *+ * The `git__basename` implementation is thread safe. The returned + * string must be manually free'd.+ *+ * The `git__basename_r` implementation expects a string allocated+ * by the user with big enough size.+ */+extern char *git__basename(const char *path);+extern int git__basename_r(char *buffer, size_t bufflen, const char *path);++extern const char *git__topdir(const char *path);++/**+ * Join two paths together. Takes care of properly fixing the+ * middle slashes and everything+ *+ * The paths are joined together into buffer_out; this is expected+ * to be an user allocated buffer of `GIT_PATH_MAX` size + */+extern void git__joinpath_n(char *buffer_out, int npath, ...);++GIT_INLINE(void) git__joinpath(char *buffer_out, const char *path_a, const char *path_b)+{+ git__joinpath_n(buffer_out, 2, path_a, path_b);+}++extern void git__hexdump(const char *buffer, size_t n);+extern uint32_t git__hash(const void *key, int len, uint32_t seed);+++/** @return true if p fits into the range of a size_t */+GIT_INLINE(int) git__is_sizet(git_off_t p)+{+ size_t r = (size_t)p;+ return p == (git_off_t)r;+}++/* 32-bit cross-platform rotl */+#ifdef _MSC_VER /* use built-in method in MSVC */+# define git__rotl(v, s) (uint32_t)_rotl(v, s)+#else /* use bitops in GCC; with o2 this gets optimized to a rotl instruction */+# define git__rotl(v, s) (uint32_t)(((uint32_t)(v) << (s)) | ((uint32_t)(v) >> (32 - (s))))+#endif++extern char *git__strtok(char *output, char *src, char *delimit);+extern char *git__strtok_keep(char *output, char *src, char *delimit);++#define STRLEN(str) (sizeof(str) - 1)++/*+ * Realloc the buffer pointed at by variable 'x' so that it can hold+ * at least 'nr' entries; the number of entries currently allocated+ * is 'alloc', using the standard growing factor alloc_nr() macro.+ *+ * DO NOT USE any expression with side-effect for 'x' or 'alloc'.+ */+#define alloc_nr(x) (((x)+16)*3/2)+#define ALLOC_GROW(x, nr, alloc) \+ do { \+ if ((nr) > alloc) { \+ if (alloc_nr(alloc) < (nr)) \+ alloc = (nr); \+ else \+ alloc = alloc_nr(alloc); \+ x = xrealloc((x), alloc * sizeof(*(x))); \+ } \+ } while (0)++#endif /* INCLUDE_util_h__ */
+ libgit2/src/vector.c view
@@ -0,0 +1,175 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ */++#include "common.h"+#include "repository.h"+#include "vector.h"++static const double resize_factor = 1.75;+static const size_t minimum_size = 8;++static int resize_vector(git_vector *v)+{+ v->_alloc_size = ((unsigned int)(v->_alloc_size * resize_factor)) + 1;+ if (v->_alloc_size < minimum_size)+ v->_alloc_size = minimum_size;++ v->contents = realloc(v->contents, v->_alloc_size * sizeof(void *));+ if (v->contents == NULL)+ return GIT_ENOMEM;++ return GIT_SUCCESS;+}+++void git_vector_free(git_vector *v)+{+ assert(v);+ free(v->contents);+}++int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp)+{+ assert(v);++ memset(v, 0x0, sizeof(git_vector));++ if (initial_size == 0)+ initial_size = minimum_size;++ v->_alloc_size = initial_size;+ v->_cmp = cmp;+ + v->length = 0;+ v->sorted = 1;++ v->contents = git__malloc(v->_alloc_size * sizeof(void *));+ if (v->contents == NULL)+ return GIT_ENOMEM;++ return GIT_SUCCESS;+}++int git_vector_insert(git_vector *v, void *element)+{+ assert(v);++ if (v->length >= v->_alloc_size) {+ if (resize_vector(v) < 0)+ return GIT_ENOMEM;+ }++ v->contents[v->length++] = element;+ v->sorted = 0;++ return GIT_SUCCESS;+}++void git_vector_sort(git_vector *v)+{+ assert(v);++ if (v->sorted || v->_cmp == NULL)+ return;++ qsort(v->contents, v->length, sizeof(void *), v->_cmp);+ v->sorted = 1;+}++int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key)+{+ void **find;++ assert(v && key && key_lookup);++ /* need comparison function to sort the vector */+ if (v->_cmp == NULL)+ return GIT_ENOTFOUND;++ git_vector_sort(v);++ find = bsearch(key, v->contents, v->length, sizeof(void *), key_lookup);+ if (find != NULL)+ return (int)(find - v->contents);++ return GIT_ENOTFOUND;+}++int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key)+{+ unsigned int i;++ assert(v && key && key_lookup);++ for (i = 0; i < v->length; ++i) {+ if (key_lookup(key, v->contents[i]) == 0)+ return i;+ }++ return GIT_ENOTFOUND;+}++static int strict_comparison(const void *a, const void *b)+{+ return (a == b) ? 0 : -1;+}++int git_vector_search(git_vector *v, const void *entry)+{+ return git_vector_search2(v, v->_cmp ? v->_cmp : strict_comparison, entry);+}++int git_vector_bsearch(git_vector *v, const void *key)+{+ if (v->_cmp == NULL)+ return GIT_ENOTFOUND;++ return git_vector_bsearch2(v, v->_cmp, key);+}++int git_vector_remove(git_vector *v, unsigned int idx)+{+ unsigned int i;++ assert(v);++ if (idx >= v->length || v->length == 0)+ return GIT_ENOTFOUND;++ for (i = idx; i < v->length - 1; ++i)+ v->contents[i] = v->contents[i + 1];++ v->length--;+ return GIT_SUCCESS;+}++void git_vector_clear(git_vector *v)+{+ assert(v);+ v->length = 0;+ v->sorted = 1;+}++
+ libgit2/src/vector.h view
@@ -0,0 +1,36 @@+#ifndef INCLUDE_vector_h__+#define INCLUDE_vector_h__++#include "git2/common.h"++typedef int (*git_vector_cmp)(const void *, const void *);++typedef struct git_vector {+ unsigned int _alloc_size;+ git_vector_cmp _cmp;+ void **contents;+ unsigned int length;+ int sorted;+} git_vector;++int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp);+void git_vector_free(git_vector *v);+void git_vector_clear(git_vector *v);++int git_vector_search(git_vector *v, const void *entry);+int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key);++int git_vector_bsearch(git_vector *v, const void *entry);+int git_vector_bsearch2(git_vector *v, git_vector_cmp cmp, const void *key);++void git_vector_sort(git_vector *v);++GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position)+{+ return (position < v->length) ? v->contents[position] : NULL;+}++int git_vector_insert(git_vector *v, void *element);+int git_vector_remove(git_vector *v, unsigned int idx);++#endif
+ libgit2/src/win32/dir.c view
@@ -0,0 +1,98 @@+#define GIT__WIN32_NO_WRAP_DIR+#include "dir.h"++static int init_filter(char *filter, size_t n, const char *dir)+{+ size_t len = strlen(dir);++ if (len+3 >= n)+ return 0;++ strcpy(filter, dir);+ if (len && dir[len-1] != '/')+ strcat(filter, "/");+ strcat(filter, "*");++ return 1;+}++git__DIR *git__opendir(const char *dir)+{+ char filter[4096];+ git__DIR *new;++ if (!dir || !init_filter(filter, sizeof(filter), dir))+ return NULL;++ new = git__malloc(sizeof(*new));+ if (!new)+ return NULL;++ new->dir = git__malloc(strlen(dir)+1);+ if (!new->dir) {+ free(new);+ return NULL;+ }+ strcpy(new->dir, dir);++ new->h = FindFirstFile(filter, &new->f);+ if (new->h == INVALID_HANDLE_VALUE) {+ free(new->dir);+ free(new);+ return NULL;+ }+ new->first = 1;++ return new;+}++struct git__dirent *git__readdir(git__DIR *d)+{+ if (!d || d->h == INVALID_HANDLE_VALUE)+ return NULL;++ if (d->first)+ d->first = 0;+ else {+ if (!FindNextFile(d->h, &d->f))+ return NULL;+ }++ if (strlen(d->f.cFileName) >= sizeof(d->entry.d_name))+ return NULL;++ d->entry.d_ino = 0;+ strcpy(d->entry.d_name, d->f.cFileName);++ return &d->entry;+}++void git__rewinddir(git__DIR *d)+{+ char filter[4096];++ if (d) {+ if (d->h != INVALID_HANDLE_VALUE)+ FindClose(d->h);+ d->h = INVALID_HANDLE_VALUE;+ d->first = 0;+ if (init_filter(filter, sizeof(filter), d->dir)) {+ d->h = FindFirstFile(filter, &d->f);+ if (d->h != INVALID_HANDLE_VALUE)+ d->first = 1;+ }+ }+}++int git__closedir(git__DIR *d)+{+ if (d) {+ if (d->h != INVALID_HANDLE_VALUE)+ FindClose(d->h);+ if (d->dir)+ free(d->dir);+ free(d);+ }+ return 0;+}+
+ libgit2/src/win32/fileops.c view
@@ -0,0 +1,41 @@+#define GIT__WIN32_NO_HIDE_FILEOPS+#include "fileops.h"+#include <errno.h>++int git__unlink(const char *path)+{+ chmod(path, 0666);+ return unlink(path);+}++int git__mkstemp(char *template)+{+ char *file = mktemp(template);+ if (file == NULL)+ return -1;+ return open(file, O_RDWR | O_CREAT | O_BINARY, 0600);+}++int git__fsync(int fd)+{+ HANDLE fh = (HANDLE)_get_osfhandle(fd);++ if (fh == INVALID_HANDLE_VALUE) {+ errno = EBADF;+ return -1;+ }++ if (!FlushFileBuffers(fh)) {+ DWORD code = GetLastError();++ if (code == ERROR_INVALID_HANDLE)+ errno = EINVAL;+ else+ errno = EIO;++ return -1;+ }++ return 0;+}+
+ libgit2/src/win32/map.c view
@@ -0,0 +1,125 @@++#include "map.h"+#include <errno.h>+++static DWORD get_page_size(void)+{+ static DWORD page_size;+ SYSTEM_INFO sys;++ if (!page_size) {+ GetSystemInfo(&sys);+ page_size = sys.dwAllocationGranularity;+ }++ return page_size;+}++int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)+{+ HANDLE fh = (HANDLE)_get_osfhandle(fd);+ DWORD page_size = get_page_size();+ DWORD fmap_prot = 0;+ DWORD view_prot = 0;+ DWORD off_low = 0;+ DWORD off_hi = 0;+ git_off_t page_start;+ git_off_t page_offset;++ assert((out != NULL) && (len > 0));++ if ((out == NULL) || (len == 0)) {+ errno = EINVAL;+ return GIT_ERROR;+ }++ out->data = NULL;+ out->len = 0;+ out->fmh = NULL;++ if (fh == INVALID_HANDLE_VALUE) {+ errno = EBADF;+ return GIT_ERROR;+ }++ if (prot & GIT_PROT_WRITE)+ fmap_prot |= PAGE_READWRITE;+ else if (prot & GIT_PROT_READ)+ fmap_prot |= PAGE_READONLY;+ else {+ errno = EINVAL;+ return GIT_ERROR;+ }++ if (prot & GIT_PROT_WRITE)+ view_prot |= FILE_MAP_WRITE;+ if (prot & GIT_PROT_READ)+ view_prot |= FILE_MAP_READ;++ if (flags & GIT_MAP_FIXED) {+ errno = EINVAL;+ return GIT_ERROR;+ }++ page_start = (offset / page_size) * page_size;+ page_offset = offset - page_start;++ if (page_offset != 0) { /* offset must be multiple of page size */+ errno = EINVAL;+ return GIT_ERROR;+ }++ out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL);+ if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {+ /* errno = ? */+ out->fmh = NULL;+ return GIT_ERROR;+ }++ assert(sizeof(git_off_t) == 8);+ off_low = (DWORD)(page_start);+ off_hi = (DWORD)(page_start >> 32);+ out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);+ if (!out->data) {+ /* errno = ? */+ CloseHandle(out->fmh);+ out->fmh = NULL;+ return GIT_ERROR;+ }+ out->len = len;++ return GIT_SUCCESS;+}++int git__munmap(git_map *map)+{+ assert(map != NULL);++ if (!map)+ return GIT_ERROR;++ if (map->data) {+ if (!UnmapViewOfFile(map->data)) {+ /* errno = ? */+ CloseHandle(map->fmh);+ map->data = NULL;+ map->fmh = NULL;+ return GIT_ERROR;+ }+ map->data = NULL;+ }++ if (map->fmh) {+ if (!CloseHandle(map->fmh)) {+ /* errno = ? */+ map->fmh = NULL;+ return GIT_ERROR;+ }+ map->fmh = NULL;+ }++ return GIT_SUCCESS;+}++
+ libgit2/src/win32/pthread.c view
@@ -0,0 +1,120 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ *+ * Original code by Ramiro Polla (Public Domain)+ */++#include "pthread.h"++int pthread_create(pthread_t *GIT_RESTRICT thread,+ const pthread_attr_t *GIT_RESTRICT GIT_UNUSED(attr),+ void *(*start_routine)(void*), void *GIT_RESTRICT arg)+{+ GIT_UNUSED_ARG(attr);+ *thread = (pthread_t) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);+ return *thread ? GIT_SUCCESS : GIT_EOSERR;+}++int pthread_cond_signal(pthread_cond_t *cond)+{+ WakeConditionVariable(cond);+ return 0;+}++int pthread_cond_wait(pthread_cond_t *GIT_RESTRICT cond,+ pthread_mutex_t *GIT_RESTRICT mutex)+{+ int ret;+ ret = SleepConditionVariableCS(cond, mutex, INFINITE);+ return -(!ret);+}++int pthread_mutex_lock(pthread_mutex_t *mutex)+{+ EnterCriticalSection(mutex);+ return 0;+}++int pthread_mutex_unlock(pthread_mutex_t *mutex)+{+ LeaveCriticalSection(mutex);+ return 0;+}++int pthread_join(pthread_t thread, void **value_ptr)+{+ int ret;+ ret = WaitForSingleObject(thread, INFINITE);+ if (ret && value_ptr)+ GetExitCodeThread(thread, (void*) value_ptr);+ return -(!!ret);+}++int pthread_cond_broadcast(pthread_cond_t *cond)+{+ WakeAllConditionVariable(cond);+ return 0;+}++int pthread_mutex_destroy(pthread_mutex_t *mutex)+{+ int ret;+ ret = CloseHandle(mutex);+ return -(!ret);+}++int pthread_cond_destroy(pthread_cond_t *GIT_UNUSED(cond))+{+ GIT_UNUSED_ARG(cond);+ return 0;+}++int pthread_cond_init(pthread_cond_t *GIT_RESTRICT cond,+ const pthread_condattr_t *GIT_RESTRICT GIT_UNUSED(condattr))+{+ GIT_UNUSED_ARG(condattr);+ InitializeConditionVariable(cond);+ return 0;+}++int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex,+ const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr))+{+ GIT_UNUSED_ARG(mutexattr);+ InitializeCriticalSection(mutex);+ return 0;+}++int pthread_num_processors_np(void)+{+ DWORD_PTR p, s;+ int n = 0;++ if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s))+ for (; p; p >>= 1)+ n += p&1;++ return n ? n : 1;+}+
+ libgit2/src/win32/pthread.h view
@@ -0,0 +1,67 @@+/*+ * This file is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License, version 2,+ * as published by the Free Software Foundation.+ *+ * In addition to the permissions in the GNU General Public License,+ * the authors give you unlimited permission to link the compiled+ * version of this file into combinations with other programs,+ * and to distribute those combinations without any restriction+ * coming from the use of this file. (The General Public License+ * restrictions do apply in other respects; for example, they cover+ * modification of the file, and distribution when not linked into+ * a combined executable.)+ *+ * This file is distributed in the hope that 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; see the file COPYING. If not, write to+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,+ * Boston, MA 02110-1301, USA.+ *+ * Original code by Ramiro Polla (Public Domain)+ */++#ifndef GIT_PTHREAD_H+#define GIT_PTHREAD_H++#include "../common.h"++#if defined (_MSC_VER)+# define GIT_RESTRICT __restrict+#else+# define GIT_RESTRICT __restrict__+#endif++typedef int pthread_mutexattr_t;+typedef int pthread_condattr_t;+typedef int pthread_attr_t;+typedef CRITICAL_SECTION pthread_mutex_t;+typedef CONDITION_VARIABLE pthread_cond_t;+typedef HANDLE pthread_t;++#define PTHREAD_MUTEX_INITIALIZER {(void*)-1};++int pthread_create(pthread_t *GIT_RESTRICT,+ const pthread_attr_t *GIT_RESTRICT,+ void *(*start_routine)(void*), void *__restrict);++int pthread_join(pthread_t, void **);++int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT);+int pthread_mutex_destroy(pthread_mutex_t *);+int pthread_mutex_lock(pthread_mutex_t *);+int pthread_mutex_unlock(pthread_mutex_t *);++int pthread_cond_init(pthread_cond_t *GIT_RESTRICT, const pthread_condattr_t *GIT_RESTRICT);+int pthread_cond_destroy(pthread_cond_t *);+int pthread_cond_broadcast(pthread_cond_t *);+int pthread_cond_signal(pthread_cond_t *);+int pthread_cond_wait(pthread_cond_t *GIT_RESTRICT, pthread_mutex_t *GIT_RESTRICT);++int pthread_num_processors_np(void);++#endif
+ tests/Main.hi view
binary file changed (absent → 837 bytes)
+ tests/Main.hs view
@@ -0,0 +1,15 @@+module Main where+import Bindings.Libgit2+import Foreign+import Foreign.C.String+import System.Exit+import Control.Monad(when)+import System.Process(system)++main = do+ alloca $ \ptr -> do+ system "git init smoke.git" + withCString "smoke.git/.git" $ \str -> do+ r <- c'git_repository_open ptr str+ when (r < 0) $ exitWith (ExitFailure 1) + peek ptr >>= c'git_repository_free
+ tests/Main.hs~ view
@@ -0,0 +1,10 @@+module Main where+import Bindings.Libgit2+import Foreign+import Foreign.C.String++main = do+ alloca $ \ptr -> do+ withCString "foobar.git/.git" $ \str -> do+ c'git_repository_open ptr str+ peek ptr >>= c'git_repository_free
+ tests/Main.o view
binary file changed (absent → 4476 bytes)