id3tag.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926
  1. /*
  2. * id3tag.c -- Write ID3 version 1 and 2 tags.
  3. *
  4. * Copyright (C) 2000 Don Melton
  5. * Copyright (C) 2011-2017 Robert Hegemann
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Library General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  20. */
  21. /*
  22. * HISTORY: This source file is part of LAME (see http://www.mp3dev.org)
  23. * and was originally adapted by Conrad Sanderson <c.sanderson@me.gu.edu.au>
  24. * from mp3info by Ricardo Cerqueira <rmc@rccn.net> to write only ID3 version 1
  25. * tags. Don Melton <don@blivet.com> COMPLETELY rewrote it to support version
  26. * 2 tags and be more conformant to other standards while remaining flexible.
  27. *
  28. * NOTE: See http://id3.org/ for more information about ID3 tag formats.
  29. */
  30. /* $Id$ */
  31. #ifdef HAVE_CONFIG_H
  32. #include <config.h>
  33. #endif
  34. #ifdef STDC_HEADERS
  35. # include <stddef.h>
  36. # include <stdlib.h>
  37. # include <string.h>
  38. # include <ctype.h>
  39. #else
  40. # ifndef HAVE_STRCHR
  41. # define strchr index
  42. # define strrchr rindex
  43. # endif
  44. char *strchr(), *strrchr();
  45. # ifndef HAVE_MEMCPY
  46. # define memcpy(d, s, n) bcopy ((s), (d), (n))
  47. # endif
  48. #endif
  49. #include "lame.h"
  50. #include "machine.h"
  51. #include "encoder.h"
  52. #include "id3tag.h"
  53. #include "lame_global_flags.h"
  54. #include "util.h"
  55. #include "bitstream.h"
  56. static const char *const genre_names[] = {
  57. /*
  58. * NOTE: The spelling of these genre names is identical to those found in
  59. * Winamp and mp3info.
  60. */
  61. "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
  62. "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
  63. "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
  64. "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
  65. "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
  66. "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock",
  67. "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
  68. "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
  69. "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
  70. "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
  71. "Native US", "Cabaret", "New Wave", "Psychedelic", "Rave",
  72. "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
  73. "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
  74. "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin",
  75. "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
  76. "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
  77. "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
  78. "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
  79. "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
  80. "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
  81. "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall",
  82. "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
  83. "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta",
  84. "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
  85. "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
  86. "SynthPop"
  87. };
  88. #define GENRE_NAME_COUNT \
  89. ((int)(sizeof genre_names / sizeof (const char *const)))
  90. static const int genre_alpha_map[] = {
  91. 123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0,
  92. 107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2,
  93. 139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84,
  94. 80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35,
  95. 100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64,
  96. 133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92,
  97. 67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21,
  98. 111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130,
  99. 144, 60, 70, 31, 72, 27, 28
  100. };
  101. #define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int)))
  102. #define GENRE_INDEX_OTHER 12
  103. #define FRAME_ID(a, b, c, d) \
  104. ( ((unsigned long)(a) << 24) \
  105. | ((unsigned long)(b) << 16) \
  106. | ((unsigned long)(c) << 8) \
  107. | ((unsigned long)(d) << 0) )
  108. typedef enum UsualStringIDs { ID_TITLE = FRAME_ID('T', 'I', 'T', '2')
  109. , ID_ARTIST = FRAME_ID('T', 'P', 'E', '1')
  110. , ID_ALBUM = FRAME_ID('T', 'A', 'L', 'B')
  111. , ID_GENRE = FRAME_ID('T', 'C', 'O', 'N')
  112. , ID_ENCODER = FRAME_ID('T', 'S', 'S', 'E')
  113. , ID_PLAYLENGTH = FRAME_ID('T', 'L', 'E', 'N')
  114. , ID_COMMENT = FRAME_ID('C', 'O', 'M', 'M') /* full text string */
  115. } UsualStringIDs;
  116. typedef enum NumericStringIDs { ID_DATE = FRAME_ID('T', 'D', 'A', 'T') /* "ddMM" */
  117. , ID_TIME = FRAME_ID('T', 'I', 'M', 'E') /* "hhmm" */
  118. , ID_TPOS = FRAME_ID('T', 'P', 'O', 'S') /* '0'-'9' and '/' allowed */
  119. , ID_TRACK = FRAME_ID('T', 'R', 'C', 'K') /* '0'-'9' and '/' allowed */
  120. , ID_YEAR = FRAME_ID('T', 'Y', 'E', 'R') /* "yyyy" */
  121. } NumericStringIDs;
  122. typedef enum MiscIDs { ID_TXXX = FRAME_ID('T', 'X', 'X', 'X')
  123. , ID_WXXX = FRAME_ID('W', 'X', 'X', 'X')
  124. , ID_SYLT = FRAME_ID('S', 'Y', 'L', 'T')
  125. , ID_APIC = FRAME_ID('A', 'P', 'I', 'C')
  126. , ID_GEOB = FRAME_ID('G', 'E', 'O', 'B')
  127. , ID_PCNT = FRAME_ID('P', 'C', 'N', 'T')
  128. , ID_AENC = FRAME_ID('A', 'E', 'N', 'C')
  129. , ID_LINK = FRAME_ID('L', 'I', 'N', 'K')
  130. , ID_ENCR = FRAME_ID('E', 'N', 'C', 'R')
  131. , ID_GRID = FRAME_ID('G', 'R', 'I', 'D')
  132. , ID_PRIV = FRAME_ID('P', 'R', 'I', 'V')
  133. , ID_USLT = FRAME_ID('U', 'S', 'L', 'T') /* full text string */
  134. , ID_USER = FRAME_ID('U', 'S', 'E', 'R') /* full text string */
  135. , ID_PCST = FRAME_ID('P', 'C', 'S', 'T') /* iTunes Podcast indicator, only presence important */
  136. , ID_WFED = FRAME_ID('W', 'F', 'E', 'D') /* iTunes Podcast URL as TEXT FRAME !!! violates standard */
  137. } MiscIDs;
  138. static int
  139. frame_id_matches(int id, int mask)
  140. {
  141. int result = 0, i, window = 0xff;
  142. for (i = 0; i < 4; ++i, window <<= 8) {
  143. int const mw = (mask & window);
  144. int const iw = (id & window);
  145. if (mw != 0 && mw != iw) {
  146. result |= iw;
  147. }
  148. }
  149. return result;
  150. }
  151. static int
  152. isFrameIdMatching(int id, int mask)
  153. {
  154. return frame_id_matches(id, mask) == 0 ? 1 : 0;
  155. }
  156. static int
  157. test_tag_spec_flags(lame_internal_flags const *gfc, unsigned int tst)
  158. {
  159. return (gfc->tag_spec.flags & tst) != 0u ? 1 : 0;
  160. }
  161. #if 0
  162. static void
  163. debug_tag_spec_flags(lame_internal_flags * gfc, const char* info)
  164. {
  165. MSGF(gfc, "%s\n", info);
  166. MSGF(gfc, "CHANGED_FLAG : %d\n", test_tag_spec_flags(gfc, CHANGED_FLAG ));
  167. MSGF(gfc, "ADD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, ADD_V2_FLAG ));
  168. MSGF(gfc, "V1_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V1_ONLY_FLAG ));
  169. MSGF(gfc, "V2_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V2_ONLY_FLAG ));
  170. MSGF(gfc, "SPACE_V1_FLAG : %d\n", test_tag_spec_flags(gfc, SPACE_V1_FLAG));
  171. MSGF(gfc, "PAD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, PAD_V2_FLAG ));
  172. }
  173. #endif
  174. static int
  175. is_lame_internal_flags_null(lame_t gfp)
  176. {
  177. return (gfp && gfp->internal_flags) ? 0 : 1;
  178. }
  179. static int
  180. id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text);
  181. static int
  182. id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text);
  183. static void
  184. copyV1ToV2(lame_t gfp, int frame_id, char const *s)
  185. {
  186. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  187. if (gfc != 0) {
  188. unsigned int flags = gfc->tag_spec.flags;
  189. id3v2_add_latin1_lng(gfp, frame_id, 0, s);
  190. gfc->tag_spec.flags = flags;
  191. #if 0
  192. debug_tag_spec_flags(gfc, "copyV1ToV2");
  193. #endif
  194. }
  195. }
  196. static void
  197. id3v2AddLameVersion(lame_t gfp)
  198. {
  199. char buffer[1024];
  200. const char *b = get_lame_os_bitness();
  201. const char *v = get_lame_version();
  202. const char *u = get_lame_url();
  203. const size_t lenb = strlen(b);
  204. if (lenb > 0) {
  205. sprintf(buffer, "LAME %s version %s (%s)", b, v, u);
  206. }
  207. else {
  208. sprintf(buffer, "LAME version %s (%s)", v, u);
  209. }
  210. copyV1ToV2(gfp, ID_ENCODER, buffer);
  211. }
  212. static void
  213. id3v2AddAudioDuration(lame_t gfp, double ms)
  214. {
  215. SessionConfig_t const *const cfg = &gfp->internal_flags->cfg; /* caller checked pointers */
  216. char buffer[1024];
  217. double const max_ulong = MAX_U_32_NUM;
  218. unsigned long playlength_ms;
  219. ms *= 1000;
  220. ms /= cfg->samplerate_in;
  221. if (ms > max_ulong) {
  222. playlength_ms = max_ulong;
  223. }
  224. else if (ms < 0) {
  225. playlength_ms = 0;
  226. }
  227. else {
  228. playlength_ms = ms;
  229. }
  230. sprintf(buffer, "%lu", playlength_ms);
  231. copyV1ToV2(gfp, ID_PLAYLENGTH, buffer);
  232. }
  233. void
  234. id3tag_genre_list(void (*handler) (int, const char *, void *), void *cookie)
  235. {
  236. if (handler) {
  237. int i;
  238. for (i = 0; i < GENRE_NAME_COUNT; ++i) {
  239. if (i < GENRE_ALPHA_COUNT) {
  240. int j = genre_alpha_map[i];
  241. handler(j, genre_names[j], cookie);
  242. }
  243. }
  244. }
  245. }
  246. #define GENRE_NUM_UNKNOWN 255
  247. void
  248. id3tag_init(lame_t gfp)
  249. {
  250. lame_internal_flags *gfc = 0;
  251. if (is_lame_internal_flags_null(gfp)) {
  252. return;
  253. }
  254. gfc = gfp->internal_flags;
  255. free_id3tag(gfc);
  256. memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec);
  257. gfc->tag_spec.genre_id3v1 = GENRE_NUM_UNKNOWN;
  258. gfc->tag_spec.padding_size = 128;
  259. id3v2AddLameVersion(gfp);
  260. }
  261. void
  262. id3tag_add_v2(lame_t gfp)
  263. {
  264. lame_internal_flags *gfc = 0;
  265. if (is_lame_internal_flags_null(gfp)) {
  266. return;
  267. }
  268. gfc = gfp->internal_flags;
  269. gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
  270. gfc->tag_spec.flags |= ADD_V2_FLAG;
  271. }
  272. void
  273. id3tag_v1_only(lame_t gfp)
  274. {
  275. lame_internal_flags *gfc = 0;
  276. if (is_lame_internal_flags_null(gfp)) {
  277. return;
  278. }
  279. gfc = gfp->internal_flags;
  280. gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG);
  281. gfc->tag_spec.flags |= V1_ONLY_FLAG;
  282. }
  283. void
  284. id3tag_v2_only(lame_t gfp)
  285. {
  286. lame_internal_flags *gfc = 0;
  287. if (is_lame_internal_flags_null(gfp)) {
  288. return;
  289. }
  290. gfc = gfp->internal_flags;
  291. gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
  292. gfc->tag_spec.flags |= V2_ONLY_FLAG;
  293. }
  294. void
  295. id3tag_space_v1(lame_t gfp)
  296. {
  297. lame_internal_flags *gfc = 0;
  298. if (is_lame_internal_flags_null(gfp)) {
  299. return;
  300. }
  301. gfc = gfp->internal_flags;
  302. gfc->tag_spec.flags &= ~V2_ONLY_FLAG;
  303. gfc->tag_spec.flags |= SPACE_V1_FLAG;
  304. }
  305. void
  306. id3tag_pad_v2(lame_t gfp)
  307. {
  308. id3tag_set_pad(gfp, 128);
  309. }
  310. void
  311. id3tag_set_pad(lame_t gfp, size_t n)
  312. {
  313. lame_internal_flags *gfc = 0;
  314. if (is_lame_internal_flags_null(gfp)) {
  315. return;
  316. }
  317. gfc = gfp->internal_flags;
  318. gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
  319. gfc->tag_spec.flags |= PAD_V2_FLAG;
  320. gfc->tag_spec.flags |= ADD_V2_FLAG;
  321. gfc->tag_spec.padding_size = (unsigned int)n;
  322. }
  323. static int
  324. hasUcs2ByteOrderMarker(unsigned short bom)
  325. {
  326. if (bom == 0xFFFEu || bom == 0xFEFFu) {
  327. return 1;
  328. }
  329. return 0;
  330. }
  331. static unsigned short
  332. swap_bytes(unsigned short w)
  333. {
  334. return (0xff00u & (w << 8)) | (0x00ffu & (w >> 8));
  335. }
  336. static unsigned short
  337. toLittleEndian(unsigned short bom, unsigned short c)
  338. {
  339. if (bom == 0xFFFEu) {
  340. return swap_bytes(c);
  341. }
  342. return c;
  343. }
  344. static unsigned short
  345. fromLatin1Char(const unsigned short* s, unsigned short c)
  346. {
  347. if (s[0] == 0xFFFEu) {
  348. return swap_bytes(c);
  349. }
  350. return c;
  351. }
  352. static size_t
  353. local_strdup(char **dst, const char *src)
  354. {
  355. if (dst == 0) {
  356. return 0;
  357. }
  358. free(*dst);
  359. *dst = 0;
  360. if (src != 0) {
  361. size_t n;
  362. for (n = 0; src[n] != 0; ++n) { /* calc src string length */
  363. }
  364. if (n > 0) { /* string length without zero termination */
  365. assert(sizeof(*src) == sizeof(**dst));
  366. *dst = lame_calloc(char, n + 1);
  367. if (*dst != 0) {
  368. memcpy(*dst, src, n * sizeof(**dst));
  369. (*dst)[n] = 0;
  370. return n;
  371. }
  372. }
  373. }
  374. return 0;
  375. }
  376. static size_t
  377. local_ucs2_strdup(unsigned short **dst, unsigned short const *src)
  378. {
  379. if (dst == 0) {
  380. return 0;
  381. }
  382. free(*dst); /* free old string pointer */
  383. *dst = 0;
  384. if (src != 0) {
  385. size_t n;
  386. for (n = 0; src[n] != 0; ++n) { /* calc src string length */
  387. }
  388. if (n > 0) { /* string length without zero termination */
  389. assert(sizeof(*src) >= 2);
  390. assert(sizeof(*src) == sizeof(**dst));
  391. *dst = lame_calloc(unsigned short, n + 1);
  392. if (*dst != 0) {
  393. memcpy(*dst, src, n * sizeof(**dst));
  394. (*dst)[n] = 0;
  395. return n;
  396. }
  397. }
  398. }
  399. return 0;
  400. }
  401. static size_t
  402. local_ucs2_strlen(unsigned short const *s)
  403. {
  404. size_t n = 0;
  405. if (s != 0) {
  406. while (*s++) {
  407. ++n;
  408. }
  409. }
  410. return n;
  411. }
  412. static size_t
  413. local_ucs2_substr(unsigned short** dst, unsigned short const* src, size_t start, size_t end)
  414. {
  415. size_t const len = 1 + 1 + ((start < end) ? (end - start) : 0);
  416. size_t n = 0;
  417. unsigned short *ptr = lame_calloc(unsigned short, len);
  418. *dst = ptr;
  419. if (ptr == 0 || src == 0) {
  420. return 0;
  421. }
  422. if (hasUcs2ByteOrderMarker(src[0])) {
  423. ptr[n++] = src[0];
  424. if (start == 0) {
  425. ++start;
  426. }
  427. }
  428. while (start < end) {
  429. ptr[n++] = src[start++];
  430. }
  431. ptr[n] = 0;
  432. return n;
  433. }
  434. static int
  435. local_ucs2_pos(unsigned short const* str, unsigned short c)
  436. {
  437. int i;
  438. for (i = 0; str != 0 && str[i] != 0; ++i) {
  439. if (str[i] == c) {
  440. return i;
  441. }
  442. }
  443. return -1;
  444. }
  445. static int
  446. local_char_pos(char const* str, char c)
  447. {
  448. int i;
  449. for (i = 0; str != 0 && str[i] != 0; ++i) {
  450. if (str[i] == c) {
  451. return i;
  452. }
  453. }
  454. return -1;
  455. }
  456. static int
  457. maybeLatin1(unsigned short const* text)
  458. {
  459. if (text) {
  460. unsigned short bom = *text++;
  461. while (*text) {
  462. unsigned short c = toLittleEndian(bom, *text++);
  463. if (c > 0x00fe) return 0;
  464. }
  465. }
  466. return 1;
  467. }
  468. static int searchGenre(char const* genre);
  469. static int sloppySearchGenre(char const* genre);
  470. static int
  471. lookupGenre(char const* genre)
  472. {
  473. char *str;
  474. int num = strtol(genre, &str, 10);
  475. /* is the input a string or a valid number? */
  476. if (*str) {
  477. num = searchGenre(genre);
  478. if (num == GENRE_NAME_COUNT) {
  479. num = sloppySearchGenre(genre);
  480. }
  481. if (num == GENRE_NAME_COUNT) {
  482. return -2; /* no common genre text found */
  483. }
  484. }
  485. else {
  486. if ((num < 0) || (num >= GENRE_NAME_COUNT)) {
  487. return -1; /* number unknown */
  488. }
  489. }
  490. return num;
  491. }
  492. static unsigned char *
  493. writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n);
  494. static char*
  495. local_strdup_utf16_to_latin1(unsigned short const* utf16)
  496. {
  497. size_t len = local_ucs2_strlen(utf16);
  498. unsigned char* latin1 = lame_calloc(unsigned char, len+1);
  499. writeLoBytes(latin1, utf16, len);
  500. return (char*)latin1;
  501. }
  502. static int
  503. id3tag_set_genre_utf16(lame_t gfp, unsigned short const* text)
  504. {
  505. lame_internal_flags* gfc = gfp->internal_flags;
  506. int ret;
  507. if (text == 0) {
  508. return -3;
  509. }
  510. if (!hasUcs2ByteOrderMarker(text[0])) {
  511. return -3;
  512. }
  513. if (maybeLatin1(text)) {
  514. char* latin1 = local_strdup_utf16_to_latin1(text);
  515. int num = lookupGenre(latin1);
  516. free(latin1);
  517. if (num == -1) return -1; /* number out of range */
  518. if (num >= 0) { /* common genre found */
  519. gfc->tag_spec.flags |= CHANGED_FLAG;
  520. gfc->tag_spec.genre_id3v1 = num;
  521. copyV1ToV2(gfp, ID_GENRE, genre_names[num]);
  522. return 0;
  523. }
  524. }
  525. ret = id3v2_add_ucs2_lng(gfp, ID_GENRE, 0, text);
  526. if (ret == 0) {
  527. gfc->tag_spec.flags |= CHANGED_FLAG;
  528. gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER;
  529. }
  530. return ret;
  531. }
  532. /*
  533. Some existing options for ID3 tag can be specified by --tv option
  534. as follows.
  535. --tt <value>, --tv TIT2=value
  536. --ta <value>, --tv TPE1=value
  537. --tl <value>, --tv TALB=value
  538. --ty <value>, --tv TYER=value
  539. --tn <value>, --tv TRCK=value
  540. --tg <value>, --tv TCON=value
  541. (although some are not exactly same)*/
  542. int
  543. id3tag_set_albumart(lame_t gfp, const char *image, size_t size)
  544. {
  545. int mimetype = MIMETYPE_NONE;
  546. lame_internal_flags *gfc = 0;
  547. if (is_lame_internal_flags_null(gfp)) {
  548. return 0;
  549. }
  550. gfc = gfp->internal_flags;
  551. if (image != 0) {
  552. unsigned char const *data = (unsigned char const *) image;
  553. /* determine MIME type from the actual image data */
  554. if (2 < size && data[0] == 0xFF && data[1] == 0xD8) {
  555. mimetype = MIMETYPE_JPEG;
  556. }
  557. else if (4 < size && data[0] == 0x89 && strncmp((const char *) &data[1], "PNG", 3) == 0) {
  558. mimetype = MIMETYPE_PNG;
  559. }
  560. else if (4 < size && strncmp((const char *) data, "GIF8", 4) == 0) {
  561. mimetype = MIMETYPE_GIF;
  562. }
  563. else {
  564. return -1;
  565. }
  566. }
  567. if (gfc->tag_spec.albumart != 0) {
  568. free(gfc->tag_spec.albumart);
  569. gfc->tag_spec.albumart = 0;
  570. gfc->tag_spec.albumart_size = 0;
  571. gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE;
  572. }
  573. if (size < 1 || mimetype == MIMETYPE_NONE) {
  574. return 0;
  575. }
  576. gfc->tag_spec.albumart = lame_calloc(unsigned char, size);
  577. if (gfc->tag_spec.albumart != 0) {
  578. memcpy(gfc->tag_spec.albumart, image, size);
  579. gfc->tag_spec.albumart_size = (unsigned int)size;
  580. gfc->tag_spec.albumart_mimetype = mimetype;
  581. gfc->tag_spec.flags |= CHANGED_FLAG;
  582. id3tag_add_v2(gfp);
  583. }
  584. return 0;
  585. }
  586. static unsigned char *
  587. set_4_byte_value(unsigned char *bytes, uint32_t value)
  588. {
  589. int i;
  590. for (i = 3; i >= 0; --i) {
  591. bytes[i] = value & 0xffUL;
  592. value >>= 8;
  593. }
  594. return bytes + 4;
  595. }
  596. static uint32_t
  597. toID3v2TagId(char const *s)
  598. {
  599. unsigned int i, x = 0;
  600. if (s == 0) {
  601. return 0;
  602. }
  603. for (i = 0; i < 4 && s[i] != 0; ++i) {
  604. char const c = s[i];
  605. unsigned int const u = 0x0ff & c;
  606. x <<= 8;
  607. x |= u;
  608. if (c < 'A' || 'Z' < c) {
  609. if (c < '0' || '9' < c) {
  610. return 0;
  611. }
  612. }
  613. }
  614. return x;
  615. }
  616. static uint32_t
  617. toID3v2TagId_ucs2(unsigned short const *s)
  618. {
  619. unsigned int i, x = 0;
  620. unsigned short bom = 0;
  621. if (s == 0) {
  622. return 0;
  623. }
  624. bom = s[0];
  625. if (hasUcs2ByteOrderMarker(bom)) {
  626. ++s;
  627. }
  628. for (i = 0; i < 4 && s[i] != 0; ++i) {
  629. unsigned short const c = toLittleEndian(bom, s[i]);
  630. if (c < 'A' || 'Z' < c) {
  631. if (c < '0' || '9' < c) {
  632. return 0;
  633. }
  634. }
  635. x <<= 8;
  636. x |= c;
  637. }
  638. return x;
  639. }
  640. #if 0
  641. static int
  642. isNumericString(uint32_t frame_id)
  643. {
  644. switch (frame_id) {
  645. case ID_DATE:
  646. case ID_TIME:
  647. case ID_TPOS:
  648. case ID_TRACK:
  649. case ID_YEAR:
  650. return 1;
  651. }
  652. return 0;
  653. }
  654. #endif
  655. static int
  656. isMultiFrame(uint32_t frame_id)
  657. {
  658. switch (frame_id) {
  659. case ID_TXXX:
  660. case ID_WXXX:
  661. case ID_COMMENT:
  662. case ID_SYLT:
  663. case ID_APIC:
  664. case ID_GEOB:
  665. case ID_PCNT:
  666. case ID_AENC:
  667. case ID_LINK:
  668. case ID_ENCR:
  669. case ID_GRID:
  670. case ID_PRIV:
  671. return 1;
  672. }
  673. return 0;
  674. }
  675. #if 0
  676. static int
  677. isFullTextString(int frame_id)
  678. {
  679. switch (frame_id) {
  680. case ID_VSLT:
  681. case ID_COMMENT:
  682. return 1;
  683. }
  684. return 0;
  685. }
  686. #endif
  687. static FrameDataNode *
  688. findNode(id3tag_spec const *tag, uint32_t frame_id, FrameDataNode const *last)
  689. {
  690. FrameDataNode *node = last ? last->nxt : tag->v2_head;
  691. while (node != 0) {
  692. if (node->fid == frame_id) {
  693. return node;
  694. }
  695. node = node->nxt;
  696. }
  697. return 0;
  698. }
  699. static void
  700. appendNode(id3tag_spec * tag, FrameDataNode * node)
  701. {
  702. if (tag->v2_tail == 0 || tag->v2_head == 0) {
  703. tag->v2_head = node;
  704. tag->v2_tail = node;
  705. }
  706. else {
  707. tag->v2_tail->nxt = node;
  708. tag->v2_tail = node;
  709. }
  710. }
  711. static void
  712. setLang(char *dst, char const *src)
  713. {
  714. int i;
  715. if (src == 0 || src[0] == 0) {
  716. dst[0] = 'e';
  717. dst[1] = 'n';
  718. dst[2] = 'g';
  719. }
  720. else {
  721. for (i = 0; i < 3 && src && *src; ++i) {
  722. dst[i] = src[i];
  723. }
  724. for (; i < 3; ++i) {
  725. dst[i] = ' ';
  726. }
  727. }
  728. }
  729. static int
  730. isSameLang(char const *l1, char const *l2)
  731. {
  732. char d[3];
  733. int i;
  734. setLang(d, l2);
  735. for (i = 0; i < 3; ++i) {
  736. char a = tolower(l1[i]);
  737. char b = tolower(d[i]);
  738. if (a < ' ')
  739. a = ' ';
  740. if (b < ' ')
  741. b = ' ';
  742. if (a != b) {
  743. return 0;
  744. }
  745. }
  746. return 1;
  747. }
  748. static int
  749. isSameDescriptor(FrameDataNode const *node, char const *dsc)
  750. {
  751. size_t i;
  752. if (node->dsc.enc == 1 && node->dsc.dim > 0) {
  753. return 0;
  754. }
  755. for (i = 0; i < node->dsc.dim; ++i) {
  756. if (!dsc || node->dsc.ptr.l[i] != dsc[i]) {
  757. return 0;
  758. }
  759. }
  760. return 1;
  761. }
  762. static int
  763. isSameDescriptorUcs2(FrameDataNode const *node, unsigned short const *dsc)
  764. {
  765. size_t i;
  766. if (node->dsc.enc != 1 && node->dsc.dim > 0) {
  767. return 0;
  768. }
  769. for (i = 0; i < node->dsc.dim; ++i) {
  770. if (!dsc || node->dsc.ptr.u[i] != dsc[i]) {
  771. return 0;
  772. }
  773. }
  774. return 1;
  775. }
  776. static int
  777. id3v2_add_ucs2(lame_t gfp, uint32_t frame_id, char const *lng, unsigned short const *desc, unsigned short const *text)
  778. {
  779. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  780. if (gfc != 0) {
  781. FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0);
  782. char lang[4];
  783. setLang(lang, lng);
  784. if (isMultiFrame(frame_id)) {
  785. while (node) {
  786. if (isSameLang(node->lng, lang)) {
  787. if (isSameDescriptorUcs2(node, desc)) {
  788. break;
  789. }
  790. }
  791. node = findNode(&gfc->tag_spec, frame_id, node);
  792. }
  793. }
  794. if (node == 0) {
  795. node = lame_calloc(FrameDataNode, 1);
  796. if (node == 0) {
  797. return -254; /* memory problem */
  798. }
  799. appendNode(&gfc->tag_spec, node);
  800. }
  801. node->fid = frame_id;
  802. setLang(node->lng, lang);
  803. node->dsc.dim = local_ucs2_strdup(&node->dsc.ptr.u, desc);
  804. node->dsc.enc = 1;
  805. node->txt.dim = local_ucs2_strdup(&node->txt.ptr.u, text);
  806. node->txt.enc = 1;
  807. gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
  808. return 0;
  809. }
  810. return -255;
  811. }
  812. static int
  813. id3v2_add_latin1(lame_t gfp, uint32_t frame_id, char const *lng, char const *desc, char const *text)
  814. {
  815. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  816. if (gfc != 0) {
  817. FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0);
  818. char lang[4];
  819. setLang(lang, lng);
  820. if (isMultiFrame(frame_id)) {
  821. while (node) {
  822. if (isSameLang(node->lng, lang)) {
  823. if (isSameDescriptor(node, desc)) {
  824. break;
  825. }
  826. }
  827. node = findNode(&gfc->tag_spec, frame_id, node);
  828. }
  829. }
  830. if (node == 0) {
  831. node = lame_calloc(FrameDataNode, 1);
  832. if (node == 0) {
  833. return -254; /* memory problem */
  834. }
  835. appendNode(&gfc->tag_spec, node);
  836. }
  837. node->fid = frame_id;
  838. setLang(node->lng, lang);
  839. node->dsc.dim = local_strdup(&node->dsc.ptr.l, desc);
  840. node->dsc.enc = 0;
  841. node->txt.dim = local_strdup(&node->txt.ptr.l, text);
  842. node->txt.enc = 0;
  843. gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
  844. return 0;
  845. }
  846. return -255;
  847. }
  848. static char const*
  849. id3v2_get_language(lame_t gfp)
  850. {
  851. lame_internal_flags const* gfc = gfp ? gfp->internal_flags : 0;
  852. if (gfc) return gfc->tag_spec.language;
  853. return 0;
  854. }
  855. static int
  856. id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text)
  857. {
  858. char const* lang = id3v2_get_language(gfp);
  859. return id3v2_add_ucs2(gfp, frame_id, lang, desc, text);
  860. }
  861. static int
  862. id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text)
  863. {
  864. char const* lang = id3v2_get_language(gfp);
  865. return id3v2_add_latin1(gfp, frame_id, lang, desc, text);
  866. }
  867. static int
  868. id3tag_set_userinfo_latin1(lame_t gfp, uint32_t id, char const *fieldvalue)
  869. {
  870. char const separator = '=';
  871. int rc = -7;
  872. int a = local_char_pos(fieldvalue, separator);
  873. if (a >= 0) {
  874. char* dup = 0;
  875. local_strdup(&dup, fieldvalue);
  876. dup[a] = 0;
  877. rc = id3v2_add_latin1_lng(gfp, id, dup, dup+a+1);
  878. free(dup);
  879. }
  880. return rc;
  881. }
  882. static int
  883. id3tag_set_userinfo_ucs2(lame_t gfp, uint32_t id, unsigned short const *fieldvalue)
  884. {
  885. unsigned short const separator = fromLatin1Char(fieldvalue,'=');
  886. int rc = -7;
  887. size_t b = local_ucs2_strlen(fieldvalue);
  888. int a = local_ucs2_pos(fieldvalue, separator);
  889. if (a >= 0) {
  890. unsigned short* dsc = 0, *val = 0;
  891. local_ucs2_substr(&dsc, fieldvalue, 0, a);
  892. local_ucs2_substr(&val, fieldvalue, a+1, b);
  893. rc = id3v2_add_ucs2_lng(gfp, id, dsc, val);
  894. free(dsc);
  895. free(val);
  896. }
  897. return rc;
  898. }
  899. int
  900. id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text)
  901. {
  902. uint32_t const frame_id = toID3v2TagId(id);
  903. if (frame_id == 0) {
  904. return -1;
  905. }
  906. if (is_lame_internal_flags_null(gfp)) {
  907. return 0;
  908. }
  909. if (text == 0) {
  910. return 0;
  911. }
  912. if (!hasUcs2ByteOrderMarker(text[0])) {
  913. return -3; /* BOM missing */
  914. }
  915. if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) {
  916. return id3tag_set_userinfo_ucs2(gfp, frame_id, text);
  917. }
  918. if (frame_id == ID_GENRE) {
  919. return id3tag_set_genre_utf16(gfp, text);
  920. }
  921. if (frame_id == ID_PCST) {
  922. return id3v2_add_ucs2_lng(gfp, frame_id, 0, text);
  923. }
  924. if (frame_id == ID_USER) {
  925. return id3v2_add_ucs2_lng(gfp, frame_id, text, 0);
  926. }
  927. if (frame_id == ID_WFED) {
  928. return id3v2_add_ucs2_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */
  929. }
  930. if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0))
  931. ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) {
  932. #if 0
  933. if (isNumericString(frame_id)) {
  934. return -2; /* must be Latin-1 encoded */
  935. }
  936. #endif
  937. return id3v2_add_ucs2_lng(gfp, frame_id, 0, text);
  938. }
  939. return -255; /* not supported by now */
  940. }
  941. extern int
  942. id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text);
  943. int
  944. id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text)
  945. {
  946. return id3tag_set_textinfo_utf16(gfp, id, text);
  947. }
  948. int
  949. id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text)
  950. {
  951. uint32_t const frame_id = toID3v2TagId(id);
  952. if (frame_id == 0) {
  953. return -1;
  954. }
  955. if (is_lame_internal_flags_null(gfp)) {
  956. return 0;
  957. }
  958. if (text == 0) {
  959. return 0;
  960. }
  961. if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) {
  962. return id3tag_set_userinfo_latin1(gfp, frame_id, text);
  963. }
  964. if (frame_id == ID_GENRE) {
  965. return id3tag_set_genre(gfp, text);
  966. }
  967. if (frame_id == ID_PCST) {
  968. return id3v2_add_latin1_lng(gfp, frame_id, 0, text);
  969. }
  970. if (frame_id == ID_USER) {
  971. return id3v2_add_latin1_lng(gfp, frame_id, text, 0);
  972. }
  973. if (frame_id == ID_WFED) {
  974. return id3v2_add_latin1_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */
  975. }
  976. if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0))
  977. ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) {
  978. return id3v2_add_latin1_lng(gfp, frame_id, 0, text);
  979. }
  980. return -255; /* not supported by now */
  981. }
  982. int
  983. id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text)
  984. {
  985. if (is_lame_internal_flags_null(gfp)) {
  986. return 0;
  987. }
  988. return id3v2_add_latin1(gfp, ID_COMMENT, lang, desc, text);
  989. }
  990. int
  991. id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text)
  992. {
  993. if (is_lame_internal_flags_null(gfp)) {
  994. return 0;
  995. }
  996. return id3v2_add_ucs2(gfp, ID_COMMENT, lang, desc, text);
  997. }
  998. extern int
  999. id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text);
  1000. int
  1001. id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text)
  1002. {
  1003. if (is_lame_internal_flags_null(gfp)) {
  1004. return 0;
  1005. }
  1006. return id3tag_set_comment_utf16(gfp, lang, desc, text);
  1007. }
  1008. void
  1009. id3tag_set_title(lame_t gfp, const char *title)
  1010. {
  1011. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1012. if (gfc && title && *title) {
  1013. local_strdup(&gfc->tag_spec.title, title);
  1014. gfc->tag_spec.flags |= CHANGED_FLAG;
  1015. copyV1ToV2(gfp, ID_TITLE, title);
  1016. }
  1017. }
  1018. void
  1019. id3tag_set_artist(lame_t gfp, const char *artist)
  1020. {
  1021. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1022. if (gfc && artist && *artist) {
  1023. local_strdup(&gfc->tag_spec.artist, artist);
  1024. gfc->tag_spec.flags |= CHANGED_FLAG;
  1025. copyV1ToV2(gfp, ID_ARTIST, artist);
  1026. }
  1027. }
  1028. void
  1029. id3tag_set_album(lame_t gfp, const char *album)
  1030. {
  1031. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1032. if (gfc && album && *album) {
  1033. local_strdup(&gfc->tag_spec.album, album);
  1034. gfc->tag_spec.flags |= CHANGED_FLAG;
  1035. copyV1ToV2(gfp, ID_ALBUM, album);
  1036. }
  1037. }
  1038. void
  1039. id3tag_set_year(lame_t gfp, const char *year)
  1040. {
  1041. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1042. if (gfc && year && *year) {
  1043. int num = atoi(year);
  1044. if (num < 0) {
  1045. num = 0;
  1046. }
  1047. /* limit a year to 4 digits so it fits in a version 1 tag */
  1048. if (num > 9999) {
  1049. num = 9999;
  1050. }
  1051. if (num) {
  1052. gfc->tag_spec.year = num;
  1053. gfc->tag_spec.flags |= CHANGED_FLAG;
  1054. }
  1055. copyV1ToV2(gfp, ID_YEAR, year);
  1056. }
  1057. }
  1058. void
  1059. id3tag_set_comment(lame_t gfp, const char *comment)
  1060. {
  1061. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1062. if (gfc && comment && *comment) {
  1063. local_strdup(&gfc->tag_spec.comment, comment);
  1064. gfc->tag_spec.flags |= CHANGED_FLAG;
  1065. {
  1066. uint32_t const flags = gfc->tag_spec.flags;
  1067. id3v2_add_latin1_lng(gfp, ID_COMMENT, "", comment);
  1068. gfc->tag_spec.flags = flags;
  1069. }
  1070. }
  1071. }
  1072. int
  1073. id3tag_set_track(lame_t gfp, const char *track)
  1074. {
  1075. char const *trackcount;
  1076. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1077. int ret = 0;
  1078. if (gfc && track && *track) {
  1079. int num = atoi(track);
  1080. /* check for valid ID3v1 track number range */
  1081. if (num < 1 || num > 255) {
  1082. num = 0;
  1083. ret = -1; /* track number out of ID3v1 range, ignored for ID3v1 */
  1084. gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
  1085. }
  1086. if (num) {
  1087. gfc->tag_spec.track_id3v1 = num;
  1088. gfc->tag_spec.flags |= CHANGED_FLAG;
  1089. }
  1090. /* Look for the total track count after a "/", same restrictions */
  1091. trackcount = strchr(track, '/');
  1092. if (trackcount && *trackcount) {
  1093. gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
  1094. }
  1095. copyV1ToV2(gfp, ID_TRACK, track);
  1096. }
  1097. return ret;
  1098. }
  1099. /* would use real "strcasecmp" but it isn't portable */
  1100. static int
  1101. local_strcasecmp(const char *s1, const char *s2)
  1102. {
  1103. unsigned char c1;
  1104. unsigned char c2;
  1105. do {
  1106. c1 = tolower(*s1);
  1107. c2 = tolower(*s2);
  1108. if (!c1) {
  1109. break;
  1110. }
  1111. ++s1;
  1112. ++s2;
  1113. } while (c1 == c2);
  1114. return c1 - c2;
  1115. }
  1116. static
  1117. const char* nextUpperAlpha(const char* p, char x)
  1118. {
  1119. char c;
  1120. for(c = toupper(*p); *p != 0; c = toupper(*++p)) {
  1121. if ('A' <= c && c <= 'Z') {
  1122. if (c != x) {
  1123. return p;
  1124. }
  1125. }
  1126. }
  1127. return p;
  1128. }
  1129. static int
  1130. sloppyCompared(const char* p, const char* q)
  1131. {
  1132. char cp, cq;
  1133. p = nextUpperAlpha(p, 0);
  1134. q = nextUpperAlpha(q, 0);
  1135. cp = toupper(*p);
  1136. cq = toupper(*q);
  1137. while (cp == cq) {
  1138. if (cp == 0) {
  1139. return 1;
  1140. }
  1141. if (p[1] == '.') { /* some abbrevation */
  1142. while (*q && *q++ != ' ') {
  1143. }
  1144. }
  1145. p = nextUpperAlpha(p, cp);
  1146. q = nextUpperAlpha(q, cq);
  1147. cp = toupper(*p);
  1148. cq = toupper(*q);
  1149. }
  1150. return 0;
  1151. }
  1152. static int
  1153. sloppySearchGenre(const char *genre)
  1154. {
  1155. int i;
  1156. for (i = 0; i < GENRE_NAME_COUNT; ++i) {
  1157. if (sloppyCompared(genre, genre_names[i])) {
  1158. return i;
  1159. }
  1160. }
  1161. return GENRE_NAME_COUNT;
  1162. }
  1163. static int
  1164. searchGenre(const char* genre)
  1165. {
  1166. int i;
  1167. for (i = 0; i < GENRE_NAME_COUNT; ++i) {
  1168. if (!local_strcasecmp(genre, genre_names[i])) {
  1169. return i;
  1170. }
  1171. }
  1172. return GENRE_NAME_COUNT;
  1173. }
  1174. int
  1175. id3tag_set_genre(lame_t gfp, const char *genre)
  1176. {
  1177. lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
  1178. int ret = 0;
  1179. if (gfc && genre && *genre) {
  1180. int const num = lookupGenre(genre);
  1181. if (num == -1) return num;
  1182. gfc->tag_spec.flags |= CHANGED_FLAG;
  1183. if (num >= 0) {
  1184. gfc->tag_spec.genre_id3v1 = num;
  1185. genre = genre_names[num];
  1186. }
  1187. else {
  1188. gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER;
  1189. gfc->tag_spec.flags |= ADD_V2_FLAG;
  1190. }
  1191. copyV1ToV2(gfp, ID_GENRE, genre);
  1192. }
  1193. return ret;
  1194. }
  1195. static size_t
  1196. sizeOfNode(FrameDataNode const *node)
  1197. {
  1198. size_t n = 0;
  1199. if (node) {
  1200. n = 10; /* header size */
  1201. n += 1; /* text encoding flag */
  1202. switch (node->txt.enc) {
  1203. default:
  1204. case 0:
  1205. if (node->dsc.dim > 0) {
  1206. n += node->dsc.dim + 1;
  1207. }
  1208. n += node->txt.dim;
  1209. break;
  1210. case 1:
  1211. if (node->dsc.dim > 0) {
  1212. n += (node->dsc.dim+1) * 2;
  1213. }
  1214. n += node->txt.dim * 2;
  1215. break;
  1216. }
  1217. }
  1218. return n;
  1219. }
  1220. static size_t
  1221. sizeOfCommentNode(FrameDataNode const *node)
  1222. {
  1223. size_t n = 0;
  1224. if (node) {
  1225. n = 10; /* header size */
  1226. n += 1; /* text encoding flag */
  1227. n += 3; /* language */
  1228. switch (node->dsc.enc) {
  1229. default:
  1230. case 0:
  1231. n += 1 + node->dsc.dim;
  1232. break;
  1233. case 1:
  1234. n += 2 + node->dsc.dim * 2;
  1235. break;
  1236. }
  1237. switch (node->txt.enc) {
  1238. default:
  1239. case 0:
  1240. n += node->txt.dim;
  1241. break;
  1242. case 1:
  1243. n += node->txt.dim * 2;
  1244. break;
  1245. }
  1246. }
  1247. return n;
  1248. }
  1249. static size_t
  1250. sizeOfWxxxNode(FrameDataNode const *node)
  1251. {
  1252. size_t n = 0;
  1253. if (node) {
  1254. n = 10; /* header size */
  1255. if (node->dsc.dim > 0) {
  1256. n += 1; /* text encoding flag */
  1257. switch (node->dsc.enc) {
  1258. default:
  1259. case 0:
  1260. n += 1 + node->dsc.dim;
  1261. break;
  1262. case 1:
  1263. n += 2 + node->dsc.dim * 2;
  1264. break;
  1265. }
  1266. }
  1267. if (node->txt.dim > 0) {
  1268. switch (node->txt.enc) {
  1269. default:
  1270. case 0:
  1271. n += node->txt.dim;
  1272. break;
  1273. case 1:
  1274. n += node->txt.dim - 1; /* UCS2 -> Latin1, skip BOM */
  1275. break;
  1276. }
  1277. }
  1278. }
  1279. return n;
  1280. }
  1281. static unsigned char *
  1282. writeChars(unsigned char *frame, char const *str, size_t n)
  1283. {
  1284. while (n--) {
  1285. *frame++ = *str++;
  1286. }
  1287. return frame;
  1288. }
  1289. static unsigned char *
  1290. writeUcs2s(unsigned char *frame, unsigned short const *str, size_t n)
  1291. {
  1292. if (n > 0) {
  1293. unsigned short const bom = *str;
  1294. while (n--) {
  1295. unsigned short const c = toLittleEndian(bom, *str++);
  1296. *frame++ = 0x00ffu & c;
  1297. *frame++ = 0x00ffu & (c >> 8);
  1298. }
  1299. }
  1300. return frame;
  1301. }
  1302. static unsigned char *
  1303. writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n)
  1304. {
  1305. if (n > 0) {
  1306. unsigned short const bom = *str;
  1307. if (hasUcs2ByteOrderMarker(bom)) {
  1308. str++; n--; /* skip BOM */
  1309. }
  1310. while (n--) {
  1311. unsigned short const c = toLittleEndian(bom, *str++);
  1312. if (c < 0x0020u || 0x00ffu < c) {
  1313. *frame++ = 0x0020; /* blank */
  1314. }
  1315. else {
  1316. *frame++ = c;
  1317. }
  1318. }
  1319. }
  1320. return frame;
  1321. }
  1322. static unsigned char *
  1323. set_frame_comment(unsigned char *frame, FrameDataNode const *node)
  1324. {
  1325. size_t const n = sizeOfCommentNode(node);
  1326. if (n > 10) {
  1327. frame = set_4_byte_value(frame, node->fid);
  1328. frame = set_4_byte_value(frame, (uint32_t) (n - 10));
  1329. /* clear 2-byte header flags */
  1330. *frame++ = 0;
  1331. *frame++ = 0;
  1332. /* encoding descriptor byte */
  1333. *frame++ = node->txt.enc == 1 ? 1 : 0;
  1334. /* 3 bytes language */
  1335. *frame++ = node->lng[0];
  1336. *frame++ = node->lng[1];
  1337. *frame++ = node->lng[2];
  1338. /* descriptor with zero byte(s) separator */
  1339. if (node->dsc.enc != 1) {
  1340. frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim);
  1341. *frame++ = 0;
  1342. }
  1343. else {
  1344. frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim);
  1345. *frame++ = 0;
  1346. *frame++ = 0;
  1347. }
  1348. /* comment full text */
  1349. if (node->txt.enc != 1) {
  1350. frame = writeChars(frame, node->txt.ptr.l, node->txt.dim);
  1351. }
  1352. else {
  1353. frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim);
  1354. }
  1355. }
  1356. return frame;
  1357. }
  1358. static unsigned char *
  1359. set_frame_custom2(unsigned char *frame, FrameDataNode const *node)
  1360. {
  1361. size_t const n = sizeOfNode(node);
  1362. if (n > 10) {
  1363. frame = set_4_byte_value(frame, node->fid);
  1364. frame = set_4_byte_value(frame, (unsigned long) (n - 10));
  1365. /* clear 2-byte header flags */
  1366. *frame++ = 0;
  1367. *frame++ = 0;
  1368. /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
  1369. *frame++ = node->txt.enc == 1 ? 1 : 0;
  1370. if (node->dsc.dim > 0) {
  1371. if (node->dsc.enc != 1) {
  1372. frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim);
  1373. *frame++ = 0;
  1374. }
  1375. else {
  1376. frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim);
  1377. *frame++ = 0;
  1378. *frame++ = 0;
  1379. }
  1380. }
  1381. if (node->txt.enc != 1) {
  1382. frame = writeChars(frame, node->txt.ptr.l, node->txt.dim);
  1383. }
  1384. else {
  1385. frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim);
  1386. }
  1387. }
  1388. return frame;
  1389. }
  1390. static unsigned char *
  1391. set_frame_wxxx(unsigned char *frame, FrameDataNode const *node)
  1392. {
  1393. size_t const n = sizeOfWxxxNode(node);
  1394. if (n > 10) {
  1395. frame = set_4_byte_value(frame, node->fid);
  1396. frame = set_4_byte_value(frame, (unsigned long) (n - 10));
  1397. /* clear 2-byte header flags */
  1398. *frame++ = 0;
  1399. *frame++ = 0;
  1400. if (node->dsc.dim > 0) {
  1401. /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
  1402. *frame++ = node->dsc.enc == 1 ? 1 : 0;
  1403. if (node->dsc.enc != 1) {
  1404. frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim);
  1405. *frame++ = 0;
  1406. }
  1407. else {
  1408. frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim);
  1409. *frame++ = 0;
  1410. *frame++ = 0;
  1411. }
  1412. }
  1413. if (node->txt.enc != 1) {
  1414. frame = writeChars(frame, node->txt.ptr.l, node->txt.dim);
  1415. }
  1416. else {
  1417. frame = writeLoBytes(frame, node->txt.ptr.u, node->txt.dim);
  1418. }
  1419. }
  1420. return frame;
  1421. }
  1422. static unsigned char *
  1423. set_frame_apic(unsigned char *frame, const char *mimetype, const unsigned char *data, size_t size)
  1424. {
  1425. /* ID3v2.3 standard APIC frame:
  1426. * <Header for 'Attached picture', ID: "APIC">
  1427. * Text encoding $xx
  1428. * MIME type <text string> $00
  1429. * Picture type $xx
  1430. * Description <text string according to encoding> $00 (00)
  1431. * Picture data <binary data>
  1432. */
  1433. if (mimetype && data && size) {
  1434. frame = set_4_byte_value(frame, FRAME_ID('A', 'P', 'I', 'C'));
  1435. frame = set_4_byte_value(frame, (unsigned long) (4 + strlen(mimetype) + size));
  1436. /* clear 2-byte header flags */
  1437. *frame++ = 0;
  1438. *frame++ = 0;
  1439. /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
  1440. *frame++ = 0;
  1441. /* copy mime_type */
  1442. while (*mimetype) {
  1443. *frame++ = *mimetype++;
  1444. }
  1445. *frame++ = 0;
  1446. /* set picture type to 0 */
  1447. *frame++ = 0;
  1448. /* empty description field */
  1449. *frame++ = 0;
  1450. /* copy the image data */
  1451. while (size--) {
  1452. *frame++ = *data++;
  1453. }
  1454. }
  1455. return frame;
  1456. }
  1457. int
  1458. id3tag_set_fieldvalue(lame_t gfp, const char *fieldvalue)
  1459. {
  1460. if (is_lame_internal_flags_null(gfp)) {
  1461. return 0;
  1462. }
  1463. if (fieldvalue && *fieldvalue) {
  1464. if (strlen(fieldvalue) < 5 || fieldvalue[4] != '=') {
  1465. return -1;
  1466. }
  1467. return id3tag_set_textinfo_latin1(gfp, fieldvalue, &fieldvalue[5]);
  1468. }
  1469. return 0;
  1470. }
  1471. int
  1472. id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue)
  1473. {
  1474. if (is_lame_internal_flags_null(gfp)) {
  1475. return 0;
  1476. }
  1477. if (fieldvalue && *fieldvalue) {
  1478. size_t dx = hasUcs2ByteOrderMarker(fieldvalue[0]);
  1479. unsigned short const separator = fromLatin1Char(fieldvalue, '=');
  1480. char fid[5] = {0,0,0,0,0};
  1481. uint32_t const frame_id = toID3v2TagId_ucs2(fieldvalue);
  1482. if (local_ucs2_strlen(fieldvalue) < (5+dx) || fieldvalue[4+dx] != separator) {
  1483. return -1;
  1484. }
  1485. fid[0] = (frame_id >> 24) & 0x0ff;
  1486. fid[1] = (frame_id >> 16) & 0x0ff;
  1487. fid[2] = (frame_id >> 8) & 0x0ff;
  1488. fid[3] = frame_id & 0x0ff;
  1489. if (frame_id != 0) {
  1490. unsigned short* txt = 0;
  1491. int rc;
  1492. local_ucs2_substr(&txt, fieldvalue, dx+5, local_ucs2_strlen(fieldvalue));
  1493. rc = id3tag_set_textinfo_utf16(gfp, fid, txt);
  1494. free(txt);
  1495. return rc;
  1496. }
  1497. }
  1498. return -1;
  1499. }
  1500. extern int
  1501. id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue);
  1502. int
  1503. id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue)
  1504. {
  1505. if (is_lame_internal_flags_null(gfp)) {
  1506. return 0;
  1507. }
  1508. return id3tag_set_fieldvalue_utf16(gfp, fieldvalue);
  1509. }
  1510. size_t
  1511. lame_get_id3v2_tag(lame_t gfp, unsigned char *buffer, size_t size)
  1512. {
  1513. lame_internal_flags *gfc = 0;
  1514. if (is_lame_internal_flags_null(gfp)) {
  1515. return 0;
  1516. }
  1517. gfc = gfp->internal_flags;
  1518. if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) {
  1519. return 0;
  1520. }
  1521. #if 0
  1522. debug_tag_spec_flags(gfc, "lame_get_id3v2_tag");
  1523. #endif
  1524. {
  1525. int usev2 = test_tag_spec_flags(gfc, ADD_V2_FLAG | V2_ONLY_FLAG);
  1526. /* calculate length of four fields which may not fit in verion 1 tag */
  1527. size_t title_length = gfc->tag_spec.title ? strlen(gfc->tag_spec.title) : 0;
  1528. size_t artist_length = gfc->tag_spec.artist ? strlen(gfc->tag_spec.artist) : 0;
  1529. size_t album_length = gfc->tag_spec.album ? strlen(gfc->tag_spec.album) : 0;
  1530. size_t comment_length = gfc->tag_spec.comment ? strlen(gfc->tag_spec.comment) : 0;
  1531. /* write tag if explicitly requested or if fields overflow */
  1532. if ((title_length > 30)
  1533. || (artist_length > 30)
  1534. || (album_length > 30)
  1535. || (comment_length > 30)
  1536. || (gfc->tag_spec.track_id3v1 && (comment_length > 28))) {
  1537. usev2 = 1;
  1538. }
  1539. if (usev2) {
  1540. size_t tag_size;
  1541. unsigned char *p;
  1542. size_t adjusted_tag_size;
  1543. const char *albumart_mime = NULL;
  1544. static const char *mime_jpeg = "image/jpeg";
  1545. static const char *mime_png = "image/png";
  1546. static const char *mime_gif = "image/gif";
  1547. if (gfp->num_samples != MAX_U_32_NUM) {
  1548. id3v2AddAudioDuration(gfp, gfp->num_samples);
  1549. }
  1550. /* calulate size of tag starting with 10-byte tag header */
  1551. tag_size = 10;
  1552. if (gfc->tag_spec.albumart && gfc->tag_spec.albumart_size) {
  1553. switch (gfc->tag_spec.albumart_mimetype) {
  1554. case MIMETYPE_JPEG:
  1555. albumart_mime = mime_jpeg;
  1556. break;
  1557. case MIMETYPE_PNG:
  1558. albumart_mime = mime_png;
  1559. break;
  1560. case MIMETYPE_GIF:
  1561. albumart_mime = mime_gif;
  1562. break;
  1563. }
  1564. if (albumart_mime) {
  1565. tag_size += 10 + 4 + strlen(albumart_mime) + gfc->tag_spec.albumart_size;
  1566. }
  1567. }
  1568. {
  1569. id3tag_spec *tag = &gfc->tag_spec;
  1570. if (tag->v2_head != 0) {
  1571. FrameDataNode *node;
  1572. for (node = tag->v2_head; node != 0; node = node->nxt) {
  1573. if (node->fid == ID_COMMENT || node->fid == ID_USER) {
  1574. tag_size += sizeOfCommentNode(node);
  1575. }
  1576. else if (isFrameIdMatching(node->fid, FRAME_ID('W',0,0,0))) {
  1577. tag_size += sizeOfWxxxNode(node);
  1578. }
  1579. else {
  1580. tag_size += sizeOfNode(node);
  1581. }
  1582. }
  1583. }
  1584. }
  1585. if (test_tag_spec_flags(gfc, PAD_V2_FLAG)) {
  1586. /* add some bytes of padding */
  1587. tag_size += gfc->tag_spec.padding_size;
  1588. }
  1589. if (size < tag_size) {
  1590. return tag_size;
  1591. }
  1592. if (buffer == 0) {
  1593. return 0;
  1594. }
  1595. p = buffer;
  1596. /* set tag header starting with file identifier */
  1597. *p++ = 'I';
  1598. *p++ = 'D';
  1599. *p++ = '3';
  1600. /* set version number word */
  1601. *p++ = 3;
  1602. *p++ = 0;
  1603. /* clear flags byte */
  1604. *p++ = 0;
  1605. /* calculate and set tag size = total size - header size */
  1606. adjusted_tag_size = tag_size - 10;
  1607. /* encode adjusted size into four bytes where most significant
  1608. * bit is clear in each byte, for 28-bit total */
  1609. *p++ = (unsigned char) ((adjusted_tag_size >> 21) & 0x7fu);
  1610. *p++ = (unsigned char) ((adjusted_tag_size >> 14) & 0x7fu);
  1611. *p++ = (unsigned char) ((adjusted_tag_size >> 7) & 0x7fu);
  1612. *p++ = (unsigned char) (adjusted_tag_size & 0x7fu);
  1613. /*
  1614. * NOTE: The remainder of the tag (frames and padding, if any)
  1615. * are not "unsynchronized" to prevent false MPEG audio headers
  1616. * from appearing in the bitstream. Why? Well, most players
  1617. * and utilities know how to skip the ID3 version 2 tag by now
  1618. * even if they don't read its contents, and it's actually
  1619. * very unlikely that such a false "sync" pattern would occur
  1620. * in just the simple text frames added here.
  1621. */
  1622. /* set each frame in tag */
  1623. {
  1624. id3tag_spec *tag = &gfc->tag_spec;
  1625. if (tag->v2_head != 0) {
  1626. FrameDataNode *node;
  1627. for (node = tag->v2_head; node != 0; node = node->nxt) {
  1628. if (node->fid == ID_COMMENT || node->fid == ID_USER) {
  1629. p = set_frame_comment(p, node);
  1630. }
  1631. else if (isFrameIdMatching(node->fid,FRAME_ID('W',0,0,0))) {
  1632. p = set_frame_wxxx(p, node);
  1633. }
  1634. else {
  1635. p = set_frame_custom2(p, node);
  1636. }
  1637. }
  1638. }
  1639. }
  1640. if (albumart_mime) {
  1641. p = set_frame_apic(p, albumart_mime, gfc->tag_spec.albumart,
  1642. gfc->tag_spec.albumart_size);
  1643. }
  1644. /* clear any padding bytes */
  1645. memset(p, 0, tag_size - (p - buffer));
  1646. return tag_size;
  1647. }
  1648. }
  1649. return 0;
  1650. }
  1651. int
  1652. id3tag_write_v2(lame_t gfp)
  1653. {
  1654. lame_internal_flags *gfc = 0;
  1655. if (is_lame_internal_flags_null(gfp)) {
  1656. return 0;
  1657. }
  1658. gfc = gfp->internal_flags;
  1659. #if 0
  1660. debug_tag_spec_flags(gfc, "write v2");
  1661. #endif
  1662. if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) {
  1663. return 0;
  1664. }
  1665. if (test_tag_spec_flags(gfc, CHANGED_FLAG)) {
  1666. unsigned char *tag = 0;
  1667. size_t tag_size, n;
  1668. n = lame_get_id3v2_tag(gfp, 0, 0);
  1669. tag = lame_calloc(unsigned char, n);
  1670. if (tag == 0) {
  1671. return -1;
  1672. }
  1673. tag_size = lame_get_id3v2_tag(gfp, tag, n);
  1674. if (tag_size > n) {
  1675. free(tag);
  1676. return -1;
  1677. }
  1678. else {
  1679. size_t i;
  1680. /* write tag directly into bitstream at current position */
  1681. for (i = 0; i < tag_size; ++i) {
  1682. add_dummy_byte(gfc, tag[i], 1);
  1683. }
  1684. }
  1685. free(tag);
  1686. return (int) tag_size; /* ok, tag should not exceed 2GB */
  1687. }
  1688. return 0;
  1689. }
  1690. static unsigned char *
  1691. set_text_field(unsigned char *field, const char *text, size_t size, int pad)
  1692. {
  1693. while (size--) {
  1694. if (text && *text) {
  1695. *field++ = *text++;
  1696. }
  1697. else {
  1698. *field++ = pad;
  1699. }
  1700. }
  1701. return field;
  1702. }
  1703. size_t
  1704. lame_get_id3v1_tag(lame_t gfp, unsigned char *buffer, size_t size)
  1705. {
  1706. size_t const tag_size = 128;
  1707. lame_internal_flags *gfc;
  1708. if (gfp == 0) {
  1709. return 0;
  1710. }
  1711. if (size < tag_size) {
  1712. return tag_size;
  1713. }
  1714. gfc = gfp->internal_flags;
  1715. if (gfc == 0) {
  1716. return 0;
  1717. }
  1718. if (buffer == 0) {
  1719. return 0;
  1720. }
  1721. if (test_tag_spec_flags(gfc, V2_ONLY_FLAG)) {
  1722. return 0;
  1723. }
  1724. if (test_tag_spec_flags(gfc, CHANGED_FLAG)) {
  1725. unsigned char *p = buffer;
  1726. int pad = test_tag_spec_flags(gfc, SPACE_V1_FLAG) ? ' ' : 0;
  1727. char year[5];
  1728. /* set tag identifier */
  1729. *p++ = 'T';
  1730. *p++ = 'A';
  1731. *p++ = 'G';
  1732. /* set each field in tag */
  1733. p = set_text_field(p, gfc->tag_spec.title, 30, pad);
  1734. p = set_text_field(p, gfc->tag_spec.artist, 30, pad);
  1735. p = set_text_field(p, gfc->tag_spec.album, 30, pad);
  1736. sprintf(year, "%d", gfc->tag_spec.year);
  1737. p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad);
  1738. /* limit comment field to 28 bytes if a track is specified */
  1739. p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track_id3v1 ? 28 : 30, pad);
  1740. if (gfc->tag_spec.track_id3v1) {
  1741. /* clear the next byte to indicate a version 1.1 tag */
  1742. *p++ = 0;
  1743. *p++ = gfc->tag_spec.track_id3v1;
  1744. }
  1745. *p++ = gfc->tag_spec.genre_id3v1;
  1746. return tag_size;
  1747. }
  1748. return 0;
  1749. }
  1750. int
  1751. id3tag_write_v1(lame_t gfp)
  1752. {
  1753. lame_internal_flags* gfc = 0;
  1754. size_t i, n, m;
  1755. unsigned char tag[128];
  1756. if (is_lame_internal_flags_null(gfp)) {
  1757. return 0;
  1758. }
  1759. gfc = gfp->internal_flags;
  1760. m = sizeof(tag);
  1761. n = lame_get_id3v1_tag(gfp, tag, m);
  1762. if (n > m) {
  1763. return 0;
  1764. }
  1765. /* write tag directly into bitstream at current position */
  1766. for (i = 0; i < n; ++i) {
  1767. add_dummy_byte(gfc, tag[i], 1);
  1768. }
  1769. return (int) n; /* ok, tag has fixed size of 128 bytes, well below 2GB */
  1770. }