Coder Social home page Coder Social logo

zip's Introduction

A portable (OSX/Linux/Windows/Android/iOS), simple zip library written in C

This is done by hacking awesome miniz library and layering functions on top of the miniz v3.0.2 API.

Build

The Idea

... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight. Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy. I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick. I wanted something powerful and small enough, so I could add just a few files and compile them into my project. And finally I found miniz. Miniz is a lossless, high performance data compression library in a single source file. I only needed simple interface to append buffers or files to the current zip-entry. Thanks to this feature I'm able to merge many files/buffers and compress them on-the-fly.

It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it.

Examples

  • Create a new zip archive with default compression level.
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        const char *buf = "Some data here...\0";
        zip_entry_write(zip, buf, strlen(buf));
    }
    zip_entry_close(zip);

    zip_entry_open(zip, "foo-2.txt");
    {
        // merge 3 files into one entry and compress them on-the-fly.
        zip_entry_fwrite(zip, "foo-2.1.txt");
        zip_entry_fwrite(zip, "foo-2.2.txt");
        zip_entry_fwrite(zip, "foo-2.3.txt");
    }
    zip_entry_close(zip);
}
zip_close(zip);
  • Append to the existing zip archive.
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
{
    zip_entry_open(zip, "foo-3.txt");
    {
        const char *buf = "Append some data here...\0";
        zip_entry_write(zip, buf, strlen(buf));
    }
    zip_entry_close(zip);
}
zip_close(zip);
  • Extract a zip archive into a folder.
int on_extract_entry(const char *filename, void *arg) {
    static int i = 0;
    int n = *(int *)arg;
    printf("Extracted: %s (%d of %d)\n", filename, ++i, n);

    return 0;
}

// From "foo.zip" on disk
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);

// Or from memory
arg = 2;
zip_stream_extract(zipstream, zipstreamsize, "/tmp", on_extract_entry, &arg);
  • Extract a zip entry into memory.
void *buf = NULL;
size_t bufsize;

struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        zip_entry_read(zip, &buf, &bufsize);
    }
    zip_entry_close(zip);
}
zip_close(zip);

free(buf);
  • Extract a zip entry into memory (no internal allocation).
unsigned char *buf;
size_t bufsize;

struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        bufsize = zip_entry_size(zip);
        buf = calloc(sizeof(unsigned char), bufsize);

        zip_entry_noallocread(zip, (void *)buf, bufsize);
    }
    zip_entry_close(zip);
}
zip_close(zip);

free(buf);
  • Extract a zip entry into memory using callback.
struct buffer_t {
    char *data;
    size_t size;
};

static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) {
    struct buffer_t *buf = (struct buffer_t *)arg;
    buf->data = realloc(buf->data, buf->size + size + 1);
    assert(NULL != buf->data);

    memcpy(&(buf->data[buf->size]), data, size);
    buf->size += size;
    buf->data[buf->size] = 0;

    return size;
}

struct buffer_t buf = {0};
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        zip_entry_extract(zip, on_extract, &buf);
    }
    zip_entry_close(zip);
}
zip_close(zip);

free(buf.data);
  • Extract a zip entry into a file.
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
    zip_entry_open(zip, "foo-2.txt");
    {
        zip_entry_fread(zip, "foo-2.txt");
    }
    zip_entry_close(zip);
}
zip_close(zip);
  • Create a new zip archive in memory (stream API).
char *outbuf = NULL;
size_t outbufsize = 0;

const char *inbuf = "Append some data here...\0";
struct zip_t *zip = zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        zip_entry_write(zip, inbuf, strlen(inbuf));
    }
    zip_entry_close(zip);

    /* copy compressed stream into outbuf */
    zip_stream_copy(zip, (void **)&outbuf, &outbufsize);
}
zip_stream_close(zip);

free(outbuf);
  • Extract a zip entry into a memory (stream API).
char *buf = NULL;
size_t bufsize = 0;

struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
{
    zip_entry_open(zip, "foo-1.txt");
    {
        zip_entry_read(zip, (void **)&buf, &bufsize);
    }
    zip_entry_close(zip);
}
zip_stream_close(zip);

free(buf);
  • List of all zip entries
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
int i, n = zip_entries_total(zip);
for (i = 0; i < n; ++i) {
    zip_entry_openbyindex(zip, i);
    {
        const char *name = zip_entry_name(zip);
        int isdir = zip_entry_isdir(zip);
        unsigned long long size = zip_entry_size(zip);
        unsigned int crc32 = zip_entry_crc32(zip);
    }
    zip_entry_close(zip);
}
zip_close(zip);
  • Compress folder (recursively)
