From 16f6b7a5baec41f18fde75fd311fb988e3c31810 Mon Sep 17 00:00:00 2001
From: Shengjiu Wang <shengjiu.wang@nxp.com>
Date: Fri, 13 Jul 2018 18:13:24 +0800
Subject: [PATCH] tinycompress: Add id3 decoding

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 include/tinycompress/id3_tag_decode.h | 198 +++++++++++
 src/utils/Makefile.am                 |   2 +-
 src/utils/cplay.c                     |  88 +++++
 src/utils/id3_tag_decode.c            | 642 ++++++++++++++++++++++++++++++++++
 4 files changed, 929 insertions(+), 1 deletion(-)
 create mode 100644 include/tinycompress/id3_tag_decode.h
 create mode 100644 src/utils/id3_tag_decode.c

diff --git a/include/tinycompress/id3_tag_decode.h b/include/tinycompress/id3_tag_decode.h
new file mode 100644
index 0000000..1a911d7
--- /dev/null
+++ b/include/tinycompress/id3_tag_decode.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
+ * Copyright 2018 NXP
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/******************************************************************
+ *  file name       : id3_tag_decode.h
+ *
+ *  description     : stores typedefs of structures specific to MP3 tag
+ *
+ *  revision history:
+ *       29 04 2004       DK     creation
+ *****************************************************************/
+
+#ifndef ID3_TAG_DECODE_H
+#define ID3_TAG_DECODE_H
+
+typedef signed char             WORD8;
+typedef signed char *           pWORD8;
+typedef unsigned char           UWORD8;
+typedef unsigned char *         pUWORD8;
+
+typedef signed short            WORD16;
+typedef signed short *          pWORD16;
+typedef unsigned short          UWORD16;
+typedef unsigned short *        pUWORD16;
+
+typedef signed int              WORD24;
+typedef signed int *            pWORD24;
+typedef unsigned int            UWORD24;
+typedef unsigned int *          pUWORD24;
+
+typedef signed int              WORD32;
+typedef signed int *            pWORD32;
+typedef unsigned int            UWORD32;
+typedef unsigned int *          pUWORD32;
+
+typedef void                    VOID;
+typedef void *                  pVOID;
+
+typedef signed int              BOOL;
+typedef unsigned int            UBOOL;
+typedef signed int              FLAG;
+typedef unsigned int            UFLAG;
+typedef signed int              LOOPIDX;
+typedef unsigned int            ULOOPIDX;
+typedef signed int              WORD;
+typedef unsigned int            UWORD;
+
+#define MAX_TAG_FRAME_SIZE		100
+
+#define ID3V1		(0x544147)      /* 0x544147 is TAG in WORD8 */
+
+#define ID3V2		(0x494433)      /* 0x494433 is ID3 in WORD8 */
+
+/*
+ * structure corresponding to ID3 tag v1 header.
+ * this structure has all the field corresponding to ID3 tag v1 header.
+ */
+
+typedef struct {
+	WORD32 tag;				// 3 bytes
+
+	WORD16 version;			// 2 bytes
+
+	WORD8 flag;				//1 byte
+
+	WORD32  size;		//4 bytes
+
+} id3_v2_header_struct;
+
+/* structure which will store the frame data and
+ * also put a limit max data to be stored
+ */
+typedef struct {
+	WORD8 frame_data[MAX_TAG_FRAME_SIZE];
+
+	WORD32  max_size;		//4 bytes
+
+	WORD16 tag_present;
+
+	WORD16 exceeds_buffer_size;
+
+} id3_v2_frame_struct;
+
+/*
+ * structure corresponding to ID3 tag v2.
+ * this structure has some of the  field corresponding to ID3 tag v2.
+ * if user wants to read some more tag information from
+ * the MP3 file, he can add that field in this structure and pass address
+ * of that element to get_inf function in id3_tag_decode.c under the
+ * corresponding field frame header. few fields which are needed are already
+ * populated by reading from the TAG header.
+ */
+typedef struct {
+	id3_v2_frame_struct  album_movie_show_title;
+
+	id3_v2_frame_struct  composer_name;
+
+	id3_v2_frame_struct  content_type;
+
+	id3_v2_frame_struct  encoded_by;
+
+	id3_v2_frame_struct  lyricist_text_writer;
+
+	id3_v2_frame_struct  content_group_description;
+
+	id3_v2_frame_struct  title_songname_content_description;
+
+	id3_v2_frame_struct  medxa_type;
+
+	id3_v2_frame_struct  original_album_movie_show_title;
+
+	id3_v2_frame_struct  original_filename;
+
+	id3_v2_frame_struct  original_lyricist_text_writer;
+
+	id3_v2_frame_struct  original_artist_performer;
+
+	id3_v2_frame_struct  file_owner_licensee;
+
+	id3_v2_frame_struct  lead_performer_soloist;
+
+	id3_v2_frame_struct  publisher;
+
+	id3_v2_frame_struct  private_frame;
+
+	id3_v2_frame_struct  other_info;
+
+	id3_v2_header_struct id3_v2_header;
+
+	WORD32 header_end;
+
+	WORD32 bytes_consumed;
+
+} id3v2_struct;
+
+/*
+ * structure corresponding to ID3 tag v1.
+ * this structure has all the field corresponding to ID3 tag v1.
+ */
+typedef struct {
+	WORD8 song_title[30]; //30 word8acters
+
+	WORD8 artist[30]; //30 word8acters
+
+	WORD8 album[30]; //30 word8acters
+
+	WORD8 year[4]; //4 word8acters
+
+	WORD8 comment[30]; //30 word8acters
+
+	WORD8 genre[1]; //1 byte
+
+} id3v1_struct;
+
+WORD32 get_info(const char *inp_buffer,
+		unsigned int         avail_inp,
+		WORD32               tag_size,
+		id3_v2_frame_struct *dest);
+
+WORD32 search_id3_v2(UWORD8 *buffer);
+
+WORD32 decode_id3_v2(const char *const buffer,
+		     id3v2_struct *id3v2,
+		     WORD32        continue_flag,
+		     WORD32        insize);
+
+WORD32 get_id3_v2_bytes(UWORD8 *buffer);
+
+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1);
+
+WORD32 search_id3_v1(UWORD8 *buffer);
+
+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1);
+
+void init_id3v2_field(id3v2_struct *id3v2);
+
+#endif
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
index 1b996d4..e813689 100644
--- a/src/utils/Makefile.am
+++ b/src/utils/Makefile.am
@@ -1,6 +1,6 @@
 bin_PROGRAMS = cplay crecord
 
