cake
/
libg1m
Archived
1
0
Fork 0

Started correcting pictures, started encoding (placeholder)

This commit is contained in:
Thomas Touhey 2017-03-19 23:27:21 +01:00
parent 8f0202924d
commit 00338af264
15 changed files with 285 additions and 68 deletions

View File

@ -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 */
/* ************************************************************************** */

View File

@ -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)}}, \

View File

@ -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];

View File

@ -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 */

View File

@ -34,6 +34,7 @@
# include <stdio_ext.h>
# else
# define __freadable(F) (1)
# define __fwritable(F) (1)
# endif
#endif /* LIBG1M_INTERNALS_STDIO_EXT_H */

View File

@ -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

View File

@ -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>

View File

@ -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",

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}
/**

91
src/encode/main.c Normal file
View File

@ -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);
}

View File

@ -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;

View File

@ -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 */

View File

@ -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