Refactor package module into C #6

Open
GreekStapler wants to merge 25 commits from GreekStapler/libvieter:package into dev
17 changed files with 1156 additions and 3 deletions

View File

@ -6,15 +6,20 @@ LIB_FILENAME ?= libvieter.a
BUILD_DIR ?= build
SRC_DIR ?= src
TEST_DIR ?= test
INC_DIRS ?= include
3RDPARTY_DIR ?= thirdparty
INCLUDE_DIR ?= include
INC_DIRS ?= $(INCLUDE_DIR) $(3RDPARTY_DIR)/include
LIB := $(BUILD_DIR)/$(LIB_FILENAME)
SRCS != find '$(SRC_DIR)' -iname '*.c'
SRCS_H != find $(INC_DIRS) '$(SRC_DIR)' -iname '*.h'
SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
SRCS_3RDPARTY != find '$(3RDPARTY_DIR)/src' -iname '*.c'
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
$(info ${SRCS})
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) $(SRCS_3RDPARTY:%=$(BUILD_DIR)/%.o)
OBJS_TEST := $(SRCS_TEST:%=$(BUILD_DIR)/%.o)
DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d)
@ -22,6 +27,7 @@ BINS_TEST := $(OBJS_TEST:%.c.o=%)
TARGETS_TEST := $(BINS_TEST:%=test-%)
TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%)
LIBFLAGS := -larchive
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# -MMD: generate a .d file for every source file. This file can be imported by
@ -50,6 +56,9 @@ $(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c
mkdir -p $(dir $@)
$(CC) $(VIETERCFLAGS) -c $< -o $@
$(BUILD_DIR)/$(3RDPARTY_DIR)/src/%.c.o: $(3RDPARTY_DIR)/src/%.c
mkdir -p $(dir $@)
$(CC) $(VIETERCFLAGS) -c $< -o $@
# =====TESTING=====
.PHONY: test
@ -71,7 +80,7 @@ build-test: $(BINS_TEST)
$(BINS_TEST): %: %.c.o $(LIB)
$(CC) \
$^ -o $@
$^ $(LIBFLAGS) -o $@
# Along with the include directory, each test includes $(TEST_DIR) (which
# contains the acutest.h header file), and the src directory of the module it's

View File

@ -15,6 +15,10 @@ See the [source code](src) for the list of modules.
Everything is handled by the provided Makefile. To compile the static library,
simply run `make`.
### Required libraries
Libvieter requires libarchive.
### Project structure
Each module has its own subdirectory inside `src`, e.g. `src/cron`. This

View File

@ -0,0 +1,34 @@
#ifndef VIETER_DYNARRAY
#define VIETER_DYNARRAY
#include <stdlib.h>
#include <string.h>
typedef struct vieter_dynarray {
char **array;
size_t capacity;
size_t size;
} vieter_dynarray;
/*
* Allocate a dynamic array.
*/
vieter_dynarray *vieter_dynarray_init(size_t initial_capacity);
/*
* Initialise array (if it's not already initialised) and insert a string.
*/
void vieter_dynarray_add(vieter_dynarray *da, const char *s);
/*
* Deallocate dynamic array.
*/
void vieter_dynarray_free(vieter_dynarray *da);
/*
* Convert a vieter_dynarray into an array by freeing all its surrounding
* components and returning the underlying array pointer.
*/
char **vieter_dynarray_convert(vieter_dynarray *da);
#endif

View File

@ -0,0 +1,33 @@
#ifndef VIETER_PACKAGE
#define VIETER_PACKAGE
typedef struct vieter_package vieter_package;
typedef enum vieter_package_error {
vieter_package_ok = 0,
vieter_package_unarchive_error = 1,
vieter_package_stat_error = 2
} vieter_package_error;
/*
* Allocate an empty package
*/
vieter_package *vieter_package_init();
/*
* Parse package file into something usable by libvieter.
*/
vieter_package_error vieter_package_read_archive(vieter_package *pkg,
const char *pkg_path);
/*

I don't personally use this style of free function right now, but it might be interesting to migrate all free functions to this style indeed. I'm assuming the pointer-to-pointer is so you can set the variable containing the pointer to NULL as well?

I don't personally use this style of free function right now, but it might be interesting to migrate all free functions to this style indeed. I'm assuming the pointer-to-pointer is so you can set the variable containing the pointer to NULL as well?

Yeah, dangling pointers can cause some real headaches, so I prefer to have free functions set the pointer to NULL themselves to make it less error prone.

Yeah, dangling pointers can cause some real headaches, so I prefer to have free functions set the pointer to NULL themselves to make it less error prone.
* Deallocate a package.
*/
void vieter_package_free(vieter_package **ptp);
/*
* Create string that will become the package's desc file.
*/
char *vieter_package_to_description(vieter_package *pkg);
#endif

View File

@ -0,0 +1,58 @@
#include "vieter_dynarray.h"
vieter_dynarray *vieter_dynarray_init(size_t initial_capacity) {
vieter_dynarray *da = malloc(sizeof(vieter_dynarray));
da->size = 0;
da->capacity = initial_capacity;
return da;
}
void vieter_dynarray_add(vieter_dynarray *da, const char *s) {
// An empty vieter_dynarray does not have an allocated internal array
// yet
if (da->size == 0) {
da->array = malloc(sizeof(char *) * da->capacity);
// Initialise all char*'s to 0 so array[i] == NULL can be used to see if
// field is empty
memset(da->array, 0, sizeof(char *) * da->capacity);
}
// Double array size if it's full
else if (da->size == da->capacity) {
// if the realloc fails, access to memory in da->array is lost
da->array = realloc(da->array, sizeof(char *) * da->capacity * 2);
da->capacity *= 2;
// Same as the previous memset, but only for newly allocated pointers
memset(da->array + da->size, 0, sizeof(char *) * da->capacity / 2);
}
da->array[da->size] = strdup(s);
da->size++;
}
void vieter_dynarray_free(vieter_dynarray *da) {
if (da == NULL) {
return;
}
if (da->array != NULL) {
for (size_t i = 0; i < da->size; i++) {
free(da->array[i]);
}
free(da->array);
}
free(da);
}
char **vieter_dynarray_convert(vieter_dynarray *da) {
char **array = da->array;
da->array = NULL;
vieter_dynarray_free(da);
return array;
}

View File

@ -0,0 +1,5 @@
# package
This module handles both parsing the published Arch tarballs & the contents of
their `.PKGINFO` files, as well as generating the contents of the database
archives' `desc` & `files` files.

View File

@ -0,0 +1,263 @@
#include <archive.h>
#include <archive_entry.h>
#include <stdbool.h>
#include <stdlib.h>
#include "sha256.h"
#include "vieter_package_internal.h"

General note for snprintf usage: what happens if the value is larger than the buffer? Is it simply cut off? Cuz if so, we shouldn't be making assumptions about the length of the input.

General note for `snprintf` usage: what happens if the value is larger than the buffer? Is it simply cut off? Cuz if so, we shouldn't be making assumptions about the length of the input.

I used snprintf because I didn't want to risk any buffer overflows, but it can truncate perfectly valid inputs if they are long enough (e.g. very long url). I'll turn aux into a malloc'd string and use the return value of snprintf to reallocate memory as is necessary without any overflows.

I used `snprintf` because I didn't want to risk any buffer overflows, but it can truncate perfectly valid inputs if they are long enough (e.g. very long url). I'll turn `aux` into a malloc'd string and use the return value of `snprintf` to reallocate memory as is necessary without any overflows.
#define ADD_STRING(section, field) \
if (pkg_info->field != 0) { \
size_to_be_written = \
snprintf(aux, small_buff_size, section, pkg_info->field); \
if (size_to_be_written > small_buff_size) { \
aux = realloc(aux, size_to_be_written + 1); \
small_buff_size = size_to_be_written + 1; \
snprintf(aux, small_buff_size, section, pkg_info->field); \
} \
if (buff_size < strlen(description) + small_buff_size + 1) { \
description = realloc(description, buff_size * 2); \
buff_size *= 2; \
} \

This check is not safe, the dynarray code doesn't make any guarantees about empty fields being NULL, they're simply malloc'ed and not initialised.

This check is not safe, the dynarray code doesn't make any guarantees about empty fields being NULL, they're simply malloc'ed and not initialised.
strcat(description, aux); \
}
#define ADD_ARRAY(section, field) \
i = 0; \
if (pkg_info->field != NULL) { \
ADD_STRING(section, field->array[i]); \
i++; \
while (pkg_info->field->array[i] != NULL) { \
ADD_STRING("\n%s", field->array[i]); \
i++; \
} \
}
static char *ignored_names[5] = {".BUILDINFO", ".INSTALL", ".MTREE", ".PKGINFO",
".CHANGELOG"};
static size_t ignored_words_len = sizeof(ignored_names) / sizeof(char *);
vieter_package *vieter_package_init() {
return calloc(sizeof(vieter_package_info), 1);
GreekStapler marked this conversation as resolved Outdated

Shouldn't this be sizeof(a package)?

Shouldn't this be `sizeof(a package)`?
}
vieter_package_error vieter_package_read_archive(vieter_package *pkg,
const char *pkg_path) {
struct archive *a = archive_read_new();
struct archive_entry *entry;
// These three are the most commonly used compression methods
archive_read_support_filter_zstd(a);
archive_read_support_filter_gzip(a);
archive_read_support_filter_xz(a);
// Contents should always be a tarball
archive_read_support_format_tar(a);
// TODO where does this 10240 come from?
int r = archive_read_open_filename(a, pkg_path, 10240);
// Exit early if we weren't able to successfully open the archive for reading
if (r != ARCHIVE_OK) {

Returning NULL when a function fails doesn't say anything about why the function failed. A better API imo (which I also use in the heap module) is for the function to return an enum value intead, indicating the success of the function. The output is written to a pointer-to-pointer that is passed as the first argument of the function.

See the heap module for an example.

Returning `NULL` when a function fails doesn't say anything about why the function failed. A better API imo (which I also use in the heap module) is for the function to return an enum value intead, indicating the success of the function. The output is written to a pointer-to-pointer that is passed as the first argument of the function. See the heap module for an example.
return vieter_package_unarchive_error;
}
int compression_code = archive_filter_code(a, 0);
const char *path_name;
vieter_package_info *pkg_info = NULL;
vieter_dynarray *files = vieter_dynarray_init(16);
vieter_dynarray_add(files, "%FILES%");
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
path_name = archive_entry_pathname(entry);
bool ignore = false;
for (size_t i = 0; i < ignored_words_len; i++) {
if (strcmp(path_name, ignored_names[i]) == 0) {
ignore = true;
break;
}
}
if (!ignore) {
vieter_dynarray_add(files, path_name);
}
if (strcmp(path_name, ".PKGINFO") == 0) {
// Read data of file into memory buffer
int size = archive_entry_size(entry);
char *buf = malloc(size + 1);
archive_read_data(a, buf, size);
buf[size] = '\0';
// Parse package vieter_package_info string into a struct
pkg_info = vieter_package_info_init();
vieter_package_info_parse(pkg_info, buf);
free(buf);
} else {
archive_read_data_skip(a);
}
}
// Get size of file
struct stat stats;

Same here

Same here
if (stat(pkg_path, &stats) != 0) {
// errno is set if stat() fails; the calling function should check
// the value of errno in case vieter_package_stat_error is returned
return vieter_package_stat_error;
}
pkg_info->csize = stats.st_size;
archive_read_free(a);
// Create final return value
pkg->path = strdup(pkg_path);
pkg->info = pkg_info;
pkg->files = files;
pkg->compression = compression_code;
return vieter_package_ok;

As mentioned on matrix, this function should become a streaming one.

As mentioned on matrix, this function should become a streaming one.
}
void vieter_package_sha256sum(vieter_package *pkg, char *res) {
FILE *f = fopen(pkg->path, "r");
// Try to read 100KiB at a time
unsigned char *in = malloc(102400);
// Actual number of bytes read
size_t read_size;
SHA256_CTX *ctx = malloc(sizeof(SHA256_CTX));
sha256_init(ctx);
while ((read_size = fread(in, 1, 102400, f)) != 0) {
sha256_update(ctx, in, read_size);
}
unsigned char hash[SHA256_BLOCK_SIZE];
sha256_final(ctx, hash);
fclose(f);
free(in);
free(ctx);
// We need to convert the bytes in the hash to get a string representation of
// its hex values i.e. turn 1001 1111 into the string "9f" Each byte of the
// hash is going to turn into two bytes in the final string so we are going to
// convert each half byte into a char
unsigned int half_byte = 0;
int j = 0;
// We advance 2 bytes in the string for every one byte of the hash
for (int i = 0; i < SHA256_BLOCK_SIZE; i++) {

Oh smart, no array indexing required, didn't even think of that ;p

Oh smart, no array indexing required, didn't even think of that ;p
// We transform the first half byte into the second character to keep
// each byte from becoming reversed in the final string
half_byte = hash[i] & 0b1111;
if (half_byte < 10) {
res[j + 1] = half_byte + 48;
} else {
res[j + 1] = half_byte + 87;
}
hash[i] = hash[i] >> 4;
half_byte = hash[i] & 0b1111;
if (half_byte < 10) {
res[j] = half_byte + 48;
} else {
res[j] = half_byte + 87;
}
j += 2;
}
res[j] = '\0';
}

