/****************************************************************************** * Copyright (c) 2000-2023 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Gabor Szalai - initial implementation and initial documentation * Peter Kremer * Sandor Palugyai * Tibor Harai ******************************************************************************/ // // File: RTP_File.cc // Description: Media files operation for RTP // Rev: R5B // Prodnr: CNL 113 392 // #include "RTP_File_Types.hh" #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #define CREAT_MODE 0644 namespace RTP__File__Types{ enum Operation {READ, WRITE}; typedef struct{ CHARSTRING *filename; int fd; int block_size; struct stat stat_buf; } File_info_type; void log_info_list(); int f_Fileinfo_Check(const int& fd, const Operation& OPERATION); int f_Operation_Check(const int& fd, const int& blockno, const int& nof_b, const Operation& OPERATION, const int& hdr_off); void f__Count__JPEG__Header__Offset(RTP__FileInfo& fi); File_info_type *file_info_list = NULL; int nof_file_infos = 0; INTEGER f__INIT__CODEC(const CHARSTRING& filename, const INTEGER& block_size, const InitOperType& INIT_TYPE) { if(filename=="") TTCN_error("INIT__CODEC: empty filename is not allowed"); if((int)block_size<=0) TTCN_error("INIT__CODEC: Block size must be a positive integer"); if( !(file_info_list = (File_info_type*) realloc( file_info_list, (nof_file_infos+1)*sizeof(File_info_type) )) ) TTCN_error("INIT__CODEC: There is not enough memory."); switch (INIT_TYPE) { case InitOperType::OPEN: if( (file_info_list[nof_file_infos].fd = open((const char *)filename, O_RDONLY))<0 ) TTCN_error("INIT__CODEC: Cannot open file '%s'\n", (const char *)filename); break; case InitOperType::CREATE: if( (file_info_list[nof_file_infos].fd = creat((const char *)filename, CREAT_MODE))<0 ) TTCN_error("INIT__CODEC: Cannot create file '%s'\n", (const char *)filename); break; default: TTCN_error("INIT__CODEC: Wrong init_type setting! Available: OPEN, CREATE.\n"); break; } file_info_list[nof_file_infos].filename = new CHARSTRING(filename); file_info_list[nof_file_infos].block_size = (int)block_size; if( stat((const char *)*file_info_list[nof_file_infos].filename, &file_info_list[nof_file_infos].stat_buf) == -1 ) TTCN_error("INIT__CODEC: Cannot gather file info"); if( file_info_list[nof_file_infos].stat_buf.st_size%block_size != 0 ) TTCN_warning("INIT__CODEC: File %s contains uncomplete blocks", (const char *)filename); TTCN_Logger::log(TTCN_DEBUG,"INIT__CODEC: filename: %s, origfilename: %s\n", (const char *)*file_info_list[nof_file_infos].filename, (const char*)filename); nof_file_infos++; log_info_list(); return INTEGER(file_info_list[nof_file_infos-1].fd); } OCTETSTRING f__GET__CONTENT(const INTEGER& fd, const INTEGER& blockno, const INTEGER& nof_blocks_to_read, const INTEGER& header_offset) { int bytes_to_read = f_Operation_Check((int)fd, (int)blockno, (int)nof_blocks_to_read, READ, (int)header_offset); if (!bytes_to_read) return OCTETSTRING(0, NULL); unsigned char * buf = (unsigned char*) malloc(bytes_to_read); if(!buf) TTCN_error("GET_CONTENT: There is not enough memory."); int read_data = 0; if((read_data = read(fd, buf, bytes_to_read))<0) TTCN_error("GET_CONTENT: unsuccesful read (%d)", read_data); OCTETSTRING retval(read_data, buf); free(buf); return retval; } void f__Count__JPEG__Header__Offset(RTP__FileInfo& fi) { int i = f_Fileinfo_Check((int)fi.fd(), READ); struct stat &stat_buf = file_info_list[i].stat_buf; int hdr_off = (int)fi.headerOffset(); if(hdr_off < 0) TTCN_error("Get_Media_Header: Header offset must be a non-negative integer!"); if(stat_buf.st_size < hdr_off) TTCN_error("Get_Media_Header: Size of file %s is smaller than the size of header!", (const char *)*file_info_list[i].filename); if(lseek((int)fi.fd(), 0, SEEK_SET) < 0) TTCN_error("Count_JPEG_Header_Offset: Cannot set the starting position in file %s\n", (const char *)*file_info_list[i].filename); unsigned char * buf = (unsigned char*) malloc(hdr_off); if(!buf) TTCN_error("Count_JPEG_Header_Offset: There is not enough memory."); int read_data = 0; if((read_data = read((int)fi.fd(), buf, hdr_off))<0) TTCN_error("Count_JPEG_Header_Offset: unsuccesful read (%d)",read_data); fi.headerOffset() = hdr_off + ((((int)buf[hdr_off-2]) << 8) | buf[hdr_off-1]); free(buf); } INTEGER f__PUT__CONTENT(const INTEGER& fd, const INTEGER& blockno, const OCTETSTRING& stream, const INTEGER& header_offset) { int bytes_to_write = f_Operation_Check((int)fd, (int)blockno, stream.lengthof(), WRITE, (int)header_offset); if (!bytes_to_write) return 0; unsigned char * buf = (unsigned char*)(const unsigned char*) stream; if (write(fd, buf, bytes_to_write) != bytes_to_write) TTCN_error("PUT_CONTENT: unsuccesful write to file"); return bytes_to_write; } void f__CLOSE__CODEC(const INTEGER& fd) { for(int i=0;i<nof_file_infos;i++) { if(file_info_list[i].fd == fd) { close((int)fd); delete file_info_list[i].filename; nof_file_infos--; if(nof_file_infos==0) { free(file_info_list); file_info_list = NULL; return; } for(int j=i;j<nof_file_infos;j++) file_info_list[j] = file_info_list[j+1]; if( !(file_info_list = (File_info_type *) realloc(file_info_list, nof_file_infos*sizeof(File_info_type))) ) TTCN_error("CLOSE__CODEC: There is not enough memory."); return; } } TTCN_error("CLOSE__CODEC: Unknown file descriptor (%d)", (int)fd); } void log_info_list() { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("\nnumber of fds: %d\n", nof_file_infos); for(int i=0;i<nof_file_infos;i++) { TTCN_Logger::log_event("%d. fd = %d\n", i, file_info_list[i].fd); } TTCN_Logger::end_event(); } int f_Fileinfo_Check(const int& fd, const Operation& OPERATION) { int i; for(i=0; i<nof_file_infos; i++) { if(file_info_list[i].fd == fd) break; } if(i == nof_file_infos) TTCN_error("Fileinfo_Check: Unknown file descriptor (%d)", fd); if(!nof_file_infos) TTCN_error("Fileinfo_Check: file info list is empty"); if(!file_info_list[i].filename) TTCN_error("Fileinfo_Check: inconsistent file info list (filename is missing)"); if( (file_info_list && !nof_file_infos) || (!file_info_list && nof_file_infos) ) TTCN_error("Fileinfo_Check: inconsistent file info list"); if (OPERATION==WRITE && stat((const char *)*file_info_list[i].filename, &file_info_list[i].stat_buf)==-1) TTCN_error("Fileinfo_Check: Cannot gather file info"); return i; } int f_Operation_Check(const int& fd, const int& blockno, const int& nof_b, const Operation& OPERATION, const int& hdr_off) { int i = f_Fileinfo_Check(fd, OPERATION); int block_size = file_info_list[i].block_size; struct stat &stat_buf = file_info_list[i].stat_buf; // nof_b: number of blocks (OPERATION==READ) or // number of bytes (OPERATION==WRITE) if(!nof_b && !hdr_off) return 0; if(nof_b < 0) TTCN_error("Operation_Check: The number of blocks to read must be a non-negative integer"); if(blockno < 0) TTCN_error("Operation_Check: Starting block position must be a non-negative integer"); if(hdr_off < 0) TTCN_error("Operation_Check: Header offset must be a non-negative integer"); if(stat_buf.st_size < blockno*block_size + hdr_off) TTCN_error("Operation_Check: Size of file %s is smaller than the starting block position", (const char *)*file_info_list[i].filename); int bytes_to_operation; switch (OPERATION) { case READ: if(!nof_b && hdr_off) { if(lseek(fd, 0, SEEK_SET) < 0) TTCN_error("Operation_Check: Cannot set the starting position in file %s\n", (const char *)*file_info_list[i].filename); return hdr_off; } if(lseek(fd, blockno*block_size + hdr_off, SEEK_SET) < 0) TTCN_error("Operation_Check: Cannot set the starting position in file %s\n", (const char *)*file_info_list[i].filename); if (stat_buf.st_size == blockno*block_size + hdr_off) bytes_to_operation = 0; else if (stat_buf.st_size < (blockno+nof_b)*block_size + hdr_off) { bytes_to_operation = stat_buf.st_size - block_size*blockno - hdr_off; TTCN_warning("Operation_Check: This is an uncomplete block. Size: %d byte/bytes.", bytes_to_operation); } else bytes_to_operation = block_size*nof_b; break; case WRITE: if(lseek(fd, blockno*block_size + hdr_off, SEEK_SET) < 0) TTCN_error("Operation_Check: Cannot set the starting position in file %s\n", (const char *)*file_info_list[i].filename); bytes_to_operation = nof_b; break; default: TTCN_error("Operation_Check: Wrong OPERATION setting! Available: READ, WRITE.\n"); break; } return bytes_to_operation; } }