-cplay_SOURCES = cplay.c
+cplay_SOURCES = cplay.c id3_tag_decode.c
 crecord_SOURCES = crecord.c
 
 cplay_CFLAGS = -I$(top_srcdir)/include
diff --git a/src/utils/cplay.c b/src/utils/cplay.c
index 87863a3..2a52b52 100644
--- a/src/utils/cplay.c
+++ b/src/utils/cplay.c
@@ -72,6 +72,7 @@
 #include "sound/compress_params.h"
 #include "tinycompress/tinycompress.h"
 #include "tinycompress/tinymp3.h"
+#include "tinycompress/id3_tag_decode.h"
 
 static int verbose;
 static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
@@ -245,12 +246,97 @@ int main(int argc, char **argv)
 	exit(EXIT_SUCCESS);
 }
 
+void shift_buffer(char *buf, int buf_size, int bytes_consumed)
+{
+	int i;
+
+	if (bytes_consumed <= 0)
+		return;
+
+	for (i = 0; i < buf_size - bytes_consumed; i++)
+		buf[i] = buf[i + bytes_consumed];
+}
+
+void parse_id3(FILE *file, int *offset) {
+	/* ID3 tag specific declarations */
+	unsigned char id3_buf[128];
+	unsigned char id3v2_buf[4096];
+	signed int id3_v1_found = 0, id3_v1_decoded = 0;
+	signed int id3_v2_found = 0, id3_v2_complete = 0;
+	signed int i_bytes_consumed = 0;
+	signed int i_fread_bytes;
+	id3v1_struct id3v1;
+	id3v2_struct id3v2;
+
+	{
+		fseek(file, -128, SEEK_END);
+		fread(id3_buf, 1, 128, file);
+
+		/* search for ID3V1 */
+		id3_v1_found = search_id3_v1(id3_buf + 0);
+		if (id3_v1_found) {
+			/* if ID3V1 is found, decode ID3V1 */
+			decode_id3_v1(id3_buf + 3, &id3v1);
+			id3_v1_decoded = 1;
+		}
+		fseek(file, 0, SEEK_SET);
+	}
+
+	{
+		signed int flag = 0;
+		signed int continue_flag = 0;
+
+		i_fread_bytes = fread(id3v2_buf,
+				sizeof(char), 0x1000, file);
+
+		/* search for ID3V2 */
+		id3_v2_found =
+			search_id3_v2(id3v2_buf);
+
+		if (id3_v2_found) {
+			/* initialise the max fields */
+			init_id3v2_field(&id3v2);
+
+			while (!id3_v2_complete && id3_v2_found) {
+				/* if ID3V2 is found, decode ID3V2 */
+				id3_v2_complete = decode_id3_v2((const char *const)id3v2_buf,
+							&id3v2, continue_flag, i_fread_bytes);
+
+				if (!id3_v2_complete) {
+					continue_flag = 1;
+					i_bytes_consumed = id3v2.bytes_consumed;
+
+					fseek(file, i_bytes_consumed, SEEK_SET);
+
+                                        i_fread_bytes = fread(id3v2_buf,
+                                                              sizeof(unsigned char), 0x1000, file);
+                                        if (i_fread_bytes <= 0) {
+						return;
+                                        }
+				}
+			}
+
+			if (id3_v2_complete) {
+				i_bytes_consumed = id3v2.bytes_consumed;
+				fseek(file, i_bytes_consumed, SEEK_SET);
+                        }
+                }
+	}
+
+	*offset = i_bytes_consumed;
+}
+
 void get_codec_mp3(FILE *file, struct compr_config *config,
 		struct snd_codec *codec)
 {
 	size_t read;
 	struct mp3_header header;
 	unsigned int channels, rate, bits;
+	int offset = 0;
+
+	parse_id3(file, &offset);
+
+	fseek(file, offset, SEEK_SET);
 
 	read = fread(&header, 1, sizeof(header), file);
 	if (read != sizeof(header)) {
@@ -279,6 +365,8 @@ void get_codec_mp3(FILE *file, struct compr_config *config,
 	codec->level = 0;
 	codec->ch_mode = 0;
 	codec->format = 0;
+
+	fseek(file, offset, SEEK_SET);
 }
 
 void get_codec_iec(FILE *file, struct compr_config *config,
diff --git a/src/utils/id3_tag_decode.c b/src/utils/id3_tag_decode.c
new file mode 100644
index 0000000..393967a
--- /dev/null
+++ b/src/utils/id3_tag_decode.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
+ * Copyright 2018 NXP
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <ctype.h>
+#include "tinycompress/id3_tag_decode.h"
+
+#define CHAR4(c1, c2, c3, c4) \
+	(int)(((unsigned char)(c1) << 24) | \
+		((unsigned char)(c2) << 16) | \
+		((unsigned char)(c3) << 8) | \
+		((unsigned char)c4))
+
+#ifndef MSVC_BUILD
+unsigned int umin(unsigned int a, unsigned int b)
+{
+	return (a < b ? a : b);
+}
+
+#else
+unsigned int umin(unsigned int a, unsigned int b)
+{
+	return (a < b ? a : b);
+}
+#endif
+
+/***********************************************************
+ *  function name   : display
+ *
+ *  description     : display ID3 tag contents.
+ *
+ *  arguments       : input parameters
+ *
+ *  values returned : 0
+ ***********************************************************/
+
+static void display2(const id3_v2_frame_struct * const src,
+		     int size,
+		     const char * const disp)
+{
+	int j;
+
+
+	for (j = 0; j < size; j++) {
+		int c = src->frame_data[j];
+
+		if (c) {
+			if (!isprint(c))
+				break;
+		}
+	}
+}
+
+static VOID display1(WORD8 src[], WORD32 size, WORD8 disp[])
+{
+	WORD32 j;
+
+	for (j = 0; j < size ; j++) {
+		int c = src[j];
+
+		if (c) {
+			if (!isprint(c))
+				break;
+		}
+	}
+}
+
+/*****************************************************************
+ *  function name   : init_id3_header
+ *
+ *  description     : initialise the max filed size of teh farem.
+ *
+ *  arguments       : input parameters
+ *
+ *  values returned : 0
+ ****************************************************************/
+
+VOID init_id3v2_field(id3v2_struct *id3v2)
+{
+	id3v2->album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->composer_name.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->content_type.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->encoded_by.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->content_group_description.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->title_songname_content_description.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->medxa_type.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->original_album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->original_filename.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->original_lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->original_artist_performer.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->file_owner_licensee.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->lead_performer_soloist.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->publisher.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->private_frame.max_size = MAX_TAG_FRAME_SIZE;
+	id3v2->other_info.max_size = MAX_TAG_FRAME_SIZE;
+
+	/* resetting the flag to indicate presese of frame */
+	id3v2->album_movie_show_title.tag_present = 0;
+	id3v2->composer_name.tag_present = 0;
+	id3v2->content_type.tag_present = 0;
+	id3v2->encoded_by.tag_present = 0;
+	id3v2->lyricist_text_writer.tag_present = 0;
+	id3v2->content_group_description.tag_present = 0;
+	id3v2->title_songname_content_description.tag_present = 0;
+	id3v2->medxa_type.tag_present = 0;
+	id3v2->original_album_movie_show_title.tag_present = 0;
+	id3v2->original_filename.tag_present = 0;
+	id3v2->original_lyricist_text_writer.tag_present = 0;
+	id3v2->original_artist_performer.tag_present = 0;
+	id3v2->file_owner_licensee.tag_present = 0;
+	id3v2->lead_performer_soloist.tag_present = 0;
+	id3v2->publisher.tag_present = 0;
+	id3v2->private_frame.tag_present = 0;
+	id3v2->other_info.tag_present = 0;
+
+	/* resetting the flag which indicates that size of the frame has
+	 * exceeded the max buffer size
+	 */
+	id3v2->album_movie_show_title.exceeds_buffer_size = 0;
+	id3v2->composer_name.exceeds_buffer_size = 0;
+	id3v2->content_type.exceeds_buffer_size = 0;
+	id3v2->encoded_by.exceeds_buffer_size = 0;
+	id3v2->lyricist_text_writer.exceeds_buffer_size = 0;
+	id3v2->content_group_description.exceeds_buffer_size = 0;
+	id3v2->title_songname_content_description.exceeds_buffer_size = 0;
+	id3v2->medxa_type.exceeds_buffer_size = 0;
+	id3v2->original_album_movie_show_title.exceeds_buffer_size = 0;
+	id3v2->original_filename.exceeds_buffer_size = 0;
+	id3v2->original_lyricist_text_writer.exceeds_buffer_size = 0;
+	id3v2->original_artist_performer.exceeds_buffer_size = 0;
+	id3v2->file_owner_licensee.exceeds_buffer_size = 0;
+	id3v2->lead_performer_soloist.exceeds_buffer_size = 0;
+	id3v2->publisher.exceeds_buffer_size = 0;
+	id3v2->private_frame.exceeds_buffer_size = 0;
+	id3v2->other_info.exceeds_buffer_size = 0;
+
+	id3v2->bytes_consumed = 0;
+	id3v2->header_end = 0;
+}
+
+/***************************************************************
+ *  function name   : search_id3_v2
+ *
+ *  description     : finds if ID3V2 starts at the start of given buffer.
+ *
+ *  arguments       : input parameters
+ *                   buffer          input buffer
+ *
+ *  values returned : FLAG   1: ID3 found   0: ID3 not found
+ ***************************************************************/
+WORD32 search_id3_v2(UWORD8 *buffer)
+{
+	UWORD32 temp;
+
+	temp  = buffer[0] << 16;
+	temp |= buffer[1] <<  8;
+	temp |= buffer[2];
+
+	if (temp == ID3V2)
+		return 1;   /* ID3 found */
+
+	return 0;       /* ID3 not found */
+}
+
+/**************************************************************
+ *  function name   : search_id3_v1
+ *
+ *  description     : finds if ID3V1 starts at the start of given buffer.
+ *
+ *  arguments       : input parameters
+ *                   buffer          input buffer
+ *
+ *  values returned : FLAG   1: ID3 found   0: ID3 not found
+ **************************************************************/
+WORD32 search_id3_v1(UWORD8 *buffer)
+{
+	UWORD32 temp;
+
+	temp  = buffer[0] << 16;
+	temp |= buffer[1] <<  8;
+	temp |= buffer[2];
+
+	if (temp == ID3V1)
+		return 1;   /* ID3 found */
+
+	return 0;       /* ID3 not found */
+}
+
+/***************************************************************
+ *  function name   : decode_id3_v1
+ *
+ *  description     : decodes ID3V1 tag.
+ *
+ *  arguments       : input parameters
+ *                   buffer              input buffer
+ *                   id3v1               structure
+ *
+ *  values returned : bytes consumed
+ **************************************************************/
+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1)
+{
+	WORD32 bytes_consumed = 0;
+	short tag_type;
+
+	/* setting the tag type */
+	tag_type = 1;
+
+	bytes_consumed = get_v1_info(buffer, id3v1);
+
+	return bytes_consumed;
+}
+
+/***********************************************************
+ *  function name   : get_v1_info
+ *
+ *  description     : gets ID3V1 information fields.
+ *
+ *  arguments       : input parameters
+ *                   buffer              input buffer
+ *                   id3v1               structure
+ *
+ *  values returned : bytes consumed
+ ***********************************************************/
+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1)
+{
+	WORD32 i;
+	WORD32 bytes_consumed = 0;
+
+	/* get song_title */
+	for (i = 0; i < 30; i++)
+		id3v1->song_title[i] = buffer[i];
+
+	buffer += 30;
+	bytes_consumed += 30;
+	display1(id3v1->song_title, 30, (WORD8 *)"song_title : ");
+
+	/* get artist */
+	for (i = 0; i < 30; i++)
+		id3v1->artist[i] = buffer[i];
+
+	buffer += 30;
+	bytes_consumed += 30;
+	display1(id3v1->artist, 30, (WORD8 *)"artist : ");
+
+	/* get album */
+	for (i = 0; i < 30; i++)
+		id3v1->album[i] = buffer[i];
+
+	buffer += 30;
+	bytes_consumed += 30;
+	display1(id3v1->album, 30, (WORD8 *)"album : ");
+
+	/* get year */
+	for (i = 0; i < 4; i++)
+		id3v1->year[i] = buffer[i];
+
+	buffer += 4;
+	bytes_consumed += 4;
+	display1(id3v1->year, 4, (WORD8 *)"year : ");
+
+	/* get comment */
+	for (i = 0; i < 30; i++)
+		id3v1->comment[i] = buffer[i];
+
+	buffer += 30;
+	bytes_consumed += 30;
+	display1(id3v1->comment, 30, (WORD8 *)"comment : ");
+
+	/* get genre */
+	for (i = 0; i < 1; i++)
+		id3v1->genre[i] = buffer[i];
+
+	buffer += 1;
+	bytes_consumed += 1;
+
+	return bytes_consumed;
+}
+
+/*****************************************************
+ *  function name   : decode_id3_v2
+ *
+ *  description     : decodes ID3V2 tag.
+ *
+ *  arguments       : input parameters
+ *                   buffer              input buffer
+ *                   id3v2               structure
+ *                   continue_flag       FLAG to indicate whether
+ *                                       it is first call or not
+ *                   insize              input buffer size
+ *
+ *  values returned : bytes consumed
+ ******************************************************/
+WORD32 decode_id3_v2(const char *const buffer,
+		     id3v2_struct *const id3v2,
+		     WORD32  continue_flag,
+		     WORD32  insize)
+{
+	UWORD32 size = 0, flag;
+	WORD32 i, buf_update_val;
+	UWORD8 buf[4], frame_header[10], id3_buffer[10];
+	WORD8 *bitstream_ptr;
+	short tag_type;
+
+	WORD32 bytes_consumed = 0;
+
+	if (id3v2->header_end == 1) {
+		id3v2->bytes_consumed += insize;
+		if (id3v2->bytes_consumed < id3v2->id3_v2_header.size)
+			return 0;
+
+		id3v2->bytes_consumed = (id3v2->id3_v2_header.size + 10);
+		return 1;
+	}
+
+	bitstream_ptr = (WORD8 *)id3_buffer;
+
+	if (!continue_flag) {
+		bytes_consumed += 3;
+		/* setting the tag type */
+		tag_type = 2;
+		id3v2->id3_v2_header.version  = buffer[bytes_consumed + 0] << 8;
+		id3v2->id3_v2_header.version |= buffer[bytes_consumed + 1];
+		id3v2->id3_v2_header.flag = buffer[bytes_consumed + 2];
+
+		/* making the msb of each byte zero */
+		buf[0] = buffer[bytes_consumed + 6] & 0x7f;
+		buf[1] = buffer[bytes_consumed + 5] & 0x7f;
+		buf[2] = buffer[bytes_consumed + 4] & 0x7f;
+		buf[3] = buffer[bytes_consumed + 3] & 0x7f;
+
+		bytes_consumed += 7;
+
+		/* concatenation the bytes after making
+		 * 7th bit zero to get 28 bits size
+		 */
+		size  = buf[0];
+		size |= (buf[1] << 7);
+		size |= (buf[2] << 14);
+		size |= (buf[3] << 21);
+		/* storing the size */
+		id3v2->id3_v2_header.size = size;
+
+		/* check for extended header */
+		if (id3v2->id3_v2_header.flag & 0x20) {
+			for (i = 0; i < 10; i++)
+				bitstream_ptr[i] = buffer[bytes_consumed + i];
+
+			i = 0;
+			bytes_consumed += 10;
+
+			size = bitstream_ptr[i++]  << 24;
+			size |= bitstream_ptr[i++] << 16;
+			size |= bitstream_ptr[i++] << 8;
+			size |= bitstream_ptr[i++];
+
+			/* two bytes for flag */
+			i += 2;
+			{
+				UWORD32 padding_size;
+
+				padding_size   = bitstream_ptr[i++]  << 24;
+				padding_size   |= bitstream_ptr[i++] << 16;
+				padding_size   |= bitstream_ptr[i++] << 8;
+				padding_size   |= bitstream_ptr[i++];
+
+				/* skipping the padding and frame size
+				 * number of bytes
+				 */
+				bytes_consumed += (padding_size + size);
+			}
+		}
+	}
+
+	while (id3v2->header_end != 1) {
+		char *key;
+		id3_v2_frame_struct *value;
+		unsigned int avail_inp;
+
+		/* reading the 10 bytes to get the frame header */
+
+		for (i = 0; i < 10; i++)
+			frame_header[i] = buffer[bytes_consumed + i];
+		bytes_consumed += 10;
+
+		/* getting the size from the header */
+		size = frame_header[4]  << 24;
+		size |= frame_header[5] << 16;
+		size |= frame_header[6] << 8;
+		size |= frame_header[7];
+
+		/* decoding the flag, currently not used */
+		flag = frame_header[8] << 8;
+		flag |= frame_header[9];
+
+		avail_inp = insize - bytes_consumed;
+
+		/* switching to the frame type */
+		switch (CHAR4(frame_header[0],
+			      frame_header[1],
+			      frame_header[2],
+			      frame_header[3])) {
+		case CHAR4('A', 'E', 'N', 'C'):
+		case CHAR4('A', 'P', 'I', 'C'):
+		case CHAR4('C', 'O', 'M', 'M'):
+		case CHAR4('C', 'O', 'M', 'R'):
+		case CHAR4('E', 'N', 'C', 'R'):
+		case CHAR4('E', 'Q', 'U', 'A'):
+		case CHAR4('E', 'T', 'C', 'O'):
+		case CHAR4('G', 'E', 'O', 'B'):
+		case CHAR4('G', 'R', 'I', 'D'):
+		case CHAR4('I', 'P', 'L', 'S'):
+		case CHAR4('L', 'I', 'N', 'K'):
+		case CHAR4('M', 'C', 'D', 'I'):
+		case CHAR4('M', 'L', 'L', 'T'):
+		case CHAR4('O', 'W', 'N', 'E'):
+		case CHAR4('P', 'C', 'N', 'T'):
+		case CHAR4('P', 'O', 'P', 'M'):
+		case CHAR4('P', 'O', 'S', 'S'):
+		case CHAR4('R', 'B', 'U', 'F'):
+		case CHAR4('R', 'V', 'A', 'D'):
+		case CHAR4('R', 'V', 'R', 'B'):
+		case CHAR4('S', 'Y', 'L', 'T'):
+		case CHAR4('S', 'Y', 'T', 'C'):
+		case CHAR4('T', 'B', 'P', 'M'):
+		case CHAR4('T', 'C', 'O', 'P'):
+		case CHAR4('T', 'D', 'A', 'T'):
+		case CHAR4('T', 'D', 'L', 'Y'):
+		case CHAR4('T', 'F', 'L', 'T'):
+		case CHAR4('T', 'I', 'M', 'E'):
+		case CHAR4('T', 'K', 'E', 'Y'):
+		case CHAR4('T', 'L', 'A', 'N'):
+		case CHAR4('T', 'L', 'E', 'N'):
+		case CHAR4('T', 'M', 'E', 'D'):
+		case CHAR4('T', 'O', 'F', 'N'):
+		case CHAR4('T', 'O', 'L', 'Y'):
+		case CHAR4('T', 'O', 'R', 'Y'):
+		case CHAR4('T', 'P', 'E', '2'):
+		case CHAR4('T', 'P', 'E', '3'):
+		case CHAR4('T', 'P', 'E', '4'):
+		case CHAR4('T', 'P', 'O', 'S'):
+		case CHAR4('T', 'R', 'C', 'K'):
+		case CHAR4('T', 'R', 'D', 'A'):
+		case CHAR4('T', 'R', 'S', 'N'):
+		case CHAR4('T', 'R', 'S', 'O'):
+		case CHAR4('T', 'S', 'I', 'Z'):
+		case CHAR4('T', 'S', 'R', 'C'):
+		case CHAR4('T', 'S', 'S', 'E'):
+		case CHAR4('T', 'Y', 'E', 'R'):
+		case CHAR4('T', 'X', 'X', 'X'):
+		case CHAR4('U', 'F', 'I', 'D'):
+		case CHAR4('U', 'S', 'E', 'R'):
+		case CHAR4('U', 'S', 'L', 'T'):
+		case CHAR4('W', 'C', 'O', 'M'):
+		case CHAR4('W', 'C', 'O', 'P'):
+		case CHAR4('W', 'O', 'A', 'F'):
+		case CHAR4('W', 'O', 'A', 'R'):
+		case CHAR4('W', 'O', 'A', 'S'):
+		case CHAR4('W', 'O', 'R', 'S'):
+		case CHAR4('W', 'P', 'A', 'Y'):
+		case CHAR4('W', 'P', 'U', 'B'):
+		case CHAR4('W', 'X', 'X', 'X'):
+		case CHAR4('T', 'I', 'T', '3'):
+			key = "other_info : ";
+			value = &id3v2->other_info;
+			break;
+		case CHAR4('P', 'R', 'I', 'V'):
+			key = "private_frame : ";
+			value = &id3v2->private_frame;
+			break;
+		case CHAR4('T', 'A', 'L', 'B'):
+			key = "album_movie_show_title : ";
+			value = &id3v2->album_movie_show_title;
+			break;
+		case CHAR4('T', 'C', 'O', 'M'):
+			key = "composer_name : ";
+			value = &id3v2->composer_name;
+			break;
+		case CHAR4('T', 'C', 'O', 'N'):
+			key = "content_type : ";
+			value = &id3v2->content_type;
+			break;
+		case CHAR4('T', 'E', 'N', 'C'):
+			key = "encoded_by : ";
+			value = &id3v2->encoded_by;
+			break;
+		case CHAR4('T', 'E', 'X', 'T'):
+			key = "lyricist_text_writer : ";
+			value = &id3v2->lyricist_text_writer;
+			break;
+		case CHAR4('T', 'I', 'T', '1'):
+			key = "content_group_description : ";
+			value = &id3v2->content_group_description;
+			break;
+		case CHAR4('T', 'I', 'T', '2'):
+			key = "title_songname_content_description : ";
+			value = &id3v2->title_songname_content_description;
+			break;
+		case CHAR4('T', 'O', 'A', 'L'):
+			key = "original_album_movie_show_title : ";
+			value = &id3v2->original_album_movie_show_title;
+			break;
+		case CHAR4('T', 'O', 'P', 'E'):
+			key = "original_artist_performer : ";
+			value = &id3v2->original_artist_performer;
+			break;
+		case CHAR4('T', 'O', 'W', 'N'):
+			key = "file_owner_licensee : ";
+			value = &id3v2->file_owner_licensee;
+			break;
+		case CHAR4('T', 'P', 'E', '1'):
+			key = "lead_performer_soloist : ";
+			value = &id3v2->lead_performer_soloist;
+			break;
+		case CHAR4('T', 'P', 'U', 'B'):
+			key =  "publisher : ";
+			value = &id3v2->publisher;
+			break;
+		default:
+			/* skipping the read 10 bytes */
+			buf_update_val = -10;
+			id3v2->header_end = 1;
+			value = 0;
+			key = 0;
+			break;
+		}
+
+		if (value != 0)
+			buf_update_val = get_info(&buffer[bytes_consumed],
+						  avail_inp, size, value);
+
+		/* Negative value for buf_update_val means one of two things:
+		 * 1. The default case happened and we're done with ID3V2 tag
+		 *    frames, or
+		 * 2. get_info() returned -1 to indicate that more input is
+		 *    required to decode this frame of the tag.
+		 */
+		if (buf_update_val >= 0)
+			display2(value,
+				 umin(value->max_size, buf_update_val), key);
+
+		if (buf_update_val == -1) {
+			id3v2->bytes_consumed += bytes_consumed;
+			return 1;
+		}
+
+		bytes_consumed += buf_update_val;
+
+		/* Is there enough input left (10 bytes) to begin
+		 * decoding another frame? If not, bag out temporarily
+		 * now. The caller will refill our input buffer and
+		 * call us again with continue_flag == 1.
+		 */
+		if (insize - bytes_consumed < 10) {
+			id3v2->bytes_consumed += bytes_consumed;
+			return 0; /* not completely decoded */
+		}
+	}
+
+	id3v2->bytes_consumed += bytes_consumed;
+	if ((id3v2->bytes_consumed + 10) < id3v2->id3_v2_header.size)
+		return 0; /* not completely decoded */
+
+	return 1; /* completely decoded */
+}
+
+/*******************************************************
+ *  function name   : get_id3_v2_bytes
+ *
+ *  description     : tells the size of ID3V2 tag.
+ *
+ *  arguments       : input parameters
+ *                   buffer          input buffer
+ *
+ *  values returned : bytes consumed
+ ********************************************************/
+WORD32 get_id3_v2_bytes(UWORD8 *buffer)
+{
+	WORD32 size;
+
+	/* making the msb of each byte zero */
+	size  =  (buffer[9] & 0x7f);
+	size |= ((buffer[8] & 0x7f) << 7);
+	size |= ((buffer[7] & 0x7f) << 14);
+	size |= ((buffer[6] & 0x7f) << 21);
+
+	return (size + 10);
+}
+
+/****************************************************
+ *  function name   : get_info
+ *
+ *  description     : read the frame information from the input buffer.
+ *
+ *  arguments       : input parameters
+ *
+ *  values returned : update value for buffer
+ ****************************************************/
+WORD32 get_info(const char *inp_buffer,
+		unsigned int         avail_inp,
+		WORD32               tag_size,
+		id3_v2_frame_struct *dest)
+{
+	WORD32 j;
+
+	/* setting the tag to indicate the presence of frame */
+	dest->tag_present = 1;
+	/* If there isn't enough input available, we punt back to the top
+	 * level and ask for more.
+	 */
+	if (avail_inp < umin(tag_size, dest->max_size))
+		return -1;
+
+	if (dest->max_size >= tag_size) {
+		for (j = 0; j < tag_size ; j++)
+			dest->frame_data[j] = inp_buffer[j];
+	} else {
+		dest->exceeds_buffer_size = 1;
+		for (j = 0; j < dest->max_size ; j++)
+			dest->frame_data[j] = inp_buffer[j];
+	}
+	return tag_size;
+}
-- 
2.7.4