This should also use SMALL_BUFF_SIZE I think, just for consistency.

This should also use `SMALL_BUFF_SIZE` I think, just for consistency.
char *vieter_package_to_description(vieter_package *pkg) {
vieter_package_info *pkg_info = pkg->info;
size_t buff_size = 1024;
int small_buff_size = 128;
int size_to_be_written;
char *aux = malloc(sizeof(char) * small_buff_size);
char *description = malloc(sizeof(char) * buff_size);

Vieter doesn't only supports zstd-compressed archives. Currently it also accepts xz- or gzip-compressed archives, so this should be accounted for.

This choice was made noteably because Archlinux ARM uses xz-compressed archives instead of zstd.

Vieter doesn't only supports zstd-compressed archives. Currently it also accepts xz- or gzip-compressed archives, so this should be accounted for. This choice was made noteably because Archlinux ARM uses xz-compressed archives instead of zstd.
// Helper variable for ADD_ARRAY macro
int i;
// special case for FILENAME
char *ext = NULL;
switch (pkg->compression) {
case 0:
ext = ".tar";
break;
case 1:
ext = ".tar.gz";
break;
case 6:
ext = ".tar.xz";
break;
case 14:
ext = ".tar.zst";
break;
}
size_to_be_written =
snprintf(aux, small_buff_size, "%%FILENAME%%\n%s-%s-%s.pkg%s",
pkg_info->name, pkg_info->version, pkg_info->arch, ext);
// We neither want to let an arbritrarily long input to overflow the buffer
// nor to truncate perfectly valid inputs
if (size_to_be_written > small_buff_size) {
aux = realloc(aux, size_to_be_written + 1);
small_buff_size = size_to_be_written + 1;
snprintf(aux, small_buff_size, "%%FILENAME%%\n%s-%s-%s.pkg.tar.zst",
pkg_info->name, pkg_info->version, pkg_info->arch);
}
strcpy(description, aux);
ADD_STRING("\n\n%%NAME%%\n%s", name);
ADD_STRING("\n\n%%BASE%%\n%s", base);
ADD_STRING("\n\n%%VERSION%%\n%s", version);
ADD_STRING("\n\n%%DESC%%\n%s", description);
ADD_ARRAY("\n\n%%GROUPS%%\n%s", groups);
ADD_STRING("\n\n%%CSIZE%%\n%ld", csize);
ADD_STRING("\n\n%%ISIZE%%\n%ld", size);
char checksum[SHA256_BLOCK_SIZE * 2 + 1];
vieter_package_sha256sum(pkg, checksum);
snprintf(aux, small_buff_size, "\n\n%%SHA256SUM%%\n%s", checksum);
if (buff_size < strlen(description) + small_buff_size + 1) {
description = realloc(description, buff_size * 2);
buff_size *= 2;
}
strcat(description, aux);
ADD_STRING("\n\n%%URL%%\n%s", url);
ADD_ARRAY("\n\n%%LICENSE%%\n%s", licenses);
ADD_STRING("\n\n%%ARCH%%\n%s", arch);
ADD_STRING("\n\n%%BUILDDATE%%\n%ld", build_date);
ADD_STRING("\n\n%%PACKAGER%%\n%s", packager);
ADD_ARRAY("\n\n%%REPLACES%%\n%s", replaces);
ADD_ARRAY("\n\n%%CONFLICTS%%\n%s", conflicts);
ADD_ARRAY("\n\n%%PROVIDES%%\n%s", provides);
ADD_ARRAY("\n\n%%DEPENDS%%\n%s", depends);
ADD_ARRAY("\n\n%%OPTDEPENDS%%\n%s", optdepends);
ADD_ARRAY("\n\n%%MAKEDEPENDS%%\n%s", makedepends);
ADD_ARRAY("\n\n%%CHECKDEPENDS%%\n%s", checkdepends);
strcat(description, "\n\n");
free(aux);
return description;
}
void vieter_package_free(vieter_package **ptp) {
FREE_STRING((*ptp)->path);
vieter_package_info_free((*ptp)->info);
vieter_dynarray_free((*ptp)->files);
free(*ptp);
*ptp = NULL;
}