void zip_walk(struct zip_t *zip, const char *path) {
    DIR *dir;
    struct dirent *entry;
    char fullpath[MAX_PATH];
    struct stat s;

    memset(fullpath, 0, MAX_PATH);
    dir = opendir(path);
    assert(dir);

    while ((entry = readdir(dir))) {
      // skip "." and ".."
      if (!strcmp(entry->d_name, ".\0") || !strcmp(entry->d_name, "..\0"))
        continue;

      snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
      stat(fullpath, &s);
      if (S_ISDIR(s.st_mode))
        zip_walk(zip, fullpath);
      else {
        zip_entry_open(zip, fullpath);
        zip_entry_fwrite(zip, fullpath);
        zip_entry_close(zip);
      }
    }

    closedir(dir);
}
  • Delete zip archive entries.
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
// size_t indices[] = {0, 1, 2};

struct zip_t *zip = zip_open("foo.zip", 0, 'd');
{
    zip_entries_delete(zip, entries, 3);

    // you can also delete by index, instead of by name
    // zip_entries_deletebyindex(zip, indices, 3);
}
zip_close(zip);

Bindings

Compile zip library as a dynamic library.

$ mkdir build
$ cd build
$ cmake -DBUILD_SHARED_LIBS=true ..
$ cmake --build .

Go (cgo)

Third party binding: kuba--/c-go-zip

package main

/*
#cgo CFLAGS: -I../src
#cgo LDFLAGS: -L. -lzip
#include <zip.h>
*/
import "C"
import "unsafe"

func main() {
    path := C.CString("/tmp/go.zip")
    zip := C.zip_open(path, 6, 'w')

    entryname := C.CString("test")
    C.zip_entry_open(zip, entryname)

    content := "test content"
    buf := unsafe.Pointer(C.CString(content))
    bufsize := C.size_t(len(content))
    C.zip_entry_write(zip, buf, bufsize)

    C.zip_entry_close(zip)

    C.zip_close(zip)
}

Rust (ffi)

extern crate libc;
use std::ffi::CString;

#[repr(C)]
pub struct Zip {
    _private: [u8; 0],
}

#[link(name = "zip")]
extern "C" {
    fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
    fn zip_close(zip: *mut Zip) -> libc::c_void;

    fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
    fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
    fn zip_entry_write(
        zip: *mut Zip,
        buf: *const libc::c_void,
        bufsize: libc::size_t,
    ) -> libc::c_int;
}

fn main() {
    let path = CString::new("/tmp/rust.zip").unwrap();
    let mode: libc::c_char = 'w' as libc::c_char;

    let entryname = CString::new("test.txt").unwrap();
    let content = "test content\0";

    unsafe {
        let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
        {
            zip_entry_open(zip, entryname.as_ptr());
            {
                let buf = content.as_ptr() as *const libc::c_void;
                let bufsize = content.len() as libc::size_t;
                zip_entry_write(zip, buf, bufsize);
            }
            zip_entry_close(zip);
        }
        zip_close(zip);
    }
}

Ruby (ffi)

Install ffi gem.

$ gem install ffi

Bind in your module.

require 'ffi'

module Zip
  extend FFI::Library
  ffi_lib "./libzip.#{::FFI::Platform::LIBSUFFIX}"

  attach_function :zip_open, [:string, :int, :char], :pointer
  attach_function :zip_close, [:pointer], :void

  attach_function :zip_entry_open, [:pointer, :string], :int
  attach_function :zip_entry_close, [:pointer], :void
  attach_function :zip_entry_write, [:pointer, :string, :int], :int
end

ptr = Zip.zip_open("/tmp/ruby.zip", 6, "w".bytes()[0])

status = Zip.zip_entry_open(ptr, "test")

content = "test content"
status = Zip.zip_entry_write(ptr, content, content.size())

Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)

Python (cffi)

Install cffi package

$ pip install cffi

Bind in your package.

import ctypes.util
from cffi import FFI

ffi = FFI()
ffi.cdef("""
    struct zip_t *zip_open(const char *zipname, int level, char mode);
    void zip_close(struct zip_t *zip);

    int zip_entry_open(struct zip_t *zip, const char *entryname);
    int zip_entry_close(struct zip_t *zip);
    int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
""")

Zip = ffi.dlopen(ctypes.util.find_library("zip"))

ptr = Zip.zip_open("/tmp/python.zip", 6, 'w')

status = Zip.zip_entry_open(ptr, "test")

content = "test content"
status = Zip.zip_entry_write(ptr, content, len(content))

Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)

Never (ffi)

extern "libzip.so" func zip_open(zipname: string, level: int, mode: char) -> c_ptr
extern "libzip.so" func zip_close(zip: c_ptr) -> void

extern "libzip.so" func zip_entry_open(zip: c_ptr, entryname: string) -> int
extern "libzip.so" func zip_entry_close(zip: c_ptr) -> int
extern "libzip.so" func zip_entry_write(zip: c_ptr, buf: string, bufsize: int) -> int
extern "libzip.so" func zip_entry_fwrite(zip: c_ptr, filename: string) -> int

func main() -> int
{
    let content = "Test content"

    let zip = zip_open("/tmp/never.zip", 6, 'w');

    zip_entry_open(zip, "test.file");
    zip_entry_fwrite(zip, "/tmp/test.txt");
    zip_entry_close(zip);

    zip_entry_open(zip, "test.content");
    zip_entry_write(zip, content, length(content));
    zip_entry_close(zip);

    zip_close(zip);
    0
}

