Started correcting pictures, started encoding (placeholder)
This commit is contained in:
parent
8f0202924d
commit
00338af264
|
@ -58,6 +58,9 @@ extern "C" {
|
|||
# define g1m_error_nostream 0x10
|
||||
# define g1m_error_noread 0x11
|
||||
# define g1m_error_noseek 0x12
|
||||
# define g1m_error_nowrite 0x13
|
||||
# define g1m_error_read 0x14
|
||||
# define g1m_error_write 0x15
|
||||
|
||||
/* Then, the decoding errors */
|
||||
# define g1m_error_unrecognized 0x20
|
||||
|
@ -97,6 +100,15 @@ extern int g1m_make_picture(g1m_t **handle,
|
|||
unsigned int width, unsigned int height);
|
||||
extern int g1m_make_addin(g1m_t **h, g1m_platform_t platform,
|
||||
const g1m_version_t *version, const time_t *created);
|
||||
|
||||
/* encode a handle, get the extension */
|
||||
extern int g1m_encode(g1m_t *handle, g1m_buffer_t *buffer);
|
||||
|
||||
/* put into a FILE */
|
||||
#ifndef G1M_DISABLED_FILE
|
||||
extern int g1m_write(g1m_t *handle, const char *path);
|
||||
extern int g1m_fwrite(g1m_t *handle, FILE *stream);
|
||||
#endif
|
||||
/* ************************************************************************** */
|
||||
/* Main MCS functions */
|
||||
/* ************************************************************************** */
|
||||
|
@ -135,9 +147,8 @@ extern int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer);
|
|||
/* MCS archive management */
|
||||
/* ************************************************************************** */
|
||||
/* create and insert an MCS file into a MCS archive */
|
||||
extern int g1m_mcs_insert(g1m_t *handle, const g1m_mcshead_t *head,
|
||||
g1m_mcsfile_t **tofile);
|
||||
|
||||
extern int g1m_mcs_insert(g1m_t *handle, g1m_mcsfile_t **tofile,
|
||||
const g1m_mcshead_t *head);
|
||||
/* ************************************************************************** */
|
||||
/* Miscallaneous utilities */
|
||||
/* ************************************************************************** */
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
* called with the size of the file to write, in order to prepare space for
|
||||
* it. If the `announce` callback returns an error, then the file will not
|
||||
* be written. If the announcement is successful, then the `write` callback
|
||||
* is used.
|
||||
* is used. If there is an error and the `unannounce` callback is set, it
|
||||
* will be called in order to free any allocated buffer.
|
||||
*
|
||||
* In each case, the `cookie` is sent as the first argument to your callbacks.
|
||||
* ************************************************************************** */
|
||||
|
@ -39,7 +40,8 @@
|
|||
/* The callbacks types... */
|
||||
typedef int (*g1m_buffer_read_t)(void*, unsigned char*, size_t);
|
||||
typedef int (*g1m_buffer_write_t)(void*, const unsigned char*, size_t);
|
||||
typedef int (*g1m_buffer_announce_t)(void*, uint_fast32_t size);
|
||||
typedef int (*g1m_buffer_announce_t)(void*, size_t);
|
||||
typedef void (*g1m_buffer_unannounce_t)(void*);
|
||||
|
||||
/* ... and the structure of a buffer. */
|
||||
typedef struct {
|
||||
|
@ -49,8 +51,15 @@ typedef struct {
|
|||
g1m_buffer_read_t read;
|
||||
g1m_buffer_write_t write;
|
||||
g1m_buffer_announce_t announce;
|
||||
g1m_buffer_unannounce_t unannounce;
|
||||
} g1m_buffer_t;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* File buffer definition */
|
||||
/* ************************************************************************** */
|
||||
/* Callbacks (the cookie is the FILE* pointer) */
|
||||
extern int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size);
|
||||
extern int g1m_filebuffer_write(void *cookie, const unsigned char *dest,
|
||||
size_t size);
|
||||
/* ************************************************************************** */
|
||||
/* Memory buffer definition */
|
||||
/* ************************************************************************** */
|
||||
|
@ -61,8 +70,7 @@ typedef struct {
|
|||
} g1m_cursor_t;
|
||||
|
||||
/* Related callbacks and functions */
|
||||
int g1m_membuffer_read(void *cookie, unsigned char *dest, size_t size);
|
||||
|
||||
extern int g1m_membuffer_read(void *cookie, unsigned char *dest, size_t size);
|
||||
/* ************************************************************************** */
|
||||
/* Limited buffer definition */
|
||||
/* ************************************************************************** */
|
||||
|
@ -75,10 +83,14 @@ typedef struct {
|
|||
/* Related functions and callbacks */
|
||||
int g1m_limbuffer_read(void *cookie, unsigned char *dest, size_t size);
|
||||
int g1m_empty_limbuffer(g1m_buffer_t *limbuffer);
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Buffer macros */
|
||||
/* ************************************************************************** */
|
||||
/* Initialize a file buffer */
|
||||
# define g1m_filebuffer(F) (g1m_filebuffer_t){ \
|
||||
.cookie = (void*)(F), .read = g1m_filebuffer_read, \
|
||||
.write = g1m_filebuffer_write}
|
||||
|
||||
/* Initialize a memory buffer */
|
||||
# define g1m_membuffer(P, SZ) (g1m_buffer_t){ \
|
||||
.cookie = (g1m_cursor_t[]){{.p = (P), .left = (SZ)}}, \
|
||||
|
|
|
@ -48,12 +48,6 @@ typedef unsigned int g1m_platform_t;
|
|||
# define g1m_platform_cg 0x0004
|
||||
# define g1m_platform_cas 0x0008
|
||||
# define g1m_platform_casemul 0x0010
|
||||
|
||||
/* Platform flags */
|
||||
# define g1m_platflag_be 0x8000
|
||||
|
||||
/* Platform macros */
|
||||
# define g1m_platform(P) ((P) & 0x7FFF)
|
||||
/* ************************************************************************** */
|
||||
/* Helpers */
|
||||
/* ************************************************************************** */
|
||||
|
@ -67,7 +61,7 @@ typedef struct g1m_version_s {
|
|||
typedef struct {
|
||||
/* file type, the source destination platform */
|
||||
g1m_type_t type;
|
||||
g1m_platform_t platform; /* use the `g1m_platorm` macro! */
|
||||
g1m_platform_t platform;
|
||||
|
||||
/* Add-in related data */
|
||||
char title[17];
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <libg1m/internals/endian.h>
|
||||
# define MEMBUFFER(P, SZ) g1m_membuffer(P, SZ)
|
||||
# define FILEBUFFER(F) g1m_filebuffer(F)
|
||||
# define MEMBUFFER(P, SZ) g1m_membuffer(P, SZ)
|
||||
# define LIMBUFFER(BUFFER, SZ) g1m_limbuffer(BUFFER, SZ)
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
@ -94,12 +95,12 @@
|
|||
# define WRITE(BUF, SZ) \
|
||||
(*buffer->write)(buffer->cookie, (unsigned char*)(BUF), (SZ));
|
||||
# define DWRITE(S) WRITE(&(S), sizeof(S))
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Decoding functions */
|
||||
/* ************************************************************************** */
|
||||
/* with expected types */
|
||||
int g1m_decode_std(g1m_t **handle, const char *path, g1m_buffer_t *buffer,
|
||||
extern int g1m_decode_std(g1m_t **handle, const char *path,
|
||||
g1m_buffer_t *buffer,
|
||||
struct standard_header*, g1m_type_t expected_types);
|
||||
|
||||
/* w/o expected types */
|
||||
|
@ -159,10 +160,11 @@ G1M_MCSFUNC(string)
|
|||
/* CASPRO-specific decoding functions */
|
||||
/* ************************************************************************** */
|
||||
# define G1M_CASFUNC(NAME) \
|
||||
int g1m_decode_caspart_##NAME(g1m_mcsfile_t *handle, g1m_buffer_t *buffer);
|
||||
# define G1M_CASHFUNC(NAME) \
|
||||
int g1m_decode_cashpart_##NAME(g1m_mcshead_t *head, g1m_mcshead_t *heads, \
|
||||
extern int g1m_decode_caspart_##NAME(g1m_mcsfile_t *handle, \
|
||||
g1m_buffer_t *buffer);
|
||||
# define G1M_CASHFUNC(NAME) \
|
||||
extern int g1m_decode_cashpart_##NAME(g1m_mcshead_t *head, \
|
||||
g1m_mcshead_t *heads, g1m_buffer_t *buffer);
|
||||
|
||||
G1M_CASFUNC(var)
|
||||
G1M_CASFUNC(program)
|
||||
|
@ -184,19 +186,16 @@ G1M_CASFUNC(capture)
|
|||
/* Utilities */
|
||||
/* ************************************************************************** */
|
||||
/* Free-ing */
|
||||
void g1m_free_line_content(g1m_line_t *line);
|
||||
extern void g1m_free_line_content(g1m_line_t *line);
|
||||
|
||||
/* Skipping */
|
||||
int g1m_skip(g1m_buffer_t *buffer, size_t size, uint32_t *checksum);
|
||||
extern int g1m_skip(g1m_buffer_t *buffer, size_t size, uint32_t *checksum);
|
||||
|
||||
/* Checksum-ing */
|
||||
uint8_t g1m_checksum8(void *mem, size_t size);
|
||||
uint32_t g1m_checksum32(void *mem, size_t size, uint32_t checksum);
|
||||
extern uint8_t g1m_checksum8(void *mem, size_t size);
|
||||
extern uint32_t g1m_checksum32(void *mem, size_t size, uint32_t checksum);
|
||||
|
||||
/* Get extension */
|
||||
int g1m_getext(const char *path, char *buf, size_t n);
|
||||
|
||||
/* File buffer */
|
||||
int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size);
|
||||
extern int g1m_getext(const char *path, char *buf, size_t n);
|
||||
|
||||
#endif /* LIBG1M_INTERNALS_H */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
# include <stdio_ext.h>
|
||||
# else
|
||||
# define __freadable(F) (1)
|
||||
# define __fwritable(F) (1)
|
||||
# endif
|
||||
|
||||
#endif /* LIBG1M_INTERNALS_STDIO_EXT_H */
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef g1m_mcsfile_type_t g1m_mcstype_t;
|
|||
# define g1m_mcstype_capture g1m_mcstype_capt
|
||||
# define g1m_mcstype_spreadsheet g1m_mcstype_ssheet
|
||||
# define g1m_mcstype_vector g1m_mcstype_vct
|
||||
# define g1m_mcstype_alpha g1m_mcstype_var
|
||||
# define g1m_mcstype_alphamem g1m_mcstype_var
|
||||
# define g1m_mcstype_variable g1m_mcstype_var
|
||||
# define g1m_mcstype_variables g1m_mcstype_var
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* TODO: dispatch this file into sources in the `manage` module!
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -37,6 +37,12 @@ const char *g1m_error_strings[] = {
|
|||
"given stream was not readable",
|
||||
[g1m_error_noseek] =
|
||||
"given stream was not seekable",
|
||||
[g1m_error_nowrite] =
|
||||
"given stream was not writable",
|
||||
[g1m_error_read] =
|
||||
"a read operation failed",
|
||||
[g1m_error_write] =
|
||||
"a write operation failed",
|
||||
|
||||
[g1m_error_wrong_type] =
|
||||
"was not of the expected type",
|
||||
|
|
|
@ -278,7 +278,7 @@ int g1m_decode_cas(g1m_t **h, g1m_buffer_t *buffer)
|
|||
for (int i = 0; i < numheads; i++) {
|
||||
/* prepare the file */
|
||||
log_info("Preparing the group file #%d", i);
|
||||
g1m_mcsfile_t *file; err = g1m_mcs_insert(handle, &heads[i], &file);
|
||||
g1m_mcsfile_t *file; err = g1m_mcs_insert(handle, &file, &heads[i]);
|
||||
if (err) goto fail;
|
||||
|
||||
/* read each part */
|
||||
|
|
|
@ -388,7 +388,6 @@ int g1m_decode_casemul(g1m_t **h, g1m_buffer_t *buffer, int big_endian)
|
|||
log_warn("Should read compiled part here!");
|
||||
|
||||
/* no error! */
|
||||
handle->platform &= ~g1m_platflag_be;
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(handle);
|
||||
|
|
|
@ -48,6 +48,9 @@ static void g3p_deobfuscate(uint8_t *buf, size_t n)
|
|||
int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
||||
struct standard_header *std)
|
||||
{
|
||||
int err; *h = NULL;
|
||||
uint8_t *defbuf = NULL, *infbuf = NULL;
|
||||
|
||||
/* get the G3P global header */
|
||||
DREAD(hd, g3p_subheader)
|
||||
hd.g3p_size = be32toh(hd.g3p_size);
|
||||
|
@ -58,8 +61,13 @@ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
|||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
/* start a checksum */
|
||||
uint32_t check = g1m_checksum32((void*)std,
|
||||
sizeof(struct standard_header), 0);
|
||||
|
||||
/* read the image header */
|
||||
DREAD(ihd, g3p_imageheader)
|
||||
check = g1m_checksum32(&ihd, sizeof(struct g3p_imageheader), check);
|
||||
ihd.df_size = be32toh(ihd.df_size);
|
||||
ihd.width = be16toh(ihd.width);
|
||||
ihd.height = be16toh(ihd.height);
|
||||
|
@ -70,7 +78,7 @@ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
|||
int is_obfuscated =
|
||||
((std->obfuscated + 8) & 0xff) != ((std->filesize & 0xff00) >> 8);
|
||||
int has_footer = 1; /* might change? */
|
||||
size_t deflated_image_size = ihd.data_size - has_footer * 0x4;
|
||||
size_t deflated_image_size = ihd.data_size;
|
||||
|
||||
/* log info */
|
||||
log_info("Width: %" PRIu16 "px, height: %" PRIu16 "px",
|
||||
|
@ -80,16 +88,18 @@ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
|||
log_info("Deflated image length: %" PRIuSIZE "o", deflated_image_size);
|
||||
log_info("Is obfuscated: %s", is_obfuscated ? "yes" : "no");
|
||||
|
||||
/* read image */
|
||||
uint8_t deflated_image[deflated_image_size];
|
||||
READ(deflated_image, deflated_image_size)
|
||||
/* read image: FIXME allocate in heap? */
|
||||
err = g1m_error_alloc;
|
||||
defbuf = malloc(deflated_image_size);
|
||||
if (!defbuf) goto fail;
|
||||
READ(defbuf, deflated_image_size)
|
||||
|
||||
/* read footer and check sum */
|
||||
if (has_footer) {
|
||||
DREAD(ft, g3p_imagefooter);
|
||||
ft.checksum = be32toh(ft.checksum);
|
||||
|
||||
uLong adl = adler32(0, deflated_image, deflated_image_size);
|
||||
uLong adl = adler32(0, defbuf, deflated_image_size);
|
||||
if (adl != ft.checksum) {
|
||||
log_fatal("Incorrect Adler32 checksum!");
|
||||
log_fatal("Expected %" PRIu32 ", got %lu",
|
||||
|
@ -99,38 +109,45 @@ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer,
|
|||
}
|
||||
|
||||
/* unobfuscate if required */
|
||||
if (is_obfuscated)
|
||||
g3p_deobfuscate(deflated_image, deflated_image_size);
|
||||
if (is_obfuscated) g3p_deobfuscate(defbuf, deflated_image_size);
|
||||
|
||||
/* find out length of inflated data */
|
||||
uLongf inflated_size = 0L; int z_err;
|
||||
if ((z_err = uncompress(Z_NULL, &inflated_size, deflated_image,
|
||||
deflated_image_size)) != Z_MEM_ERROR) {
|
||||
/* make the destination buffer */
|
||||
size_t rawsize = ihd.color_depth == g3p_color_4bit
|
||||
? g1m_picturesize_4bit_code(ihd.width, ihd.height)
|
||||
: g1m_picturesize_16bit(ihd.width, ihd.height);
|
||||
err = g1m_error_alloc;
|
||||
infbuf = malloc(rawsize);
|
||||
if (!infbuf) goto fail;
|
||||
|
||||
/* uncompress */
|
||||
err = g1m_error_alloc;
|
||||
uLongf inflated_size = 0L; // rawsize?
|
||||
int z_err = uncompress(infbuf, &inflated_size, defbuf, deflated_image_size);
|
||||
if (z_err) {
|
||||
log_fatal("Zlib error: error #%d", z_err);
|
||||
return (g1m_error_magic);
|
||||
goto fail;
|
||||
}
|
||||
log_info("Inflated image size is %lu", inflated_size);
|
||||
free(defbuf); defbuf = NULL;
|
||||
|
||||
/* allocate space for it, and uncompress */
|
||||
uint8_t inflated_image[inflated_size];
|
||||
if ((z_err = uncompress(inflated_image, &inflated_size, deflated_image,
|
||||
deflated_image_size))) {
|
||||
log_fatal("Zlib error: error #%d", z_err);
|
||||
return (g1m_error_magic);
|
||||
}
|
||||
|
||||
/* allocate picture in handle */
|
||||
int err = g1m_make_picture(h, ihd.width, ihd.height);
|
||||
if (err) return (err);
|
||||
/* make the handle */
|
||||
err = g1m_make_picture(h, ihd.width, ihd.height);
|
||||
if (err) goto fail;
|
||||
g1m_t *handle = *h;
|
||||
|
||||
/* then store it */
|
||||
g1m_decode_picture(handle->pixels, ihd.color_depth == g3p_color_4bit
|
||||
? g1m_pictureformat_4bit_code : g1m_pictureformat_16bit,
|
||||
inflated_image, handle->width, handle->height);
|
||||
infbuf, handle->width, handle->height);
|
||||
free(infbuf); infbuf = NULL;
|
||||
|
||||
/* TODO: footers? */
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
fail:
|
||||
g1m_free(*h); *h = NULL;
|
||||
free(infbuf); free(defbuf);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* *****************************************************************************
|
||||
* encode/main.c -- encode a file.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
* libg1m is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3.0 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* libg1m 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#define A(NAME) g1m_announce_##NAME
|
||||
#define E(NAME) g1m_encode_##NAME
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Correspondances */
|
||||
/* ************************************************************************** */
|
||||
/* Types */
|
||||
typedef int (*announce_t)(g1m_t*, size_t*);
|
||||
typedef int (*encode_t)(g1m_t*, g1m_buffer_t*);
|
||||
struct corresp {
|
||||
/* 'identification' */
|
||||
g1m_type_t types;
|
||||
g1m_platform_t platforms;
|
||||
|
||||
/* functions */
|
||||
announce_t announce;
|
||||
encode_t encode;
|
||||
};
|
||||
|
||||
/* All correspondances */
|
||||
static const struct corresp encodings[] = {
|
||||
/* sentinel */
|
||||
{0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Main function */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_encode:
|
||||
* Encode a file.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg buffer the buffer to write to.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_encode(g1m_t *handle, g1m_buffer_t *buffer)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* find the announcement and encoding function */
|
||||
const struct corresp *c = encodings - 1;
|
||||
while ((++c)->encode) {
|
||||
if (c->types && !(c->types & handle->type))
|
||||
continue;
|
||||
if (c->platforms && !(c->platforms & handle->platform))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!c->encode) return (g1m_error_op);
|
||||
|
||||
/* announce, if necessary */
|
||||
if (buffer->announce) {
|
||||
size_t size;
|
||||
if ((err = (*c->announce)(handle, &size))
|
||||
|| (err = (*buffer->announce)(buffer->cookie, size)))
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* encode */
|
||||
if (buffer->write) {
|
||||
err = (*c->encode)(handle, buffer);
|
||||
if (err) {
|
||||
(*buffer->unannounce)(buffer->cookie);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
|
||||
/* everything went well! */
|
||||
return (0);
|
||||
}
|
|
@ -27,13 +27,13 @@
|
|||
* Find space for a file and allocate.
|
||||
*
|
||||
* @arg handle the handle.
|
||||
* @arg tofile the user file pointer, to set.
|
||||
* @arg head the head.
|
||||
* @arg tofile the file pointer for the user.
|
||||
* @return the mcs file (NULL if allocation error).
|
||||
*/
|
||||
|
||||
int g1m_mcs_insert(g1m_t *handle, const g1m_mcshead_t *head,
|
||||
g1m_mcsfile_t **tofile)
|
||||
int g1m_mcs_insert(g1m_t *handle, g1m_mcsfile_t **tofile,
|
||||
const g1m_mcshead_t *head)
|
||||
{
|
||||
g1m_mcsfile_t **pfile = NULL; *tofile = NULL;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
|
||||
#ifndef G1M_DISABLED_FILE
|
||||
/* ************************************************************************** */
|
||||
/* FILE buffer */
|
||||
|
@ -35,7 +34,9 @@
|
|||
int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size)
|
||||
{
|
||||
FILE *file = (void*)vcookie;
|
||||
# if LOGLEVEL <= ll_error
|
||||
size_t orig = size;
|
||||
# endif
|
||||
|
||||
while (size) {
|
||||
size_t read = fread(buf, 1, size, file);
|
||||
|
@ -50,7 +51,7 @@ int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size)
|
|||
logm_info(buf, orig - size);
|
||||
}
|
||||
# endif
|
||||
return (g1m_error_eof);
|
||||
return (feof(file) ? g1m_error_eof : g1m_error_read);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +59,39 @@ int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_filebuffer_write:
|
||||
* Write to a filebuffer.
|
||||
*
|
||||
* @arg vcookie the FILE* (uncasted)
|
||||
* @arg buf the buffer to write.
|
||||
* @arg size the size to write.
|
||||
* @return the error (if any).
|
||||
*/
|
||||
|
||||
int g1m_filebuffer_write(void *vcookie, const unsigned char *buf, size_t size)
|
||||
{
|
||||
FILE *file = (void*)vcookie;
|
||||
# if LOGLEVEL <= ll_error
|
||||
size_t orig = size;
|
||||
# endif
|
||||
|
||||
while (size) {
|
||||
size_t written = fwrite(buf, 1, size, file);
|
||||
buf += written;
|
||||
size -= written;
|
||||
|
||||
if (!written) {
|
||||
log_error("WRITING failed: wrote %" PRIuSIZE "/%" PRIuSIZE
|
||||
" bytes, %" PRIuSIZE " missing.", orig - size, orig, size);
|
||||
return (g1m_error_write);
|
||||
}
|
||||
}
|
||||
|
||||
/* no error! */
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
/* ************************************************************************** */
|
||||
/* Memory buffer */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* *****************************************************************************
|
||||
* core/open.c -- open a file and decode it.
|
||||
* utils/file.c -- FILE-related functions.
|
||||
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
||||
*
|
||||
* This file is part of libg1m.
|
||||
|
@ -21,9 +21,12 @@
|
|||
#include <stdlib.h>
|
||||
#ifndef G1M_DISABLED_FILE
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Open a FILE */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_open:
|
||||
* Open handle using path.
|
||||
* Open a file using its path, and decode it.
|
||||
*
|
||||
* @arg handle the handle to create.
|
||||
* @arg path the path of the file to open.
|
||||
|
@ -34,10 +37,8 @@
|
|||
int g1m_open(g1m_t **handle, const char *path,
|
||||
g1m_type_t expected)
|
||||
{
|
||||
/* open stream */
|
||||
/* open stream and decode */
|
||||
FILE *f = fopen(path, "r");
|
||||
|
||||
/* open using `g1m_fopen` */
|
||||
int err = g1m_fopen(handle, path, f, expected);
|
||||
|
||||
/* close opened stream and return error code (or 0 if ok) */
|
||||
|
@ -47,7 +48,7 @@ int g1m_open(g1m_t **handle, const char *path,
|
|||
|
||||
/**
|
||||
* g1m_fopen:
|
||||
* Open handle using pointer on FILE.
|
||||
* Decode a file using a FILE structure.
|
||||
*
|
||||
* Will not seek, and will not keep the stream.
|
||||
* Make sure to fclose the stream after use.
|
||||
|
@ -76,4 +77,53 @@ int g1m_fopen(g1m_t **handle, const char *path, FILE *stream,
|
|||
return (g1m_decode(handle, path, &buffer, expected));
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Open a FILE and write into it */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_write:
|
||||
* Open a file and encode the file into it.
|
||||
*
|
||||
* @arg handle the handle to encode.
|
||||
* @arg path the file path.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_write(g1m_t *handle, const char *path)
|
||||
{
|
||||
/* open the stream and write */
|
||||
FILE *f = fopen(path, "w");
|
||||
int err = g1m_fwrite(handle, f);
|
||||
|
||||
/* close opened stream in case of error */
|
||||
if (f) fclose(f);
|
||||
if (f && err) remove(path);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_fwrite:
|
||||
* Write to a FILE pointer.
|
||||
*
|
||||
* @arg handle the handle to encode.
|
||||
* @arg stream the FILE stream.
|
||||
* @return the error code (0 if ok).
|
||||
*/
|
||||
|
||||
int g1m_fwrite(g1m_t *handle, FILE *stream)
|
||||
{
|
||||
/* check stream */
|
||||
if (!stream) return (g1m_error_nostream);
|
||||
if (!__fwritable(stream)) return (g1m_error_nowrite);
|
||||
|
||||
/* make the buffer */
|
||||
g1m_buffer_t buffer = {
|
||||
.cookie = stream,
|
||||
.write = g1m_filebuffer_write
|
||||
};
|
||||
|
||||
/* encode to file */
|
||||
return (g1m_encode(handle, &buffer));
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue