doubango/tinyMEDIA/src/content/tmedia_content_multipart.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
175b478c
 
74ca6d11
 *  Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 *
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * This file is part of MCOP MCPTT Client
 *
 * This is free software: you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 
 /**@file tmedia_content_multipart.c
  * @brief Base multipart content object.
  */
 #include "tinymedia/content/tmedia_content_multipart.h"
 
 #include "tsk_memory.h"
 #include "tsk_string.h"
 #include "tsk_debug.h"
 #include "tsk_uuid.h"
 
 tmedia_content_multipart_t* tmedia_content_multipart_create(const char* data, tsk_size_t data_size, const char* content_type, const char* content_disposition)
 {
 	tmedia_content_multipart_t* content = tsk_null;
 	if(!(content = tsk_object_new(tmedia_content_multipart_def_t))){
 		return tsk_null;
 	}
 
 	if(data == tsk_null || data_size == 0)
 	{
 		TSK_OBJECT_SAFE_FREE(content);
 		return tsk_null;
 	}
 	#if HAVE_CRT //Debug memory
 	content->data = (char*)calloc(data_size, sizeof(char));
 		
 	#else
 	content->data = (char*)tsk_calloc(data_size, sizeof(char));
 		
 	#endif //HAVE_CRT
 	memcpy(content->data, data, data_size);
 	content->data_size = data_size;
 
 	if(content_type != tsk_null)
 		content->content_type = tsk_strdup(content_type);
 	else
 		content->content_type = tsk_null;
 
 	if(content_disposition != tsk_null)
 		content->content_disposition = tsk_strdup(content_disposition);
 	else
 		content->content_disposition = tsk_null;
 
 	return content;
 }
 
 tmedia_content_multipart_t* tmedia_content_multipart_parse(const void* data, tsk_size_t size)
 {
 	//TO-DO
 	tmedia_content_multipart_t* mp_content = tsk_null;
 	const char* content_type_hdr = "Content-Type: ";
 	char* content_type_value = tsk_null;
 	const char* content_disp_hdr = "Content-Disposition: ";
 	const char* CRLF = "\r\n";
 	const char* DBL_CRLF = "\r\n\r\n";
 	char* content_disp_value = tsk_null;
 	int start_index = 0, stop_index = 0, value_size = 0;
 	char* content_buffer = (char*)data;
 	
 	start_index = tsk_strindexOf(content_buffer, size, content_type_hdr);
 	if(start_index >= 0)
 	{
 		start_index += strlen(content_type_hdr);
 		value_size = tsk_strindexOf(&content_buffer[start_index], size - start_index, CRLF);
 		if(value_size > 0)
 		{
 			#if HAVE_CRT //Debug memory
 				content_type_value = (char*)calloc((value_size + 1), sizeof(char));
 	
 	#else
 				content_type_value = (char*)tsk_calloc((value_size + 1), sizeof(char));
 	
 	#endif //HAVE_CRT
 			memcpy(content_type_value, &content_buffer[start_index], value_size);
 			content_type_value[value_size] = '\0';
 		}
 	}
 
 	start_index = tsk_strindexOf(content_buffer, size, content_disp_hdr);
 	if(start_index >= 0)
 	{
 		start_index += strlen(content_disp_hdr);
 		value_size = tsk_strindexOf(&content_buffer[start_index], size - start_index, CRLF);
 		if(value_size > 0)
 		{
 			#if HAVE_CRT //Debug memory
 					content_disp_value = (char*)calloc((value_size + 1), sizeof(char));
 
 	#else
 					content_disp_value = (char*)tsk_calloc((value_size + 1), sizeof(char));
 
 	#endif //HAVE_CRT
 			memcpy(content_disp_value, &content_buffer[start_index], value_size);
 			content_disp_value[value_size] = '\0';
 		}
 	}
 
 	start_index = tsk_strindexOf(content_buffer, size, DBL_CRLF);
 
 	if(start_index < 0)
 	{
 		TSK_FREE(content_type_value);
 	    TSK_FREE(content_disp_value);
 		return tsk_null;
 	}
 	
 	start_index += strlen(DBL_CRLF);
 
 	//If there is a final double CRLF, delete one
 	stop_index = tsk_strindexOf(&content_buffer[start_index], size - start_index, DBL_CRLF);
 	if(stop_index > 0)
 		stop_index += start_index + 2;
 	else
 		stop_index = size;
 
 	mp_content = tmedia_content_multipart_create(&content_buffer[start_index], stop_index - start_index, content_type_value, content_disp_value);
 	
 	TSK_FREE(content_type_value);
 	TSK_FREE(content_disp_value);
 	return mp_content;
 }
 
 char* tmedia_content_multipart_tostring(tmedia_content_multipart_t* self)
 {
 	char* string = tsk_null;
 
 	if(!self) {
 		return tsk_null;
 	}
 
 	if(self->content_type && !tsk_strempty(self->content_type))
 		tsk_sprintf(&string, "Content-Type: %s", self->content_type);
 
 	if(self->content_disposition && !tsk_strempty(self->content_disposition))
 		tsk_strcat_2(&string, "\r\nContent-Disposition: %s", self->content_disposition);
 
 	tsk_strcat_2(&string, "\r\n\r\n%.*s", self->data_size, self->data);
 
 	return string;
 }
 