The language comes with RingZip based on this library

load "ziplib.ring"

new Zip {
    setFileName("myfile.zip")
    open("w")
    newEntry() {
        open("test.c")
        writefile("test.c")
        close()
    }
    close()
}
$ zig build-exe main.zig -lc -lzip
const c = @cImport({
    @cInclude("zip.h");
});

pub fn main() void {
    var zip = c.zip_open("/tmp/zig.zip", 6, 'w');
    defer c.zip_close(zip);

    _ = c.zip_entry_open(zip, "test");
    defer _ = c.zip_entry_close(zip);

    const content = "test content";
    _ = c.zip_entry_write(zip, content, content.len);
}

Third party binding: thechampagne/zip-odin

package main

foreign import lib "system:zip"

import "core:c"

foreign lib {
    zip_open :: proc(zipname : cstring, level : c.int, mode : c.char) -> rawptr ---

    zip_close :: proc(zip : rawptr) ---

    zip_entry_open :: proc(zip : rawptr, entryname : cstring) -> c.int ---

    zip_entry_close :: proc(zip : rawptr) -> c.int ---

    zip_entry_write :: proc(zip : rawptr, buf : rawptr, bufsize : c.size_t) -> c.int ---
}

main :: proc() {
    zip_file := zip_open("odin.zip", 6, 'w')
    defer zip_close(zip_file)

    zip_entry_open(zip_file, "test")
    defer zip_entry_close(zip_file)

    content := "test content"
    zip_entry_write(zip_file, &content, len(content))
}

Third party binding: thechampagne/nimzip

$ nim c --passL:-lzip main.nim
proc zip_open(zipname: cstring, level: cint, mode: char): pointer {.importc.}
proc zip_close(zip: pointer) {.importc.}
proc zip_entry_open(zip: pointer, entryname: cstring): cint {.importc.}
proc zip_entry_close(zip: pointer): cint {.importc.}
proc zip_entry_write(zip: pointer, buf: pointer, bufsize: csize_t): cint {.importc.}

when isMainModule:
  var zip = zip_open("/tmp/nim.zip", 6, 'w')

  discard zip_entry_open(zip, "test")

  let content: cstring = "test content"
  discard zip_entry_write(zip, content, csize_t(len(content)))

  discard zip_entry_close(zip)
  zip_close(zip)

Third party binding: thechampagne/zip-d

$ dmd -L-lzip main.d
extern(C) void* zip_open(const(char)* zipname, int level, char mode);
extern(C) void zip_close(void* zip);
extern(C) int zip_entry_open(void* zip, const(char)* entryname);
extern(C) int zip_entry_close(void* zip);
extern(C) int zip_entry_write(void* zip, const(void)* buf, size_t bufsize);

void main()
{
  void* zip = zip_open("/tmp/d.zip", 6, 'w');
  scope(exit) zip_close(zip);

  zip_entry_open(zip, "test");
  scope(exit) zip_entry_close(zip);

  string content = "test content";
  zip_entry_write(zip, content.ptr, content.length);
}

Third party binding: thechampagne/zip-pascal

program main;

{$linklib c}
{$linklib zip}

uses ctypes;

function zip_open(zipname:Pchar; level:longint; mode:char):pointer;cdecl;external;
procedure zip_close(zip:pointer);cdecl;external;
function zip_entry_open(zip:pointer; entryname:Pchar):longint;cdecl;external;
function zip_entry_close(zip:pointer):longint;cdecl;external;
function zip_entry_write(zip:pointer; buf:pointer; bufsize:csize_t):longint;cdecl;external;

const
   content: Pchar = 'test content';
var
   zip : pointer;

begin
   zip := zip_open('/tmp/pascal.zip', 6, 'w');

   zip_entry_open(zip, 'test');

   zip_entry_write(zip, content, strlen(content));
   zip_entry_close(zip);
   zip_close(zip);
end.

Third party binding: gynt/luamemzip

-- Loads the luamemzip.dll
zip = require("luamemzip")

content = "Test content"

z = zip.zip_stream_open(nil, 6, 'w')

zip.zip_entry_open(z, "test.content")
zip.zip_entry_write(z, content)
zip.zip_entry_close(z)

data = zip.zip_stream_copy(z)

zip.zip_close(z)

Check out more cool projects which use this library

  • Filament: Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and as efficient as possible on Android.
  • Hermes JS Engine: Hermes is a JavaScript engine optimized for fast start-up of React Native apps on Android. It features ahead-of-time static optimization and compact bytecode.
  • Monster Mash: New Sketch-Based Modeling and Animation Tool.
  • Object-Oriented Graphics Rendering Engine: OGRE is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.
  • Open Asset Import Library: A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
  • PowerToys: Set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity.
  • The Ring Programming Language: Innovative and practical general-purpose multi-paradigm language.
  • The V Programming Language: Simple, fast, safe, compiled. For developing maintainable software.
  • TIC-80: TIC-80 is a FREE and OPEN SOURCE fantasy computer for making, playing and sharing tiny games.
  • Urho3D: Urho3D is a free lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D.
  • and more...