View File

@ -0,0 +1,86 @@
#include <stdbool.h>
#include "vieter_package_info.h"
#define PKG_INFO_STRING(key_ptr, field) \
if ((value_ptr = strstr(value_ptr, key_ptr)) != NULL) { \

How does this work? strstr doens't write any terminating NULL bytes for the substring or anything, so won't this strlen call return the entire remaining size of the pkginfo string?

How does this work? `strstr` doens't write any terminating NULL bytes for the substring or anything, so won't this `strlen` call return the entire remaining size of the pkginfo string?

The strlen is called on key_ptr which is just a small self contained string (e.g. "\ngroup = ") that is null terminated.

The pkginfo string in here is value_ptr.

The `strlen` is called on `key_ptr` which is just a small self contained string (e.g. "\ngroup = ") that is null terminated. The pkginfo string in here is `value_ptr`.
value_ptr += strlen(key_ptr); \
tail_ptr = strchr(value_ptr, '\n'); \
tail_ptr[0] = '\0'; \
pkg_info->field = strdup(value_ptr); \
tail_ptr[0] = '\n'; \
} \
value_ptr = tail_ptr;
#define PKG_INFO_INT(key_ptr, field) \
value_ptr = strstr(value_ptr, key_ptr) + strlen(key_ptr); \
tail_ptr = strchr(value_ptr, '\n'); \
tail_ptr[0] = '\0'; \
pkg_info->field = atoi(value_ptr); \
tail_ptr[0] = '\n'; \
value_ptr = tail_ptr;
#define PKG_INFO_ARRAY(key_ptr, field) \
while ((value_ptr = strstr(value_ptr, key_ptr)) != NULL) { \
value_ptr = value_ptr + strlen(key_ptr); \
tail_ptr = strchr(value_ptr, '\n'); \
tail_ptr[0] = '\0'; \
if (pkg_info->field == NULL) { \
pkg_info->field = vieter_dynarray_init(4); \
} \
vieter_dynarray_add(pkg_info->field, value_ptr); \
tail_ptr[0] = '\n'; \
value_ptr = tail_ptr; \
} \
value_ptr = tail_ptr;
vieter_package_info *vieter_package_info_init() {
return calloc(1, sizeof(vieter_package_info));
}
void vieter_package_info_free(vieter_package_info *pkg_info) {
FREE_STRING(pkg_info->name);
FREE_STRING(pkg_info->base);
FREE_STRING(pkg_info->version);
FREE_STRING(pkg_info->description);
FREE_STRING(pkg_info->url);
FREE_STRING(pkg_info->arch);
FREE_STRING(pkg_info->packager);
FREE_STRING(pkg_info->pgpsig);
vieter_dynarray_free(pkg_info->groups);
vieter_dynarray_free(pkg_info->licenses);
vieter_dynarray_free(pkg_info->replaces);
vieter_dynarray_free(pkg_info->depends);
vieter_dynarray_free(pkg_info->conflicts);
vieter_dynarray_free(pkg_info->provides);
vieter_dynarray_free(pkg_info->optdepends);
vieter_dynarray_free(pkg_info->makedepends);
vieter_dynarray_free(pkg_info->checkdepends);
free(pkg_info);
}
void vieter_package_info_parse(vieter_package_info *pkg_info,
char *pkg_info_str) {
char *value_ptr = pkg_info_str, *tail_ptr = NULL;
PKG_INFO_STRING("\npkgname = ", name);
PKG_INFO_STRING("\npkgbase = ", base);
PKG_INFO_STRING("\npkgver = ", version);
PKG_INFO_STRING("\npkgdesc = ", description);
PKG_INFO_STRING("\nurl = ", url);
PKG_INFO_INT("\nbuilddate = ", build_date);
PKG_INFO_STRING("\npackager = ", packager);
PKG_INFO_INT("\nsize = ", size);
PKG_INFO_STRING("\narch = ", arch);
PKG_INFO_ARRAY("\nlicense = ", licenses);
PKG_INFO_ARRAY("\nreplaces = ", replaces);
PKG_INFO_ARRAY("\ngroup = ", groups);
PKG_INFO_ARRAY("\nconflict = ", conflicts);
PKG_INFO_ARRAY("\nprovides = ", provides);
PKG_INFO_ARRAY("\ndepend = ", depends);
PKG_INFO_ARRAY("\noptdepend = ", optdepends);
PKG_INFO_ARRAY("\nmakedepend = ", makedepends);
PKG_INFO_ARRAY("\ncheckdepend = ", checkdepends);
}