175b478c
 
c732d49e
 int tmedia_content_multipart_init(tmedia_content_multipart_t* self)
 {
 	if (!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	return 0;
 }
 
 int tmedia_content_multipart_deinit(tmedia_content_multipart_t* self)
 {
 	if (!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	TSK_FREE(self->data);
 	self->data_size = 0;
 	TSK_FREE(self->content_type);
 	TSK_FREE(self->content_disposition);
 
 	return 0;
 }
 
 /* constructor */
 static tsk_object_t* tmedia_content_multipart_ctor(tsk_object_t * self, va_list * app)
 {
 	tmedia_content_multipart_t *content = self;
 	if (content){
 	}
 	return self;
 }
 /* destructor */
 static tsk_object_t* tmedia_content_multipart_dtor(tsk_object_t * self)
 {
 	tmedia_content_multipart_t *content = self;
 	if (content){
 		tmedia_content_multipart_deinit(content);
 	}
 
 	return self;
 }
 
 static const tsk_object_def_t tmedia_content_multipart_def_s =
 {
 	sizeof(tmedia_content_multipart_t),
 	tmedia_content_multipart_ctor,
 	tmedia_content_multipart_dtor,
 	tsk_null,
 };
 const tsk_object_def_t *tmedia_content_multipart_def_t = &tmedia_content_multipart_def_s;
 
 
 tmedia_multipart_body_t* tmedia_content_multipart_body_create(const char* multipart_type, const char* boundary)
 {
 	tmedia_multipart_body_t* content = tsk_null;
 	if(!(content = tsk_object_new(tmedia_multipart_body_def_t))){
 		return tsk_null;
 	}
 
 	content->multipart_type = tsk_strdup(multipart_type);
 	if(boundary)
 		content->boundary = tsk_strdup(boundary);
 	else
 	{
 		tsk_uuidstring_t uuid;
 		tsk_uuidgenerate(&uuid);
 		tsk_strupdate(&(content->boundary), uuid);
 	}
 	content->contents = tsk_list_create();
 
 	return content;
 }
 
 tmedia_multipart_body_t* tmedia_content_multipart_body_parse(const void* data, tsk_size_t sizeconst, char* multipart_type, const char* boundary)
 {
 	//TO-DO
 	tmedia_multipart_body_t* mp_body = tsk_null;
 	tmedia_content_multipart_t* mp_content = tsk_null;
 	const char* body_buffer = (char*)data;
 	char* content_buffer = tsk_null;
 	int start_index = 0, stop_index = 0, read_index = 0, final_index = 0;
 	tsk_size_t boundary_size = 0, delimited_boundary_size = 0, delimited_final_boundary_size = 0, content_buffer_size = 0;
 	char* delimited_boundary = tsk_null;
 	char* delimited_final_boundary = tsk_null;
 
 	if(data == tsk_null || sizeconst == 0 || multipart_type == tsk_null || boundary == tsk_null)
 		return tsk_null;
 	
 	boundary_size = tsk_strlen(boundary);
 	delimited_boundary_size = boundary_size + 3;
 	#if HAVE_CRT //Debug memory
 	delimited_boundary = (char*)calloc(delimited_boundary_size, sizeof(char));
 		
 	#else
 	delimited_boundary = (char*)tsk_calloc(delimited_boundary_size, sizeof(char));
 		
 	#endif //HAVE_CRT
 	tsk_sprintf(&delimited_boundary, "--%s", boundary);
 	delimited_boundary[delimited_boundary_size - 1] = '\0';
 	delimited_final_boundary_size = boundary_size + 5;
 	#if HAVE_CRT //Debug memory
 		delimited_final_boundary = (char*)calloc(delimited_final_boundary_size, sizeof(char));
 	
 	#else
 		delimited_final_boundary = (char*)tsk_calloc(delimited_final_boundary_size, sizeof(char));
 	
 	#endif //HAVE_CRT
 	tsk_sprintf(&delimited_final_boundary, "--%s--", boundary);
 	delimited_final_boundary[delimited_final_boundary_size - 1] = '\0';
 
 	final_index = tsk_strLastIndexOf(body_buffer, sizeconst, delimited_final_boundary);
 	if(final_index <= 0)
 	{
175b478c
 		TSK_DEBUG_ERROR("Error trying to get the end of the message");
c732d49e
 		TSK_FREE(delimited_boundary);
 		TSK_FREE(delimited_final_boundary);
 		return tsk_null;
 	}
 
 	while(read_index < final_index)
 	{
 		start_index = tsk_strindexOf(&body_buffer[read_index], sizeconst - read_index, delimited_boundary);
 		if(start_index < 0)
 			break;
 		start_index += read_index + (delimited_boundary_size - 1) + 2; //CRLF
 		stop_index = tsk_strindexOf(&body_buffer[start_index], sizeconst - start_index, delimited_boundary);
 		if(stop_index < 0) 
 			break;
 		stop_index += start_index;
 		if(stop_index > final_index)
 			break;
 		content_buffer_size = stop_index - start_index;
 		#if HAVE_CRT //Debug memory
 		content_buffer = (char*)calloc(content_buffer_size, sizeof(char));
 		
 	#else
 		content_buffer = (char*)tsk_calloc(content_buffer_size, sizeof(char));
 		
 	#endif //HAVE_CRT
 		memcpy(content_buffer, &body_buffer[start_index], content_buffer_size);
 		mp_content = tmedia_content_multipart_parse(content_buffer, content_buffer_size);
 		if(mp_content != tsk_null)
 		{
 			if(mp_body == tsk_null)
 				mp_body = tmedia_content_multipart_body_create(multipart_type, boundary);
 
 			tsk_list_push_back_data(mp_body->contents, (void**)&mp_content);
 		}
 		read_index = stop_index;
 		TSK_FREE(content_buffer);
 		content_buffer = tsk_null;
 		content_buffer_size = 0;
 	}
 	
 	TSK_FREE(delimited_boundary);
 	TSK_FREE(delimited_final_boundary);
 	return mp_body;
 }
 
 char* tmedia_content_multipart_body_tostring(tmedia_multipart_body_t* self)
 {
 	char* string = tsk_null;
 	tmedia_content_multipart_t *content;
 	const tsk_list_item_t* item;
 
 	if(!self || !self->boundary) {
 		return tsk_null;
 	}
 
 	tsk_list_foreach(item, self->contents){
 		char* content_string = tsk_null;
 		content = (tmedia_content_multipart_t*)item->data;
 		content_string = tmedia_content_multipart_tostring(content);
 		if(content_string)
 			tsk_strcat_2(&string, "--%s\r\n%s\r\n", self->boundary, content_string);
 	}
 
 	tsk_strcat_2(&string, "--%s--\r\n", self->boundary);
 
 	return string;
 }
 
175b478c
 
c732d49e
 int tmedia_content_multipart_body_init(tmedia_multipart_body_t* self)
 {
 	if (!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	return 0;
 }
 
 char* tmedia_content_multipart_body_get_header(tmedia_multipart_body_t* self)
 {
 	char* content_type_hdr = tsk_null;
 
 	if(!self){
 		return tsk_null;
 	}
 
 	tsk_sprintf(&content_type_hdr, "%s;boundary=%s", self->multipart_type, self->boundary);//change  "%s;boundary=\"%s\"" to "%s;boundary=%s"
 
     return content_type_hdr;
 }
 
 int tmedia_content_multipart_body_add_content(tmedia_multipart_body_t* self, tmedia_content_multipart_t* content)
 {
 	if(!self || !content)
 		return -1;
 
 	if(!self->contents)
 		self->contents = tsk_list_create();
 
 	tsk_list_push_back_data(self->contents, (void**)&content);
 
 	return 0;
 }
 
 tmedia_content_multipart_t* tmedia_content_multipart_body_get_content(tmedia_multipart_body_t* self, const char* content_type)
 {
 	tmedia_content_multipart_t *content = tsk_null;
 	tmedia_content_multipart_t *ret = tsk_null;
 	const tsk_list_item_t* item;
 
 	if(!self || !self->contents) {
 		return tsk_null;
 	}
 
 	tsk_list_foreach(item, self->contents)
 	{
175b478c
         content = (tmedia_content_multipart_t*)item->data;
         if(memcmp(content->content_type, content_type, strlen(content->content_type)) == 0)
c732d49e
 		{
 			ret = content;
 			break;
 		}
 	}
 
 	return ret;
 }
 
 int tmedia_content_multipart_body_deinit(tmedia_multipart_body_t* self)
 {
 	if (!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	TSK_FREE(self->multipart_type);
 	TSK_FREE(self->boundary);
 	TSK_FREE(self->contents);
 
 	return 0;
 }
 
 /* constructor */
 static tsk_object_t* tmedia_content_multipart_body_ctor(tsk_object_t * self, va_list * app)
 {
 	tmedia_multipart_body_t *content = self;
 	if (content){
 	}
 	return self;
 }
 /* destructor */
 static tsk_object_t* tmedia_content_multipart_body_dtor(tsk_object_t * self)
 {
 	tmedia_multipart_body_t *content = self;
 	if (content){
 		tmedia_content_multipart_body_deinit(content);
 	}
 
 	return self;
 }
 
 static const tsk_object_def_t tmedia_multipart_body_def_s =
 {
 	sizeof(tmedia_multipart_body_t),
 	tmedia_content_multipart_body_ctor,
 	tmedia_content_multipart_body_dtor,
 	tsk_null,
 };
 const tsk_object_def_t *tmedia_multipart_body_def_t = &tmedia_multipart_body_def_s;