zip's People

Contributors

abrasat avatar appledragon avatar avp avatar bvgastel avatar cpupreme avatar dialga avatar drizt avatar exactly-one-kas avatar frideakisab avatar inobelar avatar jamesathey avatar jay-o-way avatar jinfeihan57 avatar kimkulling avatar kuba-- avatar mahmoudfayed avatar mohe2015 avatar mykhailopylyp avatar nesbox avatar paroj avatar polluks2 avatar prissi avatar prot0man avatar rbsheth avatar samuelmarks avatar spaceim avatar thechampagne avatar thp avatar timgates42 avatar zivke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zip's Issues

miniz Limitations

miniz is a Deflate/Inflate compression library.

But zip format include lzma, bzip2 method.
Any interested in adding these two algorithms?

If Yes : I want to help.

fopen_s return is error

https://msdn.microsoft.com/en-us/library/z5hh6ee9.aspx

fopen_s Return Value
Zero if successful; an error code on failure. See errno, _doserrno, _sys_errlist, and _sys_nerr for more information about these error codes.

in zip_entry_fwrite function:

#if defined(_MSC_VER) || defined(MINGW64)
if (!fopen_s(&stream, filename, "rb"))
#else
if (!(stream = fopen(filename, "rb")))
#endif
{
// Cannot open filename
return -1;
}

change:

#if defined(_MSC_VER) || defined(MINGW64)
if (0 != fopen_s(&stream, filename, "rb"))
#else
if (!(stream = fopen(filename, "rb")))
#endif
{
// Cannot open filename
return -1;
}

test_file_permissions failed

Compile with

$ gcc --version
gcc.exe (Rev1, Built by MSYS2 project) 8.2.0
ivan@winlix MINGW64 ~/dev/zip/mg
$ ./test/test.exe

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
[0]: test/test-1.txt
[1]: test/test-2.txt
[2]: test/empty/ (DIR)
[3]: empty/ (DIR)
Assertion failed!

Program: C:\msys64\home\ivan\dev\zip\mg\test\test.exe
File: C:/msys64/home/ivan/dev/zip/test/test.c, Line 323

Expression: 0 == zip_extract(ZIPNAME, ".", NULL, NULL)

Problem with 4.txt it open only for reading and remove function seems doesn't actually delete this opened file.

warning: dereferencing type-punned pointer

Some extra warnings with MinGW 4.9.2

[2/5] C:\Qt\Tools\mingw492_32\bin\gcc.exe    -std=c99 -Wall -Wextra -pedantic -O3 -DNDEBUG -MMD -MT CMakeFiles/zip.dir/src/zip.c.obj -MF CMakeFiles/zip.dir/src/zip.c.obj.d -o CMakeFiles/zip.dir/src/zip.c.obj   -c ../src/zip.c
In file included from ../src/zip.c:35:0:
../src/miniz.h: In function 'tdefl_find_match':
../src/miniz.h:3191:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
   ^
../src/miniz.h:3208:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3209:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3210:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3237:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
       ^