View File

@ -0,0 +1,52 @@
#ifndef VIETER_PACKAGE_INFO
#define VIETER_PACKAGE_INFO
#define FREE_STRING(sp) if (sp != NULL) free(sp)
#include <stdint.h>
#include "vieter_package.h"
#include "vieter_dynarray.h"
typedef struct vieter_package_info {
char *name;
char *base;
char *version;
char *description;
int64_t size;
int64_t csize;
char *url;
char *arch;
int64_t build_date;
char *packager;
char *pgpsig;
int64_t pgpsigsize;
vieter_dynarray *groups;
vieter_dynarray *licenses;
vieter_dynarray *replaces;
vieter_dynarray *depends;
vieter_dynarray *conflicts;
vieter_dynarray *provides;
vieter_dynarray *optdepends;
vieter_dynarray *makedepends;
vieter_dynarray *checkdepends;
} vieter_package_info;
/*
* Allocate and initialise a pkg_info pointer to hold .PKGINFO.
*/
vieter_package_info *vieter_package_info_init();
/*
* Parse .PKGINFO file into something usable by libvieter.
*/
void vieter_package_info_parse(vieter_package_info *pkg_info, char *pkg_info_str);
/*
* Deallocate a pkg_info pointer.
*/
void vieter_package_info_free(vieter_package_info *pkg_info);
#endif

