summaryrefslogtreecommitdiff
path: root/XMPFiles/source/FormatSupport/ID3_Support.hpp
blob: dda6bfc137fc499eced2e02df1ba40d3e9073206 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#ifndef __ID3_Support_hpp__
#define __ID3_Support_hpp__ 1

// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
// Copyright 2008 Adobe Systems Incorporated
// All Rights Reserved
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================

#include "public/include/XMP_Environment.h"	// ! This must be the first include.

#include "public/include/XMP_Const.h"
#include "public/include/XMP_IO.hpp"

#if XMP_WinBuild
	#define stricmp _stricmp
#else
	int stricmp ( const char * left, const char * right );	// Case insensitive ASCII compare.
#endif

// =================================================================================================

namespace ID3_Support {

	// =============================================================================================

	inline XMP_Int32 synchToInt32 ( XMP_Uns32 rawDataBE ) {
		XMP_Validate ( (0 == (rawDataBE & 0x80808080)), "input not synchsafe", kXMPErr_InternalFailure );
		XMP_Int32 r = (rawDataBE & 0x0000007F) + ((rawDataBE >> 1) & 0x00003F80) +
					  ((rawDataBE >> 2) & 0x001FC000) + ((rawDataBE >> 3) & 0x0FE00000);
		return r;
	}

	inline XMP_Uns32 int32ToSynch ( XMP_Int32 value ) {
		XMP_Validate ( (0 <= 0x0FFFFFFF), "value too big", kXMPErr_InternalFailure );
		XMP_Uns32 r = (value & 0x0000007F) + ((value & 0x00003F80) << 1) +
					  ((value & 0x001FC000) << 2) + ((value & 0x0FE00000) << 3);
		return r;
	}

	// =============================================================================================
	
	bool InitializeGlobals();	// Initialize and terminate the known genre maps.
	void TerminateGlobals();
	
	// =============================================================================================

	namespace GenreUtils {	
		
		void ConvertGenreToXMP ( const char * id3Genre, std::string * xmpGenre );
		void ConvertGenreToID3 ( const char * xmpGenre, std::string * id3Genre );

		// Internal utilities, exposed for unit testing:
		const char * FindGenreName ( const std::string & code );
		const char * FindGenreCode ( const std::string & name );

	};

	// =============================================================================================

	class ID3Header {	// Minimal support to read and write the ID3 header.
	public:

		const static size_t o_id     = 0;
		const static size_t o_vMajor = 3;
		const static size_t o_vMinor = 4;
		const static size_t o_flags  = 5;
		const static size_t o_size   = 6;

		const static size_t kID3_TagHeaderSize = 10;	// This is the same in v2.2, v2.3, and v2.4.
		char fields [kID3_TagHeaderSize];

		~ID3Header() {};

		// Read the v2 header into the fields buffer and check the version.
		bool read ( XMP_IO* file );
		
		// Set the size and write the the v2 header from the fields buffer.
		void write ( XMP_IO* file, XMP_Int64 tagSize );

	};

	// =============================================================================================

	class ID3v2Frame {
	public:
	
		// Applies to ID3 v2.2, v2.3, and v2.4. The metadata values are mostly the same, v2.2 has
		// smaller frame headers and only supports UTF-16 Unicode.

		const static XMP_Uns16 o_id = 0;
		const static XMP_Uns16 o_size = 4; // size after unsync, excludes frame header.
		const static XMP_Uns16 o_flags = 8;

		const static int kV23_FrameHeaderSize = 10;	// The header for v2.3 and v2.4.
		const static int kV22_FrameHeaderSize = 6;	// The header for v2.2.
		char fields [kV23_FrameHeaderSize];

		XMP_Uns32 id;
		XMP_Uns16 flags;
		
		char* content;
		XMP_Int32 contentSize; // size of variable content, right as its stored in o_size

		bool active; //default: true. flag is lowered, if another frame with replaces this one as "last meaningful frame of its kind"
		bool changed; //default: false. flag is raised, if setString() is used

		ID3v2Frame();
		ID3v2Frame ( XMP_Uns32 id );
		
		ID3v2Frame ( const ID3v2Frame& orig ) {
			XMP_Throw ( "ID3v2Frame copy constructor not implemented", kXMPErr_InternalFailure );
		}
		
		~ID3v2Frame() { this->release(); }

		void release();
		
		void setFrameValue ( const std::string& rawvalue, bool needDescriptor = false,
							 bool utf16 = false, bool isXMPPRIVFrame = false, bool needEncodingByte = true, bool isAlreadyEncoded = false );
		
		XMP_Int64 read ( XMP_IO* file, XMP_Uns8 majorVersion );
		void write ( XMP_IO* file, XMP_Uns8 majorVersion );

		// two types of COMM frames should be preserved but otherwise ignored
		// * a 6-field long header just having
		//      encoding(1 byte),lang(3 bytes) and 0x00 31 (no descriptor, "1" as content")
		//      perhaps only used to indicate client language
		// * COMM frames whose description begins with engiTun, these are iTunes flags
		//
		// returns true: job done as expted
		//         false: do not use this frame, but preserve (i.e. iTunes marker COMM frame)
		bool advancePastCOMMDescriptor ( XMP_Int32& pos );

		// returns the frame content as a proper UTF8 string
		//    * w/o the initial encoding byte
		//    * dealing with BOM's
		//
		// @returns: by value: character string with the value
		//			as return value: false if frame is "not of intereset" despite a generally
		//                            "interesting" frame ID, these are
		//                                * iTunes-'marker' COMM frame
		bool getFrameValue ( XMP_Uns8 majorVersion, XMP_Uns32 logicalID, std::string* utf8string );

	};

	// =============================================================================================

	class ID3v1Tag {	// Support for the fixed length v1 tag found at the end of the file.
	public:

		const static XMP_Uns16 o_tag     =   0; // must be "TAG"
		const static XMP_Uns16 o_title   =   3;
		const static XMP_Uns16 o_artist  =  33;
		const static XMP_Uns16 o_album   =  63;
		const static XMP_Uns16 o_year    =  93;
		const static XMP_Uns16 o_comment =  97;
		const static XMP_Uns16 o_zero    = 125; // must be zero for trackNo to be valid
		const static XMP_Uns16 o_trackNo = 126; // trackNo
		const static XMP_Uns16 o_genre   = 127; // last byte: index, or 255

		const static int kV1_TagSize = 128;

		bool read ( XMP_IO* file, SXMPMeta* meta );
		void write ( XMP_IO* file, SXMPMeta* meta );

	};

}

#endif	// __ID3_Support_hpp__