../src/miniz.h: In function 'tdefl_compress_fast':
../src/miniz.h:3339:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
                                  (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
                                  ^
[3/5] C:\Qt\Tools\mingw492_32\bin\gcc.exe   -I../test/../src -std=c99 -Wall -Wextra -pedantic -O3 -DNDEBUG -MMD -MT test/CMakeFiles/test.exe.dir/__/src/zip.c.obj -MF test/CMakeFiles/test.exe.dir/__/src/zip.c.obj.d -o test/CMakeFiles/test.exe.dir/__/src/zip.c.obj   -c ../src/zip.c
In file included from ../src/zip.c:35:0:
../src/miniz.h: In function 'tdefl_find_match':
../src/miniz.h:3191:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
   ^
../src/miniz.h:3208:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3209:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3210:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       TDEFL_PROBE;
       ^
../src/miniz.h:3237:7: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
       c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
       ^
../src/miniz.h: In function 'tdefl_compress_fast':
../src/miniz.h:3339:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
                                  (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &

miniz.h upgrade

I found the miniz.h now we are using is v1.15, it's too old and may have bugs (newest version is 2.0.8).

Do we have a plan to upgrade it? Or, is it safe that I just upgrade the miniz.h without changing any codes in zip.h?

It changes from v1.x to v2.x so I want to confirm. I'm not familiar with zlib & miniz low-level API :(
But this library is ez to use.

supply buffer to read function

I'm working with a memory managed system (Matlab) and was wondering if it would be possible to have the following functions:

  1. extern size_t *zip_entry_size(struct zip_t *zip) - return the # of bytes of the current entry
  2. extern int zip_entry_read2(struct zip_t *zip, void *buf, size_t bufsize) -User passes in the buffer, the bufsize here is the size of the input buffer ...

The alternative, which is ok for now, is to memcpy after reading, but I'd prefer to avoid this.

max zip entries

Hi,

I discovered that the maximum number of entries in a zip file is 65535.
Any chance that this limitation could be increased?

Cheers
ds

Can I add empty directories?

I don't see anything for that in this wrapper, would have expected /dir to work or am I missing something obvious? Great project btw, was strapped for time and had issues with a 55loc dep and miniz was a bit too verbose to grasp quickly.

TDM gcc support

@kuba--
makefiles were generated but what do I need to make object file?
Log is below.


Dell@Dell-PC MINGW64 ~/Desktop/zip-master/build
$ make
[ 14%] Building C object CMakeFiles/zip.dir/src/zip.c.obj
In file included from C:\Users\Dell\Desktop\zip-master\src\zip.c:39:0:
C:\Users\Dell\Desktop\zip-master\src\miniz.h: In function 'mz_zip_file_read_func':
C:\Users\Dell\Desktop\zip-master\src\miniz.h:4083:20: error: implicit declaration of function 'ftello64' [-Werror=implicit-function-declaration]
 #define MZ_FTELL64 ftello64
                    ^
C:\Users\Dell\Desktop\zip-master\src\miniz.h:4659:22: note: in expansion of macro 'MZ_FTELL64'
   mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
                      ^
C:\Users\Dell\Desktop\zip-master\src\miniz.h:4084:20: error: implicit declaration of function 'fseeko64' [-Werror=implicit-function-declaration]
 #define MZ_FSEEK64 fseeko64
                    ^
C:\Users\Dell\Desktop\zip-master\src\miniz.h:4662:9: note: in expansion of macro 'MZ_FSEEK64'
        (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
         ^
In file included from C:\Users\Dell\Desktop\zip-master\src\zip.c:40:0:
C:\Users\Dell\Desktop\zip-master\src\zip.h: At top level:
C:\Users\Dell\Desktop\zip-master\src\zip.h:24:15: error: conflicting types for 'ssize_t'
 typedef long  ssize_t;  /* byte count or error */
               ^
In file included from I:/TDM-GCC-32/include/sys/stat.h:24:0,
                 from C:\Users\Dell\Desktop\zip-master\src\zip.c:13:
I:/TDM-GCC-32/include/sys/types.h:118:18: note: previous declaration of 'ssize_t' was here
 typedef _ssize_t ssize_t;
                  ^
C:\Users\Dell\Desktop\zip-master\src\zip.c: In function 'zip_entry_fwrite':
C:\Users\Dell\Desktop\zip-master\src\zip.c:596:7: error: implicit declaration of function 'fopen_s' [-Werror=implicit-function-declaration]
   if (fopen_s(&stream, filename, "rb"))
       ^
C:\Users\Dell\Desktop\zip-master\src\zip.c: In function 'zip_extract':
C:\Users\Dell\Desktop\zip-master\src\zip.c:841:3: error: implicit declaration of function 'strcpy_s' [-Werror=implicit-function-declaration]
   strcpy_s(path, MAX_PATH, dir);
   ^
C:\Users\Dell\Desktop\zip-master\src\zip.c:863:5: error: implicit declaration of function 'strncpy_s' [-Werror=implicit-function-declaration]
     strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename,
     ^
cc1.exe: all warnings being treated as errors
make[2]: *** [CMakeFiles/zip.dir/src/zip.c.obj] Error 1
make[1]: *** [CMakeFiles/zip.dir/all] Error 2
make: *** [all] Error 2

miniz.h bugfix

miniz currently does not support x86 compilers that disallow unaligned loads and stores. As a result, neither does this wonderful library :). I've opened a pull request (richgel999/miniz#124) to fix the missing guard upstream. Since you have a modified copy of miniz.h, I'm going to open a pull request to add that fix to your version as well.

Check localtime_s

See this. #define's look strange. Furthemore miniz just check only for _MSC_VER. I don't sure that localtime_s return zero on successful with __MINGW64__.

Issue generating zip windows MSYS

I'm having trouble with a simple example under Windows using MSYS2 where the same example works fine under cygwin and Mac. Here's the code:

#include
#include "zip.h"

using namespace std;

int main (int argc, char **argv)
{
cout << "Generating zip..." << endl;

struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
    zip_entry_open(zip, "bufWriteEntry");
    {
        const char *buf = "Some data here...";
        zip_entry_write(zip, buf, strlen(buf));
    }
    zip_entry_close(zip);

    zip_entry_open(zip, "fwriteEntry");
    {
        zip_entry_fwrite(zip, "one.txt");
    }
    zip_entry_close(zip);
}
zip_close(zip);

cout << "Done!" << endl;

}


After running the test above, the resulting zip file foo.zip is empty:

$ ls -l foo.zip
-rwxr-x---+ 1 Administrator None 65 Aug 1 15:05 foo.zip

$ unzip -l foo.zip
Archive: foo.zip
warning [foo.zip]: zipfile is empty

I'm building the library and test apps in MSYS2 MinGW 64 shell as follows:

$ mkdir build
$ cd build
$ cmake -G "MSYS Makefiles" -DBUILD_SHARED_LIBS=true ..
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/g++.exe
-- Check for working CXX compiler: C:/msys64/mingw64/bin/g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/code/zip/build

$ make
Scanning dependencies of target zip
[ 20%] Building C object CMakeFiles/zip.dir/src/zip.c.obj
[ 40%] Linking C shared library libzip.dll
[ 40%] Built target zip
Scanning dependencies of target test.exe
[ 60%] Building C object test/CMakeFiles/test.exe.dir/test.c.obj
[ 80%] Building C object test/CMakeFiles/test.exe.dir/__/src/zip.c.obj
[100%] Linking C executable test.exe.exe
[100%] Built target test.exe

To build test code above

$ cd ..
$ g++ -D_WIN32 -static-libgcc -static-libstdc++ -std=c++11 -Isrc -static msys-test.cpp build/libzip.dll.a

Any suggestions?

configuration failed!

When I tried to build cmake files I got this error

$ cmake -DBUILD_SHARED_LIBS=true ..
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:2 (project):
  The CMAKE_C_COMPILER:

    cl

  is not a full path and was not found in the PATH.

  To use the NMake generator with Visual C++, cmake must be run from a shell
  that can use the compiler cl from the command line.  This environment is
  unable to invoke the cl compiler.  To fix this problem, run cmake from the
  Visual Studio Command Prompt (vcvarsall.bat).

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


CMake Error at CMakeLists.txt:2 (project):
  The CMAKE_CXX_COMPILER:

    cl

  is not a full path and was not found in the PATH.

  To use the NMake generator with Visual C++, cmake must be run from a shell
  that can use the compiler cl from the command line.  This environment is
  unable to invoke the cl compiler.  To fix this problem, run cmake from the
  Visual Studio Command Prompt (vcvarsall.bat).

  Tell CMake where to find the compiler by setting either the environment
  variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.


-- Configuring incomplete, errors occurred!
See also "C:/Users/Dell/Desktop/zip-master/build/CMakeFiles/CMakeOutput.log".
See also "C:/Users/Dell/Desktop/zip-master/build/CMakeFiles/CMakeError.log".

I have GCC compiler set in my environment variables, tell me how to set CC and CXX paths in environment variables.
I'm a troubled noob, please help me.

heap-buffer-overflow on reading

=================================================================
==22015==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x621000003b15 at pc 0x7f53d23e466e bp 0x7ffeb9504de0 sp 0x7ffeb9504588
READ of size 4630 at 0x621000003b15 thread T0
    #0 0x7f53d23e466d  (/usr/lib/gcc/x86_64-linux-gnu/7/libasan.so+0x5166d)
    #1 0x7f53d213fc9d in nlohmann::detail::input_adapter::input_adapter<char*, 0>(char*) /home/max/WMT/lib/../lib/json.hpp:4242
    #2 0x7f53d2139f14 in WMT_ReadDroidsJSON(WZmap*) /home/max/WMT/lib/wmt.cpp:1229
    #3 0x7f53d213a8d6 in WMT_ReadDroidsFile(WZmap*) /home/max/WMT/lib/wmt.cpp:1322
    #4 0x7f53d213adab in WMT_ReadMap(char*, WZmap*) /home/max/WMT/lib/wmt.cpp:1389
    #5 0x5623b6b73099 in main /home/max/WMT/src/main.cpp:280
    #6 0x7f53d1554b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #7 0x5623b6b715f9 in _start (/home/max/WMT/build/bin/wmt+0x15f9)

0x621000003b15 is located 0 bytes to the right of 4629-byte region [0x621000002900,0x621000003b15)
allocated by thread T0 here:
    #0 0x7f53d2471b40 in __interceptor_malloc (/usr/lib/gcc/x86_64-linux-gnu/7/libasan.so+0xdeb40)
    #1 0x7f53d215fad6 in def_alloc_func /home/max/WMT/lib/miniz.h:1443
    #2 0x7f53d216f267 in mz_zip_reader_extract_to_heap /home/max/WMT/lib/miniz.h:5463
    #3 0x7f53d21755cc in zip_entry_read /home/max/WMT/lib/zip.cpp:669
    #4 0x7f53d2139e64 in WMT_ReadDroidsJSON(WZmap*) /home/max/WMT/lib/wmt.cpp:1221
    #5 0x7f53d213a8d6 in WMT_ReadDroidsFile(WZmap*) /home/max/WMT/lib/wmt.cpp:1322
    #6 0x7f53d213adab in WMT_ReadMap(char*, WZmap*) /home/max/WMT/lib/wmt.cpp:1389
    #7 0x5623b6b73099 in main /home/max/WMT/src/main.cpp:280
    #8 0x7f53d1554b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/gcc/x86_64-linux-gnu/7/libasan.so+0x5166d) 
Shadow bytes around the buggy address:
  0x0c427fff8710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff8720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff8730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff8740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff8750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fff8760: 00 00[05]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff8770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff8780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff8790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff87a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff87b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==22015==ABORTING

Related: nlohmann/json#2092
https://github.com/maxsupermanhd/WMT/blob/JSON-test/lib/wmt.cpp#L1068
Build howto is in README.md. I can send you core dump if you wish.
File required: 10c-da-bdctw10-v1max.zip
Run with ./bin/wmt 10c-da-bdctw10-v1max.zip -z 5 -feh -v999

zip_entry_open + windows

zip_entry_open(zip, "EmoPacks/PeerWeb.xml"); - OK

zip_entry_open(zip, "EmoPacks\PeerWeb.xml"); - Error

bug?

Miniz is out of date, and no way to avoid symbol clash

I have a project/lib that already includes miniz from somewhere else, (a PNG encoder/decoder) so I end up with multiple symbols.

As both were using this header-only lib at 1.15, I've deleted both and replaced with https://github.com/richgel999/miniz (2.1.0) which is released as a .c and a .h so I don't have multiple symbols.

I can see the benefit of having a single include in your library, so I propose being able to make a NO_MINIZ_INCLUDE macro I can define before including zip.h so I can include my own miniz.h first (which has no definitions)

(Will submit a PR at some point, but making a note here first)

Preserve File Permissions

The ZIP file format stores the file permissions for each of its entries as set on platforms such as linux and mac (i.e. whether a file is executable, etc). However when extracting files with this library it appears that the permissions are not set correctly on the extracted files. So if you zip up an executable file it will not be executable when extracted with this library however if the same zip is extracted by another zip program the files are executable when extracted.

Does this library support this feature or is it possible to add this?

Linking error with MinGW 4.8.2

Here I just copied my question from StackOverflow.

I need to compile some library (kuba zip) with MinGW 4.8.2. I got linking error.

[2/2 12.0/sec] Linking C executable test\test.exe.exe
FAILED: test/test.exe.exe 
cmd.exe /C "cd . && C:\mingw32\bin\gcc.exe  -std=c99 -Wall -Wextra -pedantic -g   test/CMakeFiles/test.exe.dir/test.c.obj test/CMakeFiles/test.exe.dir/__/src/zip.c.obj  -o test\test.exe.exe -Wl,--out-implib,test\libtest.exe.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
test/CMakeFiles/test.exe.dir/__/src/zip.c.obj: In function `zip_entry_close':
C:\msys64\home\ivan\dev\zip\debug-qt4/../src/zip.c:440: undefined reference to `localtime_s'

Here problem in localtime_s function. localtime_s is declared as inline and must be inlined. But by fact it is not happens.

localtime_s declaration.

__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); }