View File

@ -0,0 +1,10 @@
#include "vieter_package.h"
#include "vieter_package_info.h"
#include "vieter_dynarray.h"
struct vieter_package {
char *path;
vieter_package_info *info;
vieter_dynarray *files;
int compression;
};

View File

@ -0,0 +1,22 @@
# Generated by makepkg 6.0.2
# using fakeroot version 1.30.1
pkgname = xcursor-dmz
pkgbase = xcursor-dmz
pkgver = 0.4.5-2
pkgdesc = Style neutral, scalable cursor theme
url = https://packages.debian.org/sid/dmz-cursor-theme
builddate = 1673751613
packager = Unknown Packager
size = 3469584
arch = any
license = MIT
replaces = test1
group = x11
conflict = test2
conflict = test3
provides = test4
depend = test5
depend = test6
optdepend = test7
makedepend = xorg-xcursorgen
checkdepend = test8

45
test/package/desc 100644
View File

@ -0,0 +1,45 @@
%FILENAME%
xcursor-dmz-0.4.5-2-any.pkg.tar.zst
%NAME%
xcursor-dmz
%BASE%
xcursor-dmz
%VERSION%
0.4.5-2
%DESC%
Style neutral, scalable cursor theme
%GROUPS%
x11
%CSIZE%
328282
%ISIZE%
3469584
%SHA256SUM%
4f4bce9e975334ed7775ff4ddf4d2e82e411d599802f6179a122f89149f53bfb
%URL%
https://packages.debian.org/sid/dmz-cursor-theme
%LICENSE%
MIT
%ARCH%
any
%BUILDDATE%
1673751613
%PACKAGER%
Unknown Packager
%MAKEDEPENDS%
xorg-xcursorgen

243
test/package/files 100644
View File