I wrote some testcase for this.

#include <time.h>
int main()
{
    struct tm _Tm;
    time_t _Time;
    localtime_s(&_Tm, &_Time);
    return 0;
}

With gcc it produces link error:

$ gcc localtime_test.c
C:\msys64\tmp\ccEMjUQ8.o:localtime_test.c:(.text+0x1e): undefined reference to `localtime_s'
collect2.exe: error: ld returned 1 exit status

But no error with g++ or MinGW 5.3.0 (both gcc and g++). So how to make my testcase working with MinGW 4.8.2 gcc?

I know that I can just use _localtime32_s in my case and it will work. But this seems some incorrect decision.

Beginner's questions: I don't know how properly store files inside the zip file

I am working in a software that I need to store some HTML and JPG files inside a ZIP file (actually I am aiming to make an EPUB file). I find your software amazing and it seems to fit my needs, but I am finding some difficulties because of my newbieness. Firstly, here is my code:

#include <stdio.h>
#include "zip.h"

int main(int argc, char *argv[])
{
	struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
	{
		zip_entry_open(zip, "x.jpg");
		{
			zip_entry_fwrite(zip, "z.jpg");
			zip_entry_fwrite(zip, "w.png");
		}
		zip_entry_close(zip);
	}
	zip_close(zip);
}
  1. First, the x.jpg file is not added to the ZIP file and the z.jpg file is renamed to "x.jpg"...
  2. I can't see the file w.png, but seems that its "weight" was added to the x.jpg file (which actually is the z.jpg file...)
  3. In the case of adding a HTML or image file, what am I supposed to add in the line const char *buf = "Some data here...\0";?

unicode file names in zip content?

does it support unicode files names in zip content?

try to pass some UTF-8 chars as file name, but got wrong file names when opened by other zip tools, won't happen if all file names are ASCII chars

Directory traversal vulnerability when handling crafted zip file

Impact

This vulnerability could allow the attacker to write a file to an arbitrary directory.

How to reproduce

On the latest version (0.1.19) and the master branch of zip:

To reproduce the issue, you may try to extract this crafted zip file, which contains two files good.txt and ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../tmp/evil.txt. After extraction, you will find evil.txt is at /tmp, which should be at ./tmp.

Here is the [PoC repo] (https://github.com/jiahao42/PoC/tree/master/zip%40kuba--).

Root cause

This root cause is that zip doesn't normalize the path in mz_zip_reader_file_stat in miniz.h.

Patch

#124 should be able to fix the problem.

zip_extract doesn't work if not on main OS drive?

I'm using this lib in a Qt app and everything works as expected until I move the app to another drive. This line of code works as expected if the application resides on C (the main drive where the OS is installed). Moving it to somewhere like F and nothing gets extracted.

zip_extract(input_filename, temporary_dir, nullptr, nullptr);

In my test case, input_filename is also on C and temporary_dir is a folder created in the temp directory (also on C). I'm using MSVC 2017 on Windows 10. Even running as admin I get the same issue.

sfx

Hello,
Is there a way to unzip sfx archive ?

Printf can't print st_mtime

Test.c: Lines 430 -> 432

 fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime);
 fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime);
 assert(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1);

On my Windows 10 64-bit machine, using GCC, it'll give you compiler errors because .st_mtime returns long long int instead of long unsigned int. It compiles perfectly fine with MSVC. A temporary fix is to use casts like so:

 fprintf(stdout, "file_stat1.st_mtime: %lu\n", (long unsigned) file_stat1.st_mtime);
 fprintf(stdout, "file_stat2.st_mtime: %lu\n", (long unsigned) file_stat2.st_mtime);
 assert(labs((long) (file_stat1.st_mtime - file_stat2.st_mtime)) <= 1);

But I don't know if it'll cause issues down the line.
EDIT: There are also various more related issues all around the code. I'll look at it later.

UTF8 File Name Support on Windows Platform

Hi,

On windows platform non-ascii file names created incorrectly.
miniz use fopen_s and freopen_s to create and redirect the pre-opened files.
It might be better to use _wfopen_s and _wfreopen_s methods which supports wchar.

Also zip.c (line 548) use fopen to read files. Its better to replace it with _wfopen_s

Thanks

Unzip a file

Hello, when I try to uncompress a file in a dir on windows. I have the next problem.
Cannot convert 'int (* (_closure )(const char *,void *))(const char *,void )' to 'int ()(const char *,void *)'
I only use the steps in the help.

How to add a folder into zip

Hi,
I have a case which needs compress some regular files and a folder with some other regular files into a zip. Is there anyway to compress a folder into zip with this library.

Many thanks!

Runtime error on creating archive

lib/miniz.h:4630:15: runtime error: load of misaligned address 0x7fff23b7d17b for type 'const mz_uint32', which requires 4 byte alignment
0x7fff23b7d17b: note: pointer points here
 03  00 00 e5 4b 01 00 00 00  00 00 00 00 00 00 00 00  00 8d c9 2e b8 68 20 11  d0 d1 b7 23 ff 7f 00
              ^ 

zip doesn't compile on 32b system with GCC 9.2.0

Trying to compile assimp for Alpine Linux on 32bit platforms and there seems to be an issue with ssize_t decleration:

[ 62%] Building CXX object code/CMakeFiles/assimp.dir/__/contrib/poly2tri/poly2tri/sweep/cdt.cc.o
In file included from /home/buildozer/aports/testing/assimp/src/assimp-5.0.0/code/3MF/D3MFExporter.cpp:61:
/home/buildozer/aports/testing/assimp/src/assimp-5.0.0/contrib/zip/src/zip.h:30:15: error: conflicting declaration 'typedef long int ssize_t'
   30 | typedef long  ssize_t;  /* byte count or error */
      |               ^~~~~~~
In file included from /usr/include/stdio.h:26,
                 from /usr/include/fortify/stdio.h:22,
                 from /usr/include/c++/9.2.0/cstdio:42,
                 from /usr/include/c++/9.2.0/ext/string_conversions.h:43,
                 from /usr/include/c++/9.2.0/bits/basic_string.h:6493,
                 from /usr/include/c++/9.2.0/string:55,
                 from /usr/include/c++/9.2.0/stdexcept:39,
                 from /usr/include/c++/9.2.0/array:39,
                 from /usr/include/c++/9.2.0/tuple:39,
                 from /usr/include/c++/9.2.0/bits/unique_ptr.h:37,
                 from /usr/include/c++/9.2.0/memory:80,
                 from /home/buildozer/aports/testing/assimp/src/assimp-5.0.0/code/3MF/D3MFExporter.h:44,
                 from /home/buildozer/aports/testing/assimp/src/assimp-5.0.0/code/3MF/D3MFExporter.cpp:45:
/usr/include/bits/alltypes.h:151:15: note: previous declaration as 'typedef int ssize_t'
  151 | typedef _Addr ssize_t;
      |               ^~~~~~~

CI output might be of interest: https://cloud.drone.io/alpinelinux/aports/13069 and AL PR alpinelinux/aports#11998

I posted this to assimp/assimp#2733 as well.

File hasn't read access after unpacking

I use zip_entry_write to write data to archive. Such unpacked file has no any access. On Linux it's a problem when working in console. So need a way to manually set zip->entry.external_attr.

Implement zip_entry_read

It would be nice to have zip_entry_read(). Sometimes we only want to read a single file of an archive, change it and save it back.

I didn't see a simple way to do it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.