@ -0,0 +1,243 @@
%FILES%
usr/
usr/share/
usr/share/icons/
usr/share/icons/DMZ-Black/
usr/share/icons/DMZ-Black/cursor.theme
usr/share/icons/DMZ-Black/cursors/
usr/share/icons/DMZ-Black/cursors/00008160000006810000408080010102
usr/share/icons/DMZ-Black/cursors/028006030e0e7ebffc7f7070c0600140
usr/share/icons/DMZ-Black/cursors/03b6e0fcb3499374a867c041f52298f0
usr/share/icons/DMZ-Black/cursors/08e8e1c95fe2fc01f976f1e063a24ccd
usr/share/icons/DMZ-Black/cursors/1081e37283d90000800003c07f3ef6bf
usr/share/icons/DMZ-Black/cursors/14fef782d02440884392942c11205230
usr/share/icons/DMZ-Black/cursors/2870a09082c103050810ffdffffe0204
usr/share/icons/DMZ-Black/cursors/3085a0e285430894940527032f8b26df
usr/share/icons/DMZ-Black/cursors/3ecb610c1bf2410f44200f48c40d3599
usr/share/icons/DMZ-Black/cursors/4498f0e0c1937ffe01fd06f973665830
usr/share/icons/DMZ-Black/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408
usr/share/icons/DMZ-Black/cursors/6407b0e94181790501fd1e167b474872
usr/share/icons/DMZ-Black/cursors/640fb0e74195791501fd1ed57b41487f
usr/share/icons/DMZ-Black/cursors/9081237383d90e509aa00f00170e968f
usr/share/icons/DMZ-Black/cursors/9d800788f1b08800ae810202380a0822
usr/share/icons/DMZ-Black/cursors/X_cursor
usr/share/icons/DMZ-Black/cursors/alias
usr/share/icons/DMZ-Black/cursors/arrow
usr/share/icons/DMZ-Black/cursors/bd_double_arrow
usr/share/icons/DMZ-Black/cursors/bottom_left_corner
usr/share/icons/DMZ-Black/cursors/bottom_right_corner
usr/share/icons/DMZ-Black/cursors/bottom_side
usr/share/icons/DMZ-Black/cursors/bottom_tee
usr/share/icons/DMZ-Black/cursors/c7088f0f3e6c8088236ef8e1e3e70000
usr/share/icons/DMZ-Black/cursors/circle
usr/share/icons/DMZ-Black/cursors/col-resize
usr/share/icons/DMZ-Black/cursors/color-picker
usr/share/icons/DMZ-Black/cursors/copy
usr/share/icons/DMZ-Black/cursors/cross
usr/share/icons/DMZ-Black/cursors/cross_reverse
usr/share/icons/DMZ-Black/cursors/crossed_circle
usr/share/icons/DMZ-Black/cursors/crosshair
usr/share/icons/DMZ-Black/cursors/d9ce0ab605698f320427677b458ad60b
usr/share/icons/DMZ-Black/cursors/default
usr/share/icons/DMZ-Black/cursors/diamond_cross
usr/share/icons/DMZ-Black/cursors/dnd-ask
usr/share/icons/DMZ-Black/cursors/dnd-copy
usr/share/icons/DMZ-Black/cursors/dnd-link
usr/share/icons/DMZ-Black/cursors/dnd-move
usr/share/icons/DMZ-Black/cursors/dnd-none
usr/share/icons/DMZ-Black/cursors/dot_box_mask
usr/share/icons/DMZ-Black/cursors/dotbox
usr/share/icons/DMZ-Black/cursors/double_arrow
usr/share/icons/DMZ-Black/cursors/draft_large
usr/share/icons/DMZ-Black/cursors/draft_small
usr/share/icons/DMZ-Black/cursors/draped_box
usr/share/icons/DMZ-Black/cursors/e-resize
usr/share/icons/DMZ-Black/cursors/e29285e634086352946a0e7090d73106
usr/share/icons/DMZ-Black/cursors/ew-resize
usr/share/icons/DMZ-Black/cursors/fcf1c3c7cd4491d801f1e1c78f100000
usr/share/icons/DMZ-Black/cursors/fd_double_arrow
usr/share/icons/DMZ-Black/cursors/fleur
usr/share/icons/DMZ-Black/cursors/grab
usr/share/icons/DMZ-Black/cursors/grabbing
usr/share/icons/DMZ-Black/cursors/h_double_arrow
usr/share/icons/DMZ-Black/cursors/hand
usr/share/icons/DMZ-Black/cursors/hand1
usr/share/icons/DMZ-Black/cursors/hand2
usr/share/icons/DMZ-Black/cursors/help
usr/share/icons/DMZ-Black/cursors/icon
usr/share/icons/DMZ-Black/cursors/left_ptr
usr/share/icons/DMZ-Black/cursors/left_ptr_help
usr/share/icons/DMZ-Black/cursors/left_ptr_watch
usr/share/icons/DMZ-Black/cursors/left_side
usr/share/icons/DMZ-Black/cursors/left_tee
usr/share/icons/DMZ-Black/cursors/link
usr/share/icons/DMZ-Black/cursors/ll_angle
usr/share/icons/DMZ-Black/cursors/lr_angle
usr/share/icons/DMZ-Black/cursors/move
usr/share/icons/DMZ-Black/cursors/n-resize
usr/share/icons/DMZ-Black/cursors/ne-resize
usr/share/icons/DMZ-Black/cursors/nesw-resize
usr/share/icons/DMZ-Black/cursors/not-allowed
usr/share/icons/DMZ-Black/cursors/ns-resize
usr/share/icons/DMZ-Black/cursors/nw-resize
usr/share/icons/DMZ-Black/cursors/nwse-resize
usr/share/icons/DMZ-Black/cursors/openhand
usr/share/icons/DMZ-Black/cursors/pencil
usr/share/icons/DMZ-Black/cursors/pirate
usr/share/icons/DMZ-Black/cursors/plus
usr/share/icons/DMZ-Black/cursors/pointer
usr/share/icons/DMZ-Black/cursors/progress
usr/share/icons/DMZ-Black/cursors/question_arrow
usr/share/icons/DMZ-Black/cursors/right_ptr
usr/share/icons/DMZ-Black/cursors/right_side
usr/share/icons/DMZ-Black/cursors/right_tee
usr/share/icons/DMZ-Black/cursors/row-resize
usr/share/icons/DMZ-Black/cursors/s-resize
usr/share/icons/DMZ-Black/cursors/sb_down_arrow
usr/share/icons/DMZ-Black/cursors/sb_h_double_arrow
usr/share/icons/DMZ-Black/cursors/sb_left_arrow
usr/share/icons/DMZ-Black/cursors/sb_right_arrow
usr/share/icons/DMZ-Black/cursors/sb_up_arrow
usr/share/icons/DMZ-Black/cursors/sb_v_double_arrow
usr/share/icons/DMZ-Black/cursors/se-resize
usr/share/icons/DMZ-Black/cursors/size_bdiag
usr/share/icons/DMZ-Black/cursors/size_fdiag
usr/share/icons/DMZ-Black/cursors/size_hor
usr/share/icons/DMZ-Black/cursors/size_ver
usr/share/icons/DMZ-Black/cursors/sw-resize
usr/share/icons/DMZ-Black/cursors/target
usr/share/icons/DMZ-Black/cursors/tcross
usr/share/icons/DMZ-Black/cursors/text
usr/share/icons/DMZ-Black/cursors/top_left_arrow
usr/share/icons/DMZ-Black/cursors/top_left_corner
usr/share/icons/DMZ-Black/cursors/top_right_corner
usr/share/icons/DMZ-Black/cursors/top_side
usr/share/icons/DMZ-Black/cursors/top_tee
usr/share/icons/DMZ-Black/cursors/ul_angle
usr/share/icons/DMZ-Black/cursors/ur_angle
usr/share/icons/DMZ-Black/cursors/v_double_arrow
usr/share/icons/DMZ-Black/cursors/w-resize
usr/share/icons/DMZ-Black/cursors/wait
usr/share/icons/DMZ-Black/cursors/watch
usr/share/icons/DMZ-Black/cursors/xterm
usr/share/icons/DMZ-White/
usr/share/icons/DMZ-White/cursor.theme
usr/share/icons/DMZ-White/cursors/
usr/share/icons/DMZ-White/cursors/00008160000006810000408080010102
usr/share/icons/DMZ-White/cursors/028006030e0e7ebffc7f7070c0600140
usr/share/icons/DMZ-White/cursors/03b6e0fcb3499374a867c041f52298f0
usr/share/icons/DMZ-White/cursors/08e8e1c95fe2fc01f976f1e063a24ccd
usr/share/icons/DMZ-White/cursors/1081e37283d90000800003c07f3ef6bf
usr/share/icons/DMZ-White/cursors/14fef782d02440884392942c11205230
usr/share/icons/DMZ-White/cursors/2870a09082c103050810ffdffffe0204
usr/share/icons/DMZ-White/cursors/3085a0e285430894940527032f8b26df
usr/share/icons/DMZ-White/cursors/3ecb610c1bf2410f44200f48c40d3599
usr/share/icons/DMZ-White/cursors/4498f0e0c1937ffe01fd06f973665830
usr/share/icons/DMZ-White/cursors/5c6cd98b3f3ebcb1f9c7f1c204630408
usr/share/icons/DMZ-White/cursors/6407b0e94181790501fd1e167b474872
usr/share/icons/DMZ-White/cursors/640fb0e74195791501fd1ed57b41487f
usr/share/icons/DMZ-White/cursors/9081237383d90e509aa00f00170e968f
usr/share/icons/DMZ-White/cursors/9d800788f1b08800ae810202380a0822
usr/share/icons/DMZ-White/cursors/X_cursor
usr/share/icons/DMZ-White/cursors/alias
usr/share/icons/DMZ-White/cursors/arrow
usr/share/icons/DMZ-White/cursors/bd_double_arrow
usr/share/icons/DMZ-White/cursors/bottom_left_corner
usr/share/icons/DMZ-White/cursors/bottom_right_corner
usr/share/icons/DMZ-White/cursors/bottom_side
usr/share/icons/DMZ-White/cursors/bottom_tee
usr/share/icons/DMZ-White/cursors/c7088f0f3e6c8088236ef8e1e3e70000
usr/share/icons/DMZ-White/cursors/circle
usr/share/icons/DMZ-White/cursors/col-resize
usr/share/icons/DMZ-White/cursors/color-picker
usr/share/icons/DMZ-White/cursors/copy
usr/share/icons/DMZ-White/cursors/cross
usr/share/icons/DMZ-White/cursors/cross_reverse
usr/share/icons/DMZ-White/cursors/crossed_circle
usr/share/icons/DMZ-White/cursors/crosshair
usr/share/icons/DMZ-White/cursors/d9ce0ab605698f320427677b458ad60b
usr/share/icons/DMZ-White/cursors/default
usr/share/icons/DMZ-White/cursors/diamond_cross
usr/share/icons/DMZ-White/cursors/dnd-ask
usr/share/icons/DMZ-White/cursors/dnd-copy
usr/share/icons/DMZ-White/cursors/dnd-link
usr/share/icons/DMZ-White/cursors/dnd-move
usr/share/icons/DMZ-White/cursors/dnd-none
usr/share/icons/DMZ-White/cursors/dot_box_mask
usr/share/icons/DMZ-White/cursors/dotbox
usr/share/icons/DMZ-White/cursors/double_arrow
usr/share/icons/DMZ-White/cursors/draft_large
usr/share/icons/DMZ-White/cursors/draft_small
usr/share/icons/DMZ-White/cursors/draped_box
usr/share/icons/DMZ-White/cursors/e-resize
usr/share/icons/DMZ-White/cursors/e29285e634086352946a0e7090d73106
usr/share/icons/DMZ-White/cursors/ew-resize
usr/share/icons/DMZ-White/cursors/fcf1c3c7cd4491d801f1e1c78f100000
usr/share/icons/DMZ-White/cursors/fd_double_arrow
usr/share/icons/DMZ-White/cursors/fleur
usr/share/icons/DMZ-White/cursors/grab
usr/share/icons/DMZ-White/cursors/grabbing
usr/share/icons/DMZ-White/cursors/h_double_arrow
usr/share/icons/DMZ-White/cursors/hand
usr/share/icons/DMZ-White/cursors/hand1
usr/share/icons/DMZ-White/cursors/hand2
usr/share/icons/DMZ-White/cursors/help
usr/share/icons/DMZ-White/cursors/icon
usr/share/icons/DMZ-White/cursors/left_ptr
usr/share/icons/DMZ-White/cursors/left_ptr_help
usr/share/icons/DMZ-White/cursors/left_ptr_watch
usr/share/icons/DMZ-White/cursors/left_side
usr/share/icons/DMZ-White/cursors/left_tee
usr/share/icons/DMZ-White/cursors/link
usr/share/icons/DMZ-White/cursors/ll_angle
usr/share/icons/DMZ-White/cursors/lr_angle
usr/share/icons/DMZ-White/cursors/move
usr/share/icons/DMZ-White/cursors/n-resize
usr/share/icons/DMZ-White/cursors/ne-resize
usr/share/icons/DMZ-White/cursors/nesw-resize
usr/share/icons/DMZ-White/cursors/not-allowed
usr/share/icons/DMZ-White/cursors/ns-resize
usr/share/icons/DMZ-White/cursors/nw-resize
usr/share/icons/DMZ-White/cursors/nwse-resize
usr/share/icons/DMZ-White/cursors/openhand
usr/share/icons/DMZ-White/cursors/pencil
usr/share/icons/DMZ-White/cursors/pirate
usr/share/icons/DMZ-White/cursors/plus
usr/share/icons/DMZ-White/cursors/pointer
usr/share/icons/DMZ-White/cursors/progress
usr/share/icons/DMZ-White/cursors/question_arrow
usr/share/icons/DMZ-White/cursors/right_ptr
usr/share/icons/DMZ-White/cursors/right_side
usr/share/icons/DMZ-White/cursors/right_tee
usr/share/icons/DMZ-White/cursors/row-resize
usr/share/icons/DMZ-White/cursors/s-resize
usr/share/icons/DMZ-White/cursors/sb_down_arrow
usr/share/icons/DMZ-White/cursors/sb_h_double_arrow
usr/share/icons/DMZ-White/cursors/sb_left_arrow
usr/share/icons/DMZ-White/cursors/sb_right_arrow
usr/share/icons/DMZ-White/cursors/sb_up_arrow
usr/share/icons/DMZ-White/cursors/sb_v_double_arrow
usr/share/icons/DMZ-White/cursors/se-resize
usr/share/icons/DMZ-White/cursors/size_bdiag
usr/share/icons/DMZ-White/cursors/size_fdiag
usr/share/icons/DMZ-White/cursors/size_hor
usr/share/icons/DMZ-White/cursors/size_ver
usr/share/icons/DMZ-White/cursors/sw-resize
usr/share/icons/DMZ-White/cursors/target
usr/share/icons/DMZ-White/cursors/tcross
usr/share/icons/DMZ-White/cursors/text
usr/share/icons/DMZ-White/cursors/top_left_arrow
usr/share/icons/DMZ-White/cursors/top_left_corner
usr/share/icons/DMZ-White/cursors/top_right_corner
usr/share/icons/DMZ-White/cursors/top_side
usr/share/icons/DMZ-White/cursors/top_tee
usr/share/icons/DMZ-White/cursors/ul_angle
usr/share/icons/DMZ-White/cursors/ur_angle
usr/share/icons/DMZ-White/cursors/v_double_arrow
usr/share/icons/DMZ-White/cursors/w-resize
usr/share/icons/DMZ-White/cursors/wait
usr/share/icons/DMZ-White/cursors/watch
usr/share/icons/DMZ-White/cursors/xterm
usr/share/licenses/
usr/share/licenses/xcursor-dmz/
usr/share/licenses/xcursor-dmz/LICENSE

View File

@ -0,0 +1,97 @@
#include "acutest.h"
#include "vieter_package_internal.h"
void test_info_parse() {
FILE *f = fopen("./test/package/.PKGINFO", "r");
TEST_ASSERT_(f != NULL, "could not find test .PKGINFO file in ./test/package ");
fseek(f, 0L, SEEK_END);
size_t size = ftell(f);
fflush(stdout);
rewind(f);
char *pkg_info_str = malloc(size + 1);
fread(pkg_info_str, 1, size, f);
pkg_info_str[size] = '\0';
fclose(f);
vieter_package_info *pkg_info = vieter_package_info_init();
vieter_package_info_parse(pkg_info, pkg_info_str);
TEST_CHECK(!strcmp(pkg_info->name, "xcursor-dmz"));
TEST_CHECK(!strcmp(pkg_info->base, "xcursor-dmz"));
TEST_CHECK(!strcmp(pkg_info->version, "0.4.5-2"));
TEST_CHECK(!strcmp(pkg_info->description, "Style neutral, scalable cursor theme"));
TEST_CHECK(!strcmp(pkg_info->url, "https://packages.debian.org/sid/dmz-cursor-theme"));
TEST_CHECK(pkg_info->build_date == 1673751613);
TEST_CHECK(!strcmp(pkg_info->packager, "Unknown Packager"));
TEST_CHECK(pkg_info->size == 3469584);
TEST_CHECK(!strcmp(pkg_info->arch, "any"));
TEST_CHECK(!strcmp(pkg_info->licenses->array[0], "MIT"));
TEST_CHECK(!strcmp(pkg_info->replaces->array[0], "test1"));
TEST_CHECK(!strcmp(pkg_info->groups->array[0], "x11"));
TEST_CHECK(!strcmp(pkg_info->conflicts->array[0], "test2"));
TEST_CHECK(!strcmp(pkg_info->conflicts->array[1], "test3"));
TEST_CHECK(!strcmp(pkg_info->provides->array[0], "test4"));
TEST_CHECK(!strcmp(pkg_info->depends->array[0], "test5"));
TEST_CHECK(!strcmp(pkg_info->depends->array[1], "test6"));
TEST_CHECK(!strcmp(pkg_info->optdepends->array[0], "test7"));
TEST_CHECK(!strcmp(pkg_info->makedepends->array[0], "xorg-xcursorgen"));
TEST_CHECK(!strcmp(pkg_info->checkdepends->array[0], "test8"));
free(pkg_info_str);
vieter_package_info_free(pkg_info);
}
void test_pkg_read_archive_files() {
vieter_package *pkg = vieter_package_init();
vieter_package_error e = vieter_package_read_archive(pkg, "./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst");
TEST_ASSERT_(e == vieter_package_ok, "failure parsing pkg archive");
FILE *f = fopen("./test/package/files", "r");
TEST_ASSERT_(f != NULL, "could not find test files file in ./test/package");
char buff[128];
size_t i = 0;
while ((fgets(buff, 128, f)) != NULL || i < pkg->files->size) {
if (buff[strlen(buff) - 1] == '\n') {
buff[strlen(buff) - 1] = '\0';
}
TEST_CHECK_(!strcmp(pkg->files->array[i], buff), "%s != %s", pkg->files->array[i], buff);
i++;
}
TEST_CHECK(pkg->compression = 14);
vieter_package_free(&pkg);
}
void test_pkg_read_archive_desc() {
vieter_package *pkg = vieter_package_init();
vieter_package_error e = vieter_package_read_archive(pkg, "./test/package/xcursor-dmz-0.4.5-2-any.pkg.tar.zst");
TEST_ASSERT_(e == vieter_package_ok, "failure parsing pkg archive");
char *description = vieter_package_to_description(pkg);
FILE *f = fopen("./test/package/desc", "r");
TEST_ASSERT_(f != NULL, "could not find test desc file in ./test/package");
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
rewind(f);
char *desc = malloc(size + 1);
fread(desc, 1, size, f);
desc[size] = '\0';
fclose(f);
TEST_CHECK(!strcmp(description, desc));
vieter_package_free(&pkg);
free(description);
free(desc);
}
TEST_LIST = {
{".PKGINFO parse", test_info_parse},
{"files array creation", test_pkg_read_archive_files},
{"desc file creation", test_pkg_read_archive_desc},
{NULL, NULL}
};

34
thirdparty/include/sha256.h vendored 100644
View File

@ -0,0 +1,34 @@
/*********************************************************************
* Filename: sha256.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding SHA1 implementation.
*********************************************************************/
#ifndef SHA256_H
#define SHA256_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[8];
} SHA256_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void sha256_init(SHA256_CTX *ctx);
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
#endif // SHA256_H

158
thirdparty/src/sha256.c vendored 100644
View File

@ -0,0 +1,158 @@
/*********************************************************************
* Filename: sha256.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the SHA-256 hashing algorithm.
SHA-256 is one of the three algorithms in the SHA2
specification. The others, SHA-384 and SHA-512, are not
offered in this implementation.
Algorithm specification can be found here:
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "sha256.h"
/****************************** MACROS ******************************/
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
/**************************** VARIABLES *****************************/
static const WORD k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
/*********************** FUNCTION DEFINITIONS ***********************/
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a,b,c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
{
WORD i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
{
WORD i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}