cmstypes.c 172 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440
  1. //---------------------------------------------------------------------------------
  2. //
  3. // Little Color Management System
  4. // Copyright (c) 1998-2011 Marti Maria Saguer
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining
  7. // a copy of this software and associated documentation files (the "Software"),
  8. // to deal in the Software without restriction, including without limitation
  9. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. // and/or sell copies of the Software, and to permit persons to whom the Software
  11. // is furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  18. // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //
  24. //---------------------------------------------------------------------------------
  25. //
  26. #include "lcms2_internal.h"
  27. // Tag Serialization -----------------------------------------------------------------------------
  28. // This file implements every single tag and tag type as described in the ICC spec. Some types
  29. // have been deprecated, like ncl and Data. There is no implementation for those types as there
  30. // are no profiles holding them. The programmer can also extend this list by defining his own types
  31. // by using the appropiate plug-in. There are three types of plug ins regarding that. First type
  32. // allows to define new tags using any existing type. Next plug-in type allows to define new types
  33. // and the third one is very specific: allows to extend the number of elements in the multiprofile
  34. // elements special type.
  35. //--------------------------------------------------------------------------------------------------
  36. // Some broken types
  37. #define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8)
  38. #define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
  39. // This is the linked list that keeps track of the defined types
  40. typedef struct _cmsTagTypeLinkedList_st {
  41. cmsTagTypeHandler Handler;
  42. struct _cmsTagTypeLinkedList_st* Next;
  43. } _cmsTagTypeLinkedList;
  44. // Some macros to define callbacks.
  45. #define READ_FN(x) Type_##x##_Read
  46. #define WRITE_FN(x) Type_##x##_Write
  47. #define FREE_FN(x) Type_##x##_Free
  48. #define DUP_FN(x) Type_##x##_Dup
  49. // Helper macro to define a handler. Callbacks do have a fixed naming convention.
  50. #define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 }
  51. // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
  52. #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
  53. // Register a new type handler. This routine is shared between normal types and MPE
  54. static
  55. cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
  56. {
  57. cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
  58. _cmsTagTypeLinkedList *pt, *Anterior = NULL;
  59. // Calling the function with NULL as plug-in would unregister the plug in.
  60. if (Data == NULL) {
  61. LinkedList[DefaultListCount-1].Next = NULL;
  62. return TRUE;
  63. }
  64. pt = Anterior = LinkedList;
  65. while (pt != NULL) {
  66. if (Plugin->Handler.Signature == pt -> Handler.Signature) {
  67. pt ->Handler = Plugin ->Handler; // Replace old behaviour.
  68. // Note that since no memory is allocated, unregister does not
  69. // reset this action.
  70. return TRUE;
  71. }
  72. Anterior = pt;
  73. pt = pt ->Next;
  74. }
  75. // Registering happens in plug-in memory pool
  76. pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
  77. if (pt == NULL) return FALSE;
  78. pt ->Handler = Plugin ->Handler;
  79. pt ->Next = NULL;
  80. if (Anterior)
  81. Anterior -> Next = pt;
  82. return TRUE;
  83. }
  84. // Return handler for a given type or NULL if not found. Shared between normal types and MPE
  85. static
  86. cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList)
  87. {
  88. _cmsTagTypeLinkedList* pt;
  89. for (pt = LinkedList;
  90. pt != NULL;
  91. pt = pt ->Next) {
  92. if (sig == pt -> Handler.Signature) return &pt ->Handler;
  93. }
  94. return NULL;
  95. }
  96. // Auxiliar to convert UTF-32 to UTF-16 in some cases
  97. static
  98. cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
  99. {
  100. cmsUInt32Number i;
  101. _cmsAssert(io != NULL);
  102. _cmsAssert(!(Array == NULL && n > 0));
  103. for (i=0; i < n; i++) {
  104. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
  105. }
  106. return TRUE;
  107. }
  108. static
  109. cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
  110. {
  111. cmsUInt32Number i;
  112. cmsUInt16Number tmp;
  113. _cmsAssert(io != NULL);
  114. for (i=0; i < n; i++) {
  115. if (Array != NULL) {
  116. if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
  117. Array[i] = (wchar_t) tmp;
  118. }
  119. else {
  120. if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
  121. }
  122. }
  123. return TRUE;
  124. }
  125. // To deal with position tables
  126. typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
  127. cmsIOHANDLER* io,
  128. void* Cargo,
  129. cmsUInt32Number n,
  130. cmsUInt32Number SizeOfTag);
  131. // Helper function to deal with position tables as decribed in ICC spec 4.3
  132. // A table of n elements is readed, where first comes n records containing offsets and sizes and
  133. // then a block containing the data itself. This allows to reuse same data in more than one entry
  134. static
  135. cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
  136. cmsIOHANDLER* io,
  137. cmsUInt32Number Count,
  138. cmsUInt32Number BaseOffset,
  139. void *Cargo,
  140. PositionTableEntryFn ElementFn)
  141. {
  142. cmsUInt32Number i;
  143. cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
  144. // Let's take the offsets to each element
  145. ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
  146. if (ElementOffsets == NULL) goto Error;
  147. ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
  148. if (ElementSizes == NULL) goto Error;
  149. for (i=0; i < Count; i++) {
  150. if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
  151. if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
  152. ElementOffsets[i] += BaseOffset;
  153. }
  154. // Seek to each element and read it
  155. for (i=0; i < Count; i++) {
  156. if (!io -> Seek(io, ElementOffsets[i])) goto Error;
  157. // This is the reader callback
  158. if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
  159. }
  160. // Success
  161. if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
  162. if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
  163. return TRUE;
  164. Error:
  165. if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
  166. if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
  167. return FALSE;
  168. }
  169. // Same as anterior, but for write position tables
  170. static
  171. cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
  172. cmsIOHANDLER* io,
  173. cmsUInt32Number SizeOfTag,
  174. cmsUInt32Number Count,
  175. cmsUInt32Number BaseOffset,
  176. void *Cargo,
  177. PositionTableEntryFn ElementFn)
  178. {
  179. cmsUInt32Number i;
  180. cmsUInt32Number DirectoryPos, CurrentPos, Before;
  181. cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
  182. // Create table
  183. ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
  184. if (ElementOffsets == NULL) goto Error;
  185. ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
  186. if (ElementSizes == NULL) goto Error;
  187. // Keep starting position of curve offsets
  188. DirectoryPos = io ->Tell(io);
  189. // Write a fake directory to be filled latter on
  190. for (i=0; i < Count; i++) {
  191. if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
  192. if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
  193. }
  194. // Write each element. Keep track of the size as well.
  195. for (i=0; i < Count; i++) {
  196. Before = io ->Tell(io);
  197. ElementOffsets[i] = Before - BaseOffset;
  198. // Callback to write...
  199. if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
  200. // Now the size
  201. ElementSizes[i] = io ->Tell(io) - Before;
  202. }
  203. // Write the directory
  204. CurrentPos = io ->Tell(io);
  205. if (!io ->Seek(io, DirectoryPos)) goto Error;
  206. for (i=0; i < Count; i++) {
  207. if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
  208. if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
  209. }
  210. if (!io ->Seek(io, CurrentPos)) goto Error;
  211. if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
  212. if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
  213. return TRUE;
  214. Error:
  215. if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
  216. if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
  217. return FALSE;
  218. }
  219. // ********************************************************************************
  220. // Type XYZ. Only one value is allowed
  221. // ********************************************************************************
  222. //The XYZType contains an array of three encoded values for the XYZ tristimulus
  223. //values. Tristimulus values must be non-negative. The signed encoding allows for
  224. //implementation optimizations by minimizing the number of fixed formats.
  225. static
  226. void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  227. {
  228. cmsCIEXYZ* xyz;
  229. *nItems = 0;
  230. xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
  231. if (xyz == NULL) return NULL;
  232. if (!_cmsReadXYZNumber(io, xyz)) {
  233. _cmsFree(self ->ContextID, xyz);
  234. return NULL;
  235. }
  236. *nItems = 1;
  237. return (void*) xyz;
  238. cmsUNUSED_PARAMETER(SizeOfTag);
  239. }
  240. static
  241. cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  242. {
  243. return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
  244. cmsUNUSED_PARAMETER(nItems);
  245. cmsUNUSED_PARAMETER(self);
  246. }
  247. static
  248. void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  249. {
  250. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
  251. cmsUNUSED_PARAMETER(n);
  252. }
  253. static
  254. void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
  255. {
  256. _cmsFree(self ->ContextID, Ptr);
  257. }
  258. static
  259. cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
  260. {
  261. return cmsSigXYZType;
  262. cmsUNUSED_PARAMETER(ICCVersion);
  263. cmsUNUSED_PARAMETER(Data);
  264. }
  265. // ********************************************************************************
  266. // Type chromaticity. Only one value is allowed
  267. // ********************************************************************************
  268. // The chromaticity tag type provides basic chromaticity data and type of
  269. // phosphors or colorants of a monitor to applications and utilities.
  270. static
  271. void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  272. {
  273. cmsCIExyYTRIPLE* chrm;
  274. cmsUInt16Number nChans, Table;
  275. *nItems = 0;
  276. chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
  277. if (chrm == NULL) return NULL;
  278. if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
  279. // Let's recover from a bug introduced in early versions of lcms1
  280. if (nChans == 0 && SizeOfTag == 32) {
  281. if (!_cmsReadUInt16Number(io, NULL)) goto Error;
  282. if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
  283. }
  284. if (nChans != 3) goto Error;
  285. if (!_cmsReadUInt16Number(io, &Table)) goto Error;
  286. if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
  287. if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
  288. chrm ->Red.Y = 1.0;
  289. if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
  290. if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
  291. chrm ->Green.Y = 1.0;
  292. if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
  293. if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
  294. chrm ->Blue.Y = 1.0;
  295. *nItems = 1;
  296. return (void*) chrm;
  297. Error:
  298. _cmsFree(self ->ContextID, (void*) chrm);
  299. return NULL;
  300. cmsUNUSED_PARAMETER(SizeOfTag);
  301. }
  302. static
  303. cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
  304. {
  305. if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
  306. if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
  307. return TRUE;
  308. }
  309. static
  310. cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  311. {
  312. cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
  313. if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
  314. if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
  315. if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
  316. if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
  317. if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
  318. return TRUE;
  319. cmsUNUSED_PARAMETER(nItems);
  320. cmsUNUSED_PARAMETER(self);
  321. }
  322. static
  323. void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  324. {
  325. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
  326. cmsUNUSED_PARAMETER(n);
  327. }
  328. static
  329. void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
  330. {
  331. _cmsFree(self ->ContextID, Ptr);
  332. }
  333. // ********************************************************************************
  334. // Type cmsSigColorantOrderType
  335. // ********************************************************************************
  336. // This is an optional tag which specifies the laydown order in which colorants will
  337. // be printed on an n-colorant device. The laydown order may be the same as the
  338. // channel generation order listed in the colorantTableTag or the channel order of a
  339. // colour space such as CMYK, in which case this tag is not needed. When this is not
  340. // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
  341. // used to specify the laydown order of the colorants.
  342. static
  343. void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  344. {
  345. cmsUInt8Number* ColorantOrder;
  346. cmsUInt32Number Count;
  347. *nItems = 0;
  348. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  349. if (Count > cmsMAXCHANNELS) return NULL;
  350. ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
  351. if (ColorantOrder == NULL) return NULL;
  352. // We use FF as end marker
  353. memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
  354. if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
  355. _cmsFree(self ->ContextID, (void*) ColorantOrder);
  356. return NULL;
  357. }
  358. *nItems = 1;
  359. return (void*) ColorantOrder;
  360. cmsUNUSED_PARAMETER(SizeOfTag);
  361. }
  362. static
  363. cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  364. {
  365. cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
  366. cmsUInt32Number i, sz, Count;
  367. // Get the length
  368. for (Count=i=0; i < cmsMAXCHANNELS; i++) {
  369. if (ColorantOrder[i] != 0xFF) Count++;
  370. }
  371. if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
  372. sz = Count * sizeof(cmsUInt8Number);
  373. if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
  374. return TRUE;
  375. cmsUNUSED_PARAMETER(nItems);
  376. cmsUNUSED_PARAMETER(self);
  377. }
  378. static
  379. void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  380. {
  381. return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
  382. cmsUNUSED_PARAMETER(n);
  383. }
  384. static
  385. void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
  386. {
  387. _cmsFree(self ->ContextID, Ptr);
  388. }
  389. // ********************************************************************************
  390. // Type cmsSigS15Fixed16ArrayType
  391. // ********************************************************************************
  392. // This type represents an array of generic 4-byte/32-bit fixed point quantity.
  393. // The number of values is determined from the size of the tag.
  394. static
  395. void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  396. {
  397. cmsFloat64Number* array_double;
  398. cmsUInt32Number i, n;
  399. *nItems = 0;
  400. n = SizeOfTag / sizeof(cmsUInt32Number);
  401. array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
  402. if (array_double == NULL) return NULL;
  403. for (i=0; i < n; i++) {
  404. if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
  405. _cmsFree(self ->ContextID, array_double);
  406. return NULL;
  407. }
  408. }
  409. *nItems = n;
  410. return (void*) array_double;
  411. }
  412. static
  413. cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  414. {
  415. cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
  416. cmsUInt32Number i;
  417. for (i=0; i < nItems; i++) {
  418. if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
  419. }
  420. return TRUE;
  421. cmsUNUSED_PARAMETER(self);
  422. }
  423. static
  424. void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  425. {
  426. return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
  427. }
  428. static
  429. void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
  430. {
  431. _cmsFree(self ->ContextID, Ptr);
  432. }
  433. // ********************************************************************************
  434. // Type cmsSigU16Fixed16ArrayType
  435. // ********************************************************************************
  436. // This type represents an array of generic 4-byte/32-bit quantity.
  437. // The number of values is determined from the size of the tag.
  438. static
  439. void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  440. {
  441. cmsFloat64Number* array_double;
  442. cmsUInt32Number v;
  443. cmsUInt32Number i, n;
  444. *nItems = 0;
  445. n = SizeOfTag / sizeof(cmsUInt32Number);
  446. array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
  447. if (array_double == NULL) return NULL;
  448. for (i=0; i < n; i++) {
  449. if (!_cmsReadUInt32Number(io, &v)) {
  450. _cmsFree(self ->ContextID, (void*) array_double);
  451. return NULL;
  452. }
  453. // Convert to cmsFloat64Number
  454. array_double[i] = (cmsFloat64Number) (v / 65536.0);
  455. }
  456. *nItems = n;
  457. return (void*) array_double;
  458. }
  459. static
  460. cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  461. {
  462. cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
  463. cmsUInt32Number i;
  464. for (i=0; i < nItems; i++) {
  465. cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
  466. if (!_cmsWriteUInt32Number(io, v)) return FALSE;
  467. }
  468. return TRUE;
  469. cmsUNUSED_PARAMETER(self);
  470. }
  471. static
  472. void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  473. {
  474. return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
  475. }
  476. static
  477. void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
  478. {
  479. _cmsFree(self ->ContextID, Ptr);
  480. }
  481. // ********************************************************************************
  482. // Type cmsSigSignatureType
  483. // ********************************************************************************
  484. //
  485. // The signatureType contains a four-byte sequence, Sequences of less than four
  486. // characters are padded at the end with spaces, 20h.
  487. // Typically this type is used for registered tags that can be displayed on many
  488. // development systems as a sequence of four characters.
  489. static
  490. void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  491. {
  492. cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
  493. if (SigPtr == NULL) return NULL;
  494. if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
  495. *nItems = 1;
  496. return SigPtr;
  497. cmsUNUSED_PARAMETER(SizeOfTag);
  498. }
  499. static
  500. cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  501. {
  502. cmsSignature* SigPtr = (cmsSignature*) Ptr;
  503. return _cmsWriteUInt32Number(io, *SigPtr);
  504. cmsUNUSED_PARAMETER(nItems);
  505. cmsUNUSED_PARAMETER(self);
  506. }
  507. static
  508. void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  509. {
  510. return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
  511. }
  512. static
  513. void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
  514. {
  515. _cmsFree(self ->ContextID, Ptr);
  516. }
  517. // ********************************************************************************
  518. // Type cmsSigTextType
  519. // ********************************************************************************
  520. //
  521. // The textType is a simple text structure that contains a 7-bit ASCII text string.
  522. // The length of the string is obtained by subtracting 8 from the element size portion
  523. // of the tag itself. This string must be terminated with a 00h byte.
  524. static
  525. void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  526. {
  527. char* Text = NULL;
  528. cmsMLU* mlu = NULL;
  529. // Create a container
  530. mlu = cmsMLUalloc(self ->ContextID, 1);
  531. if (mlu == NULL) return NULL;
  532. *nItems = 0;
  533. // We need to store the "\0" at the end, so +1
  534. if (SizeOfTag == UINT_MAX) goto Error;
  535. Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
  536. if (Text == NULL) goto Error;
  537. if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
  538. // Make sure text is properly ended
  539. Text[SizeOfTag] = 0;
  540. *nItems = 1;
  541. // Keep the result
  542. if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
  543. _cmsFree(self ->ContextID, Text);
  544. return (void*) mlu;
  545. Error:
  546. if (mlu != NULL)
  547. cmsMLUfree(mlu);
  548. if (Text != NULL)
  549. _cmsFree(self ->ContextID, Text);
  550. return NULL;
  551. }
  552. // The conversion implies to choose a language. So, we choose the actual language.
  553. static
  554. cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  555. {
  556. cmsMLU* mlu = (cmsMLU*) Ptr;
  557. cmsUInt32Number size;
  558. cmsBool rc;
  559. char* Text;
  560. // Get the size of the string. Note there is an extra "\0" at the end
  561. size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
  562. if (size == 0) return FALSE; // Cannot be zero!
  563. // Create memory
  564. Text = (char*) _cmsMalloc(self ->ContextID, size);
  565. cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
  566. // Write it, including separator
  567. rc = io ->Write(io, size, Text);
  568. _cmsFree(self ->ContextID, Text);
  569. return rc;
  570. cmsUNUSED_PARAMETER(nItems);
  571. }
  572. static
  573. void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  574. {
  575. return (void*) cmsMLUdup((cmsMLU*) Ptr);
  576. cmsUNUSED_PARAMETER(n);
  577. cmsUNUSED_PARAMETER(self);
  578. }
  579. static
  580. void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
  581. {
  582. cmsMLU* mlu = (cmsMLU*) Ptr;
  583. cmsMLUfree(mlu);
  584. return;
  585. cmsUNUSED_PARAMETER(self);
  586. }
  587. static
  588. cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
  589. {
  590. if (ICCVersion >= 4.0)
  591. return cmsSigMultiLocalizedUnicodeType;
  592. return cmsSigTextType;
  593. cmsUNUSED_PARAMETER(Data);
  594. }
  595. // ********************************************************************************
  596. // Type cmsSigDataType
  597. // ********************************************************************************
  598. // General purpose data type
  599. static
  600. void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  601. {
  602. cmsICCData* BinData;
  603. cmsUInt32Number LenOfData;
  604. *nItems = 0;
  605. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  606. LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
  607. if (LenOfData > INT_MAX) return NULL;
  608. BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
  609. if (BinData == NULL) return NULL;
  610. BinData ->len = LenOfData;
  611. if (!_cmsReadUInt32Number(io, &BinData->flag)) {
  612. _cmsFree(self ->ContextID, BinData);
  613. return NULL;
  614. }
  615. if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
  616. _cmsFree(self ->ContextID, BinData);
  617. return NULL;
  618. }
  619. *nItems = 1;
  620. return (void*) BinData;
  621. }
  622. static
  623. cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  624. {
  625. cmsICCData* BinData = (cmsICCData*) Ptr;
  626. if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
  627. return io ->Write(io, BinData ->len, BinData ->data);
  628. cmsUNUSED_PARAMETER(nItems);
  629. cmsUNUSED_PARAMETER(self);
  630. }
  631. static
  632. void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  633. {
  634. cmsICCData* BinData = (cmsICCData*) Ptr;
  635. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
  636. cmsUNUSED_PARAMETER(n);
  637. }
  638. static
  639. void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
  640. {
  641. _cmsFree(self ->ContextID, Ptr);
  642. }
  643. // ********************************************************************************
  644. // Type cmsSigTextDescriptionType
  645. // ********************************************************************************
  646. static
  647. void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  648. {
  649. char* Text = NULL;
  650. cmsMLU* mlu = NULL;
  651. cmsUInt32Number AsciiCount;
  652. cmsUInt32Number i, UnicodeCode, UnicodeCount;
  653. cmsUInt16Number ScriptCodeCode, Dummy;
  654. cmsUInt8Number ScriptCodeCount;
  655. *nItems = 0;
  656. // One dword should be there
  657. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  658. // Read len of ASCII
  659. if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
  660. SizeOfTag -= sizeof(cmsUInt32Number);
  661. // Check for size
  662. if (SizeOfTag < AsciiCount) return NULL;
  663. // All seems Ok, allocate the container
  664. mlu = cmsMLUalloc(self ->ContextID, 1);
  665. if (mlu == NULL) return NULL;
  666. // As many memory as size of tag
  667. Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
  668. if (Text == NULL) goto Error;
  669. // Read it
  670. if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
  671. SizeOfTag -= AsciiCount;
  672. // Make sure there is a terminator
  673. Text[AsciiCount] = 0;
  674. // Set the MLU entry. From here we can be tolerant to wrong types
  675. if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
  676. _cmsFree(self ->ContextID, (void*) Text);
  677. Text = NULL;
  678. // Skip Unicode code
  679. if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
  680. if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
  681. if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
  682. SizeOfTag -= 2* sizeof(cmsUInt32Number);
  683. if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
  684. for (i=0; i < UnicodeCount; i++) {
  685. if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
  686. }
  687. SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
  688. // Skip ScriptCode code if present. Some buggy profiles does have less
  689. // data that stricttly required. We need to skip it as this type may come
  690. // embedded in other types.
  691. if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
  692. if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
  693. if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done;
  694. // Skip rest of tag
  695. for (i=0; i < 67; i++) {
  696. if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
  697. }
  698. }
  699. Done:
  700. *nItems = 1;
  701. return mlu;
  702. Error:
  703. if (Text) _cmsFree(self ->ContextID, (void*) Text);
  704. if (mlu) cmsMLUfree(mlu);
  705. return NULL;
  706. }
  707. // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
  708. static
  709. cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  710. {
  711. cmsMLU* mlu = (cmsMLU*) Ptr;
  712. char *Text = NULL;
  713. wchar_t *Wide = NULL;
  714. cmsUInt32Number len, len_aligned, len_filler_alignment;
  715. cmsBool rc = FALSE;
  716. char Filler[68];
  717. // Used below for writting zeroes
  718. memset(Filler, 0, sizeof(Filler));
  719. // Get the len of string
  720. len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
  721. // From ICC3.4: It has been found that textDescriptionType can contain misaligned data
  722. //(see clause 4.1 for the definition of “aligned”). Because the Unicode language
  723. // code and Unicode count immediately follow the ASCII description, their
  724. // alignment is not correct if the ASCII count is not a multiple of four. The
  725. // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
  726. // writing software must be written carefully in order to handle these alignment
  727. // problems.
  728. // Compute an aligned size
  729. len_aligned = _cmsALIGNLONG(len);
  730. len_filler_alignment = len_aligned - len;
  731. // Null strings
  732. if (len <= 0) {
  733. Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
  734. Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
  735. }
  736. else {
  737. // Create independent buffers
  738. Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
  739. if (Text == NULL) goto Error;
  740. Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
  741. if (Wide == NULL) goto Error;
  742. // Get both representations.
  743. cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
  744. cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
  745. }
  746. // * cmsUInt32Number count; * Description length
  747. // * cmsInt8Number desc[count] * NULL terminated ascii string
  748. // * cmsUInt32Number ucLangCode; * UniCode language code
  749. // * cmsUInt32Number ucCount; * UniCode description length
  750. // * cmsInt16Number ucDesc[ucCount];* The UniCode description
  751. // * cmsUInt16Number scCode; * ScriptCode code
  752. // * cmsUInt8Number scCount; * ScriptCode count
  753. // * cmsInt8Number scDesc[67]; * ScriptCode Description
  754. if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error;
  755. if (!io ->Write(io, len, Text)) goto Error;
  756. if (!io ->Write(io, len_filler_alignment, Filler)) goto Error;
  757. if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
  758. // This part is tricky: we need an aligned tag size, and the ScriptCode part
  759. // takes 70 bytes, so we need 2 extra bytes to do the alignment
  760. if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
  761. // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
  762. if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
  763. if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
  764. // ScriptCode Code & count (unused)
  765. if (!_cmsWriteUInt16Number(io, 0)) goto Error;
  766. if (!_cmsWriteUInt8Number(io, 0)) goto Error;
  767. if (!io ->Write(io, 67, Filler)) goto Error;
  768. rc = TRUE;
  769. Error:
  770. if (Text) _cmsFree(self ->ContextID, Text);
  771. if (Wide) _cmsFree(self ->ContextID, Wide);
  772. return rc;
  773. cmsUNUSED_PARAMETER(nItems);
  774. }
  775. static
  776. void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  777. {
  778. return (void*) cmsMLUdup((cmsMLU*) Ptr);
  779. cmsUNUSED_PARAMETER(n);
  780. cmsUNUSED_PARAMETER(self);
  781. }
  782. static
  783. void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
  784. {
  785. cmsMLU* mlu = (cmsMLU*) Ptr;
  786. cmsMLUfree(mlu);
  787. return;
  788. cmsUNUSED_PARAMETER(self);
  789. }
  790. static
  791. cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
  792. {
  793. if (ICCVersion >= 4.0)
  794. return cmsSigMultiLocalizedUnicodeType;
  795. return cmsSigTextDescriptionType;
  796. cmsUNUSED_PARAMETER(Data);
  797. }
  798. // ********************************************************************************
  799. // Type cmsSigCurveType
  800. // ********************************************************************************
  801. static
  802. void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  803. {
  804. cmsUInt32Number Count;
  805. cmsToneCurve* NewGamma;
  806. *nItems = 0;
  807. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  808. switch (Count) {
  809. case 0: // Linear.
  810. {
  811. cmsFloat64Number SingleGamma = 1.0;
  812. NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
  813. if (!NewGamma) return NULL;
  814. *nItems = 1;
  815. return NewGamma;
  816. }
  817. case 1: // Specified as the exponent of gamma function
  818. {
  819. cmsUInt16Number SingleGammaFixed;
  820. cmsFloat64Number SingleGamma;
  821. if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
  822. SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
  823. *nItems = 1;
  824. return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
  825. }
  826. default: // Curve
  827. if (Count > 0x7FFF)
  828. return NULL; // This is to prevent bad guys for doing bad things
  829. NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
  830. if (!NewGamma) return NULL;
  831. if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
  832. *nItems = 1;
  833. return NewGamma;
  834. }
  835. cmsUNUSED_PARAMETER(SizeOfTag);
  836. }
  837. static
  838. cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  839. {
  840. cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
  841. if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
  842. // Single gamma, preserve number
  843. cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
  844. if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
  845. if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
  846. return TRUE;
  847. }
  848. if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
  849. return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
  850. cmsUNUSED_PARAMETER(nItems);
  851. cmsUNUSED_PARAMETER(self);
  852. }
  853. static
  854. void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  855. {
  856. return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
  857. cmsUNUSED_PARAMETER(n);
  858. cmsUNUSED_PARAMETER(self);
  859. }
  860. static
  861. void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
  862. {
  863. cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
  864. cmsFreeToneCurve(gamma);
  865. return;
  866. cmsUNUSED_PARAMETER(self);
  867. }
  868. // ********************************************************************************
  869. // Type cmsSigParametricCurveType
  870. // ********************************************************************************
  871. // Decide which curve type to use on writting
  872. static
  873. cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
  874. {
  875. cmsToneCurve* Curve = (cmsToneCurve*) Data;
  876. if (ICCVersion < 4.0) return cmsSigCurveType;
  877. if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
  878. if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
  879. if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
  880. return cmsSigParametricCurveType;
  881. }
  882. static
  883. void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  884. {
  885. static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
  886. cmsFloat64Number Params[10];
  887. cmsUInt16Number Type;
  888. int i, n;
  889. cmsToneCurve* NewGamma;
  890. if (!_cmsReadUInt16Number(io, &Type)) return NULL;
  891. if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
  892. if (Type > 4) {
  893. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
  894. return NULL;
  895. }
  896. memset(Params, 0, sizeof(Params));
  897. n = ParamsByType[Type];
  898. for (i=0; i < n; i++) {
  899. if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
  900. }
  901. NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
  902. *nItems = 1;
  903. return NewGamma;
  904. cmsUNUSED_PARAMETER(SizeOfTag);
  905. }
  906. static
  907. cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  908. {
  909. cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
  910. int i, nParams, typen;
  911. static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
  912. typen = Curve -> Segments[0].Type;
  913. if (Curve ->nSegments > 1 || typen < 1) {
  914. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
  915. return FALSE;
  916. }
  917. if (typen > 5) {
  918. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
  919. return FALSE;
  920. }
  921. nParams = ParamsByType[typen];
  922. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
  923. if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
  924. for (i=0; i < nParams; i++) {
  925. if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
  926. }
  927. return TRUE;
  928. cmsUNUSED_PARAMETER(nItems);
  929. }
  930. static
  931. void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  932. {
  933. return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
  934. cmsUNUSED_PARAMETER(n);
  935. cmsUNUSED_PARAMETER(self);
  936. }
  937. static
  938. void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
  939. {
  940. cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
  941. cmsFreeToneCurve(gamma);
  942. return;
  943. cmsUNUSED_PARAMETER(self);
  944. }
  945. // ********************************************************************************
  946. // Type cmsSigDateTimeType
  947. // ********************************************************************************
  948. // A 12-byte value representation of the time and date, where the byte usage is assigned
  949. // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
  950. // (uInt16Number - see 5.1.6).
  951. //
  952. // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
  953. // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
  954. // time to UTC when setting these values. Programmes that display these values may show
  955. // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
  956. // display both UTC and local versions of the dateTimeNumber.
  957. static
  958. void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  959. {
  960. cmsDateTimeNumber timestamp;
  961. struct tm * NewDateTime;
  962. *nItems = 0;
  963. NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
  964. if (NewDateTime == NULL) return NULL;
  965. if (io->Read(io, &timestamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
  966. _cmsDecodeDateTimeNumber(&timestamp, NewDateTime);
  967. *nItems = 1;
  968. return NewDateTime;
  969. cmsUNUSED_PARAMETER(SizeOfTag);
  970. }
  971. static
  972. cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  973. {
  974. struct tm * DateTime = (struct tm*) Ptr;
  975. cmsDateTimeNumber timestamp;
  976. _cmsEncodeDateTimeNumber(&timestamp, DateTime);
  977. if (!io ->Write(io, sizeof(cmsDateTimeNumber), &timestamp)) return FALSE;
  978. return TRUE;
  979. cmsUNUSED_PARAMETER(nItems);
  980. cmsUNUSED_PARAMETER(self);
  981. }
  982. static
  983. void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  984. {
  985. return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
  986. cmsUNUSED_PARAMETER(n);
  987. }
  988. static
  989. void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
  990. {
  991. _cmsFree(self ->ContextID, Ptr);
  992. }
  993. // ********************************************************************************
  994. // Type icMeasurementType
  995. // ********************************************************************************
  996. /*
  997. The measurementType information refers only to the internal profile data and is
  998. meant to provide profile makers an alternative to the default measurement
  999. specifications.
  1000. */
  1001. static
  1002. void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  1003. {
  1004. cmsICCMeasurementConditions mc;
  1005. memset(&mc, 0, sizeof(mc));
  1006. if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
  1007. if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
  1008. if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
  1009. if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
  1010. if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
  1011. *nItems = 1;
  1012. return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
  1013. cmsUNUSED_PARAMETER(SizeOfTag);
  1014. }
  1015. static
  1016. cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  1017. {
  1018. cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
  1019. if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
  1020. if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
  1021. if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
  1022. if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
  1023. if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
  1024. return TRUE;
  1025. cmsUNUSED_PARAMETER(nItems);
  1026. cmsUNUSED_PARAMETER(self);
  1027. }
  1028. static
  1029. void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  1030. {
  1031. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
  1032. cmsUNUSED_PARAMETER(n);
  1033. }
  1034. static
  1035. void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
  1036. {
  1037. _cmsFree(self ->ContextID, Ptr);
  1038. }
  1039. // ********************************************************************************
  1040. // Type cmsSigMultiLocalizedUnicodeType
  1041. // ********************************************************************************
  1042. //
  1043. // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
  1044. // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
  1045. // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
  1046. //
  1047. static
  1048. void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  1049. {
  1050. cmsMLU* mlu;
  1051. cmsUInt32Number Count, RecLen, NumOfWchar;
  1052. cmsUInt32Number SizeOfHeader;
  1053. cmsUInt32Number Len, Offset;
  1054. cmsUInt32Number i;
  1055. wchar_t* Block;
  1056. cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition;
  1057. *nItems = 0;
  1058. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  1059. if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
  1060. if (RecLen != 12) {
  1061. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
  1062. return NULL;
  1063. }
  1064. mlu = cmsMLUalloc(self ->ContextID, Count);
  1065. if (mlu == NULL) return NULL;
  1066. mlu ->UsedEntries = Count;
  1067. SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
  1068. LargestPosition = 0;
  1069. for (i=0; i < Count; i++) {
  1070. if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
  1071. if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
  1072. // Now deal with Len and offset.
  1073. if (!_cmsReadUInt32Number(io, &Len)) goto Error;
  1074. if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
  1075. // Check for overflow
  1076. if (Offset < (SizeOfHeader + 8)) goto Error;
  1077. // True begin of the string
  1078. BeginOfThisString = Offset - SizeOfHeader - 8;
  1079. // Ajust to wchar_t elements
  1080. mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
  1081. mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
  1082. // To guess maximum size, add offset + len
  1083. EndOfThisString = BeginOfThisString + Len;
  1084. if (EndOfThisString > LargestPosition)
  1085. LargestPosition = EndOfThisString;
  1086. }
  1087. // Now read the remaining of tag and fill all strings. Substract the directory
  1088. SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
  1089. if (SizeOfTag == 0)
  1090. {
  1091. Block = NULL;
  1092. NumOfWchar = 0;
  1093. }
  1094. else
  1095. {
  1096. Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
  1097. if (Block == NULL) goto Error;
  1098. NumOfWchar = SizeOfTag / sizeof(wchar_t);
  1099. if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
  1100. }
  1101. mlu ->MemPool = Block;
  1102. mlu ->PoolSize = SizeOfTag;
  1103. mlu ->PoolUsed = SizeOfTag;
  1104. *nItems = 1;
  1105. return (void*) mlu;
  1106. Error:
  1107. if (mlu) cmsMLUfree(mlu);
  1108. return NULL;
  1109. }
  1110. static
  1111. cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  1112. {
  1113. cmsMLU* mlu =(cmsMLU*) Ptr;
  1114. cmsUInt32Number HeaderSize;
  1115. cmsUInt32Number Len, Offset;
  1116. int i;
  1117. if (Ptr == NULL) {
  1118. // Empty placeholder
  1119. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  1120. if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
  1121. return TRUE;
  1122. }
  1123. if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
  1124. if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
  1125. HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
  1126. for (i=0; i < mlu ->UsedEntries; i++) {
  1127. Len = mlu ->Entries[i].Len;
  1128. Offset = mlu ->Entries[i].StrW;
  1129. Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
  1130. Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
  1131. if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
  1132. if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
  1133. if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
  1134. if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
  1135. }
  1136. if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
  1137. return TRUE;
  1138. cmsUNUSED_PARAMETER(nItems);
  1139. cmsUNUSED_PARAMETER(self);
  1140. }
  1141. static
  1142. void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  1143. {
  1144. return (void*) cmsMLUdup((cmsMLU*) Ptr);
  1145. cmsUNUSED_PARAMETER(n);
  1146. cmsUNUSED_PARAMETER(self);
  1147. }
  1148. static
  1149. void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
  1150. {
  1151. cmsMLUfree((cmsMLU*) Ptr);
  1152. return;
  1153. cmsUNUSED_PARAMETER(self);
  1154. }
  1155. // ********************************************************************************
  1156. // Type cmsSigLut8Type
  1157. // ********************************************************************************
  1158. // Decide which LUT type to use on writting
  1159. static
  1160. cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
  1161. {
  1162. cmsPipeline* Lut = (cmsPipeline*) Data;
  1163. if (ICCVersion < 4.0) {
  1164. if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
  1165. return cmsSigLut16Type;
  1166. }
  1167. else {
  1168. return cmsSigLutAtoBType;
  1169. }
  1170. }
  1171. static
  1172. cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
  1173. {
  1174. cmsPipeline* Lut = (cmsPipeline*) Data;
  1175. if (ICCVersion < 4.0) {
  1176. if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
  1177. return cmsSigLut16Type;
  1178. }
  1179. else {
  1180. return cmsSigLutBtoAType;
  1181. }
  1182. }
  1183. /*
  1184. This structure represents a colour transform using tables of 8-bit precision.
  1185. This type contains four processing elements: a 3 by 3 matrix (which shall be
  1186. the identity matrix unless the input colour space is XYZ), a set of one dimensional
  1187. input tables, a multidimensional lookup table, and a set of one dimensional output
  1188. tables. Data is processed using these elements via the following sequence:
  1189. (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
  1190. Byte Position Field Length (bytes) Content Encoded as...
  1191. 8 1 Number of Input Channels (i) uInt8Number
  1192. 9 1 Number of Output Channels (o) uInt8Number
  1193. 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
  1194. 11 1 Reserved for padding (fill with 00h)
  1195. 12..15 4 Encoded e00 parameter s15Fixed16Number
  1196. */
  1197. // Read 8 bit tables as gamma functions
  1198. static
  1199. cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
  1200. {
  1201. cmsUInt8Number* Temp = NULL;
  1202. int i, j;
  1203. cmsToneCurve* Tables[cmsMAXCHANNELS];
  1204. if (nChannels > cmsMAXCHANNELS) return FALSE;
  1205. if (nChannels <= 0) return FALSE;
  1206. memset(Tables, 0, sizeof(Tables));
  1207. Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
  1208. if (Temp == NULL) return FALSE;
  1209. for (i=0; i < nChannels; i++) {
  1210. Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
  1211. if (Tables[i] == NULL) goto Error;
  1212. }
  1213. for (i=0; i < nChannels; i++) {
  1214. if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
  1215. for (j=0; j < 256; j++)
  1216. Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
  1217. }
  1218. _cmsFree(ContextID, Temp);
  1219. Temp = NULL;
  1220. if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
  1221. goto Error;
  1222. for (i=0; i < nChannels; i++)
  1223. cmsFreeToneCurve(Tables[i]);
  1224. return TRUE;
  1225. Error:
  1226. for (i=0; i < nChannels; i++) {
  1227. if (Tables[i]) cmsFreeToneCurve(Tables[i]);
  1228. }
  1229. if (Temp) _cmsFree(ContextID, Temp);
  1230. return FALSE;
  1231. }
  1232. static
  1233. cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
  1234. {
  1235. int j;
  1236. cmsUInt32Number i;
  1237. cmsUInt8Number val;
  1238. for (i=0; i < n; i++) {
  1239. if (Tables) {
  1240. // Usual case of identity curves
  1241. if ((Tables ->TheCurves[i]->nEntries == 2) &&
  1242. (Tables->TheCurves[i]->Table16[0] == 0) &&
  1243. (Tables->TheCurves[i]->Table16[1] == 65535)) {
  1244. for (j=0; j < 256; j++) {
  1245. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE;
  1246. }
  1247. }
  1248. else
  1249. if (Tables ->TheCurves[i]->nEntries != 256) {
  1250. cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
  1251. return FALSE;
  1252. }
  1253. else
  1254. for (j=0; j < 256; j++) {
  1255. if (Tables != NULL)
  1256. val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
  1257. else
  1258. val = (cmsUInt8Number) j;
  1259. if (!_cmsWriteUInt8Number(io, val)) return FALSE;
  1260. }
  1261. }
  1262. }
  1263. return TRUE;
  1264. }
  1265. // Check overflow
  1266. static
  1267. cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
  1268. {
  1269. cmsUInt32Number rv = 1, rc;
  1270. if (a == 0) return 0;
  1271. if (n == 0) return 0;
  1272. for (; b > 0; b--) {
  1273. rv *= a;
  1274. // Check for overflow
  1275. if (rv > UINT_MAX / a) return (cmsUInt32Number) -1;
  1276. }
  1277. rc = rv * n;
  1278. if (rv != rc / n) return (cmsUInt32Number) -1;
  1279. return rc;
  1280. }
  1281. // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
  1282. // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
  1283. // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
  1284. static
  1285. void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  1286. {
  1287. cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
  1288. cmsUInt8Number* Temp = NULL;
  1289. cmsPipeline* NewLUT = NULL;
  1290. cmsUInt32Number nTabSize, i;
  1291. cmsFloat64Number Matrix[3*3];
  1292. *nItems = 0;
  1293. if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
  1294. if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
  1295. if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
  1296. if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
  1297. // Padding
  1298. if (!_cmsReadUInt8Number(io, NULL)) goto Error;
  1299. // Do some checking
  1300. if (InputChannels > cmsMAXCHANNELS) goto Error;
  1301. if (OutputChannels > cmsMAXCHANNELS) goto Error;
  1302. // Allocates an empty Pipeline
  1303. NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
  1304. if (NewLUT == NULL) goto Error;
  1305. // Read the Matrix
  1306. if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
  1307. if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
  1308. if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
  1309. if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
  1310. if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
  1311. if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
  1312. if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
  1313. if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
  1314. if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
  1315. // Only operates if not identity...
  1316. if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
  1317. if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
  1318. goto Error;
  1319. }
  1320. // Get input tables
  1321. if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error;
  1322. // Get 3D CLUT. Check the overflow....
  1323. nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
  1324. if (nTabSize == (cmsUInt32Number) -1) goto Error;
  1325. if (nTabSize > 0) {
  1326. cmsUInt16Number *PtrW, *T;
  1327. PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
  1328. if (T == NULL) goto Error;
  1329. Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
  1330. if (Temp == NULL) goto Error;
  1331. if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error;
  1332. for (i = 0; i < nTabSize; i++) {
  1333. *PtrW++ = FROM_8_TO_16(Temp[i]);
  1334. }
  1335. _cmsFree(self ->ContextID, Temp);
  1336. Temp = NULL;
  1337. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
  1338. goto Error;
  1339. _cmsFree(self ->ContextID, T);
  1340. }
  1341. // Get output tables
  1342. if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
  1343. *nItems = 1;
  1344. return NewLUT;
  1345. Error:
  1346. if (NewLUT != NULL) cmsPipelineFree(NewLUT);
  1347. return NULL;
  1348. cmsUNUSED_PARAMETER(SizeOfTag);
  1349. }
  1350. // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
  1351. static
  1352. cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  1353. {
  1354. cmsUInt32Number j, nTabSize;
  1355. cmsUInt8Number val;
  1356. cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
  1357. cmsStage* mpe;
  1358. _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
  1359. _cmsStageMatrixData* MatMPE = NULL;
  1360. _cmsStageCLutData* clut = NULL;
  1361. int clutPoints;
  1362. // Disassemble the LUT into components.
  1363. mpe = NewLUT -> Elements;
  1364. if (mpe ->Type == cmsSigMatrixElemType) {
  1365. MatMPE = (_cmsStageMatrixData*) mpe ->Data;
  1366. mpe = mpe -> Next;
  1367. }
  1368. if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
  1369. PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
  1370. mpe = mpe -> Next;
  1371. }
  1372. if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
  1373. clut = (_cmsStageCLutData*) mpe -> Data;
  1374. mpe = mpe ->Next;
  1375. }
  1376. if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
  1377. PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
  1378. mpe = mpe -> Next;
  1379. }
  1380. // That should be all
  1381. if (mpe != NULL) {
  1382. cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
  1383. return FALSE;
  1384. }
  1385. if (clut == NULL)
  1386. clutPoints = 0;
  1387. else
  1388. clutPoints = clut->Params->nSamples[0];
  1389. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
  1390. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
  1391. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
  1392. if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
  1393. if (MatMPE != NULL) {
  1394. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
  1395. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
  1396. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
  1397. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
  1398. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
  1399. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
  1400. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
  1401. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
  1402. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
  1403. }
  1404. else {
  1405. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1406. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1407. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1408. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1409. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1410. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1411. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1412. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1413. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1414. }
  1415. // The prelinearization table
  1416. if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
  1417. nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
  1418. if (nTabSize == (cmsUInt32Number) -1) return FALSE;
  1419. if (nTabSize > 0) {
  1420. // The 3D CLUT.
  1421. if (clut != NULL) {
  1422. for (j=0; j < nTabSize; j++) {
  1423. val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
  1424. if (!_cmsWriteUInt8Number(io, val)) return FALSE;
  1425. }
  1426. }
  1427. }
  1428. // The postlinearization table
  1429. if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
  1430. return TRUE;
  1431. cmsUNUSED_PARAMETER(nItems);
  1432. }
  1433. static
  1434. void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  1435. {
  1436. return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
  1437. cmsUNUSED_PARAMETER(n);
  1438. cmsUNUSED_PARAMETER(self);
  1439. }
  1440. static
  1441. void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
  1442. {
  1443. cmsPipelineFree((cmsPipeline*) Ptr);
  1444. return;
  1445. cmsUNUSED_PARAMETER(self);
  1446. }
  1447. // ********************************************************************************
  1448. // Type cmsSigLut16Type
  1449. // ********************************************************************************
  1450. // Read 16 bit tables as gamma functions
  1451. static
  1452. cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
  1453. {
  1454. int i;
  1455. cmsToneCurve* Tables[cmsMAXCHANNELS];
  1456. // Maybe an empty table? (this is a lcms extension)
  1457. if (nEntries <= 0) return TRUE;
  1458. // Check for malicious profiles
  1459. if (nEntries < 2) return FALSE;
  1460. if (nChannels > cmsMAXCHANNELS) return FALSE;
  1461. // Init table to zero
  1462. memset(Tables, 0, sizeof(Tables));
  1463. for (i=0; i < nChannels; i++) {
  1464. Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
  1465. if (Tables[i] == NULL) goto Error;
  1466. if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
  1467. }
  1468. // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
  1469. if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
  1470. goto Error;
  1471. for (i=0; i < nChannels; i++)
  1472. cmsFreeToneCurve(Tables[i]);
  1473. return TRUE;
  1474. Error:
  1475. for (i=0; i < nChannels; i++) {
  1476. if (Tables[i]) cmsFreeToneCurve(Tables[i]);
  1477. }
  1478. return FALSE;
  1479. }
  1480. static
  1481. cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
  1482. {
  1483. int j;
  1484. cmsUInt32Number i;
  1485. cmsUInt16Number val;
  1486. int nEntries;
  1487. _cmsAssert(Tables != NULL);
  1488. nEntries = Tables->TheCurves[0]->nEntries;
  1489. for (i=0; i < Tables ->nCurves; i++) {
  1490. for (j=0; j < nEntries; j++) {
  1491. val = Tables->TheCurves[i]->Table16[j];
  1492. if (!_cmsWriteUInt16Number(io, val)) return FALSE;
  1493. }
  1494. }
  1495. return TRUE;
  1496. cmsUNUSED_PARAMETER(ContextID);
  1497. }
  1498. static
  1499. void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  1500. {
  1501. cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
  1502. cmsPipeline* NewLUT = NULL;
  1503. cmsUInt32Number nTabSize;
  1504. cmsFloat64Number Matrix[3*3];
  1505. cmsUInt16Number InputEntries, OutputEntries;
  1506. *nItems = 0;
  1507. if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
  1508. if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
  1509. if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
  1510. // Padding
  1511. if (!_cmsReadUInt8Number(io, NULL)) return NULL;
  1512. // Do some checking
  1513. if (InputChannels > cmsMAXCHANNELS) goto Error;
  1514. if (OutputChannels > cmsMAXCHANNELS) goto Error;
  1515. // Allocates an empty LUT
  1516. NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
  1517. if (NewLUT == NULL) goto Error;
  1518. // Read the Matrix
  1519. if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
  1520. if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
  1521. if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
  1522. if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
  1523. if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
  1524. if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
  1525. if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
  1526. if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
  1527. if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
  1528. // Only operates on 3 channels
  1529. if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
  1530. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
  1531. goto Error;
  1532. }
  1533. if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
  1534. if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error;
  1535. if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error;
  1536. if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
  1537. // Get input tables
  1538. if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error;
  1539. // Get 3D CLUT
  1540. nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
  1541. if (nTabSize == (cmsUInt32Number) -1) goto Error;
  1542. if (nTabSize > 0) {
  1543. cmsUInt16Number *T;
  1544. T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
  1545. if (T == NULL) goto Error;
  1546. if (!_cmsReadUInt16Array(io, nTabSize, T)) {
  1547. _cmsFree(self ->ContextID, T);
  1548. goto Error;
  1549. }
  1550. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
  1551. _cmsFree(self ->ContextID, T);
  1552. goto Error;
  1553. }
  1554. _cmsFree(self ->ContextID, T);
  1555. }
  1556. // Get output tables
  1557. if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
  1558. *nItems = 1;
  1559. return NewLUT;
  1560. Error:
  1561. if (NewLUT != NULL) cmsPipelineFree(NewLUT);
  1562. return NULL;
  1563. cmsUNUSED_PARAMETER(SizeOfTag);
  1564. }
  1565. // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
  1566. // Some empty defaults are created for missing parts
  1567. static
  1568. cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  1569. {
  1570. cmsUInt32Number nTabSize;
  1571. cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
  1572. cmsStage* mpe;
  1573. _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
  1574. _cmsStageMatrixData* MatMPE = NULL;
  1575. _cmsStageCLutData* clut = NULL;
  1576. int i, InputChannels, OutputChannels, clutPoints;
  1577. // Disassemble the LUT into components.
  1578. mpe = NewLUT -> Elements;
  1579. if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
  1580. MatMPE = (_cmsStageMatrixData*) mpe ->Data;
  1581. mpe = mpe -> Next;
  1582. }
  1583. if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
  1584. PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
  1585. mpe = mpe -> Next;
  1586. }
  1587. if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
  1588. clut = (_cmsStageCLutData*) mpe -> Data;
  1589. mpe = mpe ->Next;
  1590. }
  1591. if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
  1592. PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
  1593. mpe = mpe -> Next;
  1594. }
  1595. // That should be all
  1596. if (mpe != NULL) {
  1597. cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
  1598. return FALSE;
  1599. }
  1600. InputChannels = cmsPipelineInputChannels(NewLUT);
  1601. OutputChannels = cmsPipelineOutputChannels(NewLUT);
  1602. if (clut == NULL)
  1603. clutPoints = 0;
  1604. else
  1605. clutPoints = clut->Params->nSamples[0];
  1606. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
  1607. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
  1608. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
  1609. if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
  1610. if (MatMPE != NULL) {
  1611. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
  1612. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
  1613. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
  1614. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
  1615. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
  1616. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
  1617. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
  1618. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
  1619. if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
  1620. }
  1621. else {
  1622. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1623. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1624. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1625. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1626. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1627. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1628. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1629. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1630. if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
  1631. }
  1632. if (PreMPE != NULL) {
  1633. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
  1634. } else {
  1635. if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
  1636. }
  1637. if (PostMPE != NULL) {
  1638. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
  1639. } else {
  1640. if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
  1641. }
  1642. // The prelinearization table
  1643. if (PreMPE != NULL) {
  1644. if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
  1645. }
  1646. else {
  1647. for (i=0; i < InputChannels; i++) {
  1648. if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
  1649. if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
  1650. }
  1651. }
  1652. nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
  1653. if (nTabSize == (cmsUInt32Number) -1) return FALSE;
  1654. if (nTabSize > 0) {
  1655. // The 3D CLUT.
  1656. if (clut != NULL) {
  1657. if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
  1658. }
  1659. }
  1660. // The postlinearization table
  1661. if (PostMPE != NULL) {
  1662. if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
  1663. }
  1664. else {
  1665. for (i=0; i < OutputChannels; i++) {
  1666. if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
  1667. if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
  1668. }
  1669. }
  1670. return TRUE;
  1671. cmsUNUSED_PARAMETER(nItems);
  1672. }
  1673. static
  1674. void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  1675. {
  1676. return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
  1677. cmsUNUSED_PARAMETER(n);
  1678. cmsUNUSED_PARAMETER(self);
  1679. }
  1680. static
  1681. void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
  1682. {
  1683. cmsPipelineFree((cmsPipeline*) Ptr);
  1684. return;
  1685. cmsUNUSED_PARAMETER(self);
  1686. }
  1687. // ********************************************************************************
  1688. // Type cmsSigLutAToBType
  1689. // ********************************************************************************
  1690. // V4 stuff. Read matrix for LutAtoB and LutBtoA
  1691. static
  1692. cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
  1693. {
  1694. cmsFloat64Number dMat[3*3];
  1695. cmsFloat64Number dOff[3];
  1696. cmsStage* Mat;
  1697. // Go to address
  1698. if (!io -> Seek(io, Offset)) return NULL;
  1699. // Read the Matrix
  1700. if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
  1701. if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
  1702. if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
  1703. if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
  1704. if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
  1705. if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
  1706. if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
  1707. if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
  1708. if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
  1709. if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
  1710. if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
  1711. if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
  1712. Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
  1713. return Mat;
  1714. }
  1715. // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
  1716. static
  1717. cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
  1718. {
  1719. cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
  1720. cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
  1721. cmsUInt8Number Precision;
  1722. cmsStage* CLUT;
  1723. _cmsStageCLutData* Data;
  1724. if (!io -> Seek(io, Offset)) return NULL;
  1725. if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
  1726. for (i=0; i < cmsMAXCHANNELS; i++) {
  1727. if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least
  1728. GridPoints[i] = gridPoints8[i];
  1729. }
  1730. if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
  1731. if (!_cmsReadUInt8Number(io, NULL)) return NULL;
  1732. if (!_cmsReadUInt8Number(io, NULL)) return NULL;
  1733. if (!_cmsReadUInt8Number(io, NULL)) return NULL;
  1734. CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
  1735. if (CLUT == NULL) return NULL;
  1736. Data = (_cmsStageCLutData*) CLUT ->Data;
  1737. // Precision can be 1 or 2 bytes
  1738. if (Precision == 1) {
  1739. cmsUInt8Number v;
  1740. for (i=0; i < Data ->nEntries; i++) {
  1741. if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
  1742. Data ->Tab.T[i] = FROM_8_TO_16(v);
  1743. }
  1744. }
  1745. else
  1746. if (Precision == 2) {
  1747. if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
  1748. }
  1749. else {
  1750. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
  1751. return NULL;
  1752. }
  1753. return CLUT;
  1754. }
  1755. static
  1756. cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
  1757. {
  1758. cmsTagTypeSignature BaseType;
  1759. cmsUInt32Number nItems;
  1760. BaseType = _cmsReadTypeBase(io);
  1761. switch (BaseType) {
  1762. case cmsSigCurveType:
  1763. return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
  1764. case cmsSigParametricCurveType:
  1765. return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
  1766. default:
  1767. {
  1768. char String[5];
  1769. _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
  1770. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
  1771. }
  1772. return NULL;
  1773. }
  1774. }
  1775. // Read a set of curves from specific offset
  1776. static
  1777. cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
  1778. {
  1779. cmsToneCurve* Curves[cmsMAXCHANNELS];
  1780. cmsUInt32Number i;
  1781. cmsStage* Lin = NULL;
  1782. if (nCurves > cmsMAXCHANNELS) return FALSE;
  1783. if (!io -> Seek(io, Offset)) return FALSE;
  1784. for (i=0; i < nCurves; i++)
  1785. Curves[i] = NULL;
  1786. for (i=0; i < nCurves; i++) {
  1787. Curves[i] = ReadEmbeddedCurve(self, io);
  1788. if (Curves[i] == NULL) goto Error;
  1789. if (!_cmsReadAlignment(io)) goto Error;
  1790. }
  1791. Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
  1792. Error:
  1793. for (i=0; i < nCurves; i++)
  1794. cmsFreeToneCurve(Curves[i]);
  1795. return Lin;
  1796. }
  1797. // LutAtoB type
  1798. // This structure represents a colour transform. The type contains up to five processing
  1799. // elements which are stored in the AtoBTag tag in the following order: a set of one
  1800. // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
  1801. // a multidimensional lookup table, and a set of one dimensional output curves.
  1802. // Data are processed using these elements via the following sequence:
  1803. //
  1804. //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
  1805. //
  1806. /*
  1807. It is possible to use any or all of these processing elements. At least one processing element
  1808. must be included.Only the following combinations are allowed:
  1809. B
  1810. M - Matrix - B
  1811. A - CLUT - B
  1812. A - CLUT - M - Matrix - B
  1813. */
  1814. static
  1815. void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  1816. {
  1817. cmsUInt32Number BaseOffset;
  1818. cmsUInt8Number inputChan; // Number of input channels
  1819. cmsUInt8Number outputChan; // Number of output channels
  1820. cmsUInt32Number offsetB; // Offset to first "B" curve
  1821. cmsUInt32Number offsetMat; // Offset to matrix
  1822. cmsUInt32Number offsetM; // Offset to first "M" curve
  1823. cmsUInt32Number offsetC; // Offset to CLUT
  1824. cmsUInt32Number offsetA; // Offset to first "A" curve
  1825. cmsPipeline* NewLUT = NULL;
  1826. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  1827. if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
  1828. if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
  1829. if (!_cmsReadUInt16Number(io, NULL)) return NULL;
  1830. if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
  1831. if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
  1832. if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
  1833. if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
  1834. if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
  1835. // Allocates an empty LUT
  1836. NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
  1837. if (NewLUT == NULL) return NULL;
  1838. if (offsetA!= 0) {
  1839. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
  1840. goto Error;
  1841. }
  1842. if (offsetC != 0) {
  1843. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
  1844. goto Error;
  1845. }
  1846. if (offsetM != 0) {
  1847. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
  1848. goto Error;
  1849. }
  1850. if (offsetMat != 0) {
  1851. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
  1852. goto Error;
  1853. }
  1854. if (offsetB != 0) {
  1855. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
  1856. goto Error;
  1857. }
  1858. *nItems = 1;
  1859. return NewLUT;
  1860. Error:
  1861. cmsPipelineFree(NewLUT);
  1862. return NULL;
  1863. cmsUNUSED_PARAMETER(SizeOfTag);
  1864. }
  1865. // Write a set of curves
  1866. static
  1867. cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
  1868. {
  1869. _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
  1870. // Write the Matrix
  1871. if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
  1872. if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
  1873. if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
  1874. if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
  1875. if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
  1876. if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
  1877. if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
  1878. if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
  1879. if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
  1880. if (m ->Offset != NULL) {
  1881. if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
  1882. if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
  1883. if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
  1884. }
  1885. else {
  1886. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1887. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1888. if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
  1889. }
  1890. return TRUE;
  1891. cmsUNUSED_PARAMETER(self);
  1892. }
  1893. // Write a set of curves
  1894. static
  1895. cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
  1896. {
  1897. cmsUInt32Number i, n;
  1898. cmsTagTypeSignature CurrentType;
  1899. cmsToneCurve** Curves;
  1900. n = cmsStageOutputChannels(mpe);
  1901. Curves = _cmsStageGetPtrToCurveSet(mpe);
  1902. for (i=0; i < n; i++) {
  1903. // If this is a table-based curve, use curve type even on V4
  1904. CurrentType = Type;
  1905. if ((Curves[i] ->nSegments == 0)||
  1906. ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
  1907. CurrentType = cmsSigCurveType;
  1908. else
  1909. if (Curves[i] ->Segments[0].Type < 0)
  1910. CurrentType = cmsSigCurveType;
  1911. if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
  1912. switch (CurrentType) {
  1913. case cmsSigCurveType:
  1914. if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
  1915. break;
  1916. case cmsSigParametricCurveType:
  1917. if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
  1918. break;
  1919. default:
  1920. {
  1921. char String[5];
  1922. _cmsTagSignature2String(String, (cmsTagSignature) Type);
  1923. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
  1924. }
  1925. return FALSE;
  1926. }
  1927. if (!_cmsWriteAlignment(io)) return FALSE;
  1928. }
  1929. return TRUE;
  1930. }
  1931. static
  1932. cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe)
  1933. {
  1934. cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
  1935. cmsUInt32Number i;
  1936. _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
  1937. if (CLUT ->HasFloatValues) {
  1938. cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
  1939. return FALSE;
  1940. }
  1941. memset(gridPoints, 0, sizeof(gridPoints));
  1942. for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
  1943. gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
  1944. if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
  1945. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
  1946. if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
  1947. if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
  1948. if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
  1949. // Precision can be 1 or 2 bytes
  1950. if (Precision == 1) {
  1951. for (i=0; i < CLUT->nEntries; i++) {
  1952. if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
  1953. }
  1954. }
  1955. else
  1956. if (Precision == 2) {
  1957. if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
  1958. }
  1959. else {
  1960. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
  1961. return FALSE;
  1962. }
  1963. if (!_cmsWriteAlignment(io)) return FALSE;
  1964. return TRUE;
  1965. }
  1966. static
  1967. cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  1968. {
  1969. cmsPipeline* Lut = (cmsPipeline*) Ptr;
  1970. int inputChan, outputChan;
  1971. cmsStage *A = NULL, *B = NULL, *M = NULL;
  1972. cmsStage * Matrix = NULL;
  1973. cmsStage * CLUT = NULL;
  1974. cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
  1975. cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
  1976. // Get the base for all offsets
  1977. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  1978. if (Lut ->Elements != NULL)
  1979. if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
  1980. if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
  1981. if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
  1982. if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
  1983. cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
  1984. cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
  1985. return FALSE;
  1986. }
  1987. // Get input, output channels
  1988. inputChan = cmsPipelineInputChannels(Lut);
  1989. outputChan = cmsPipelineOutputChannels(Lut);
  1990. // Write channel count
  1991. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
  1992. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
  1993. if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
  1994. // Keep directory to be filled latter
  1995. DirectoryPos = io ->Tell(io);
  1996. // Write the directory
  1997. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  1998. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  1999. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2000. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2001. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2002. if (A != NULL) {
  2003. offsetA = io ->Tell(io) - BaseOffset;
  2004. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
  2005. }
  2006. if (CLUT != NULL) {
  2007. offsetC = io ->Tell(io) - BaseOffset;
  2008. if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
  2009. }
  2010. if (M != NULL) {
  2011. offsetM = io ->Tell(io) - BaseOffset;
  2012. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
  2013. }
  2014. if (Matrix != NULL) {
  2015. offsetMat = io ->Tell(io) - BaseOffset;
  2016. if (!WriteMatrix(self, io, Matrix)) return FALSE;
  2017. }
  2018. if (B != NULL) {
  2019. offsetB = io ->Tell(io) - BaseOffset;
  2020. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
  2021. }
  2022. CurrentPos = io ->Tell(io);
  2023. if (!io ->Seek(io, DirectoryPos)) return FALSE;
  2024. if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
  2025. if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
  2026. if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
  2027. if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
  2028. if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
  2029. if (!io ->Seek(io, CurrentPos)) return FALSE;
  2030. return TRUE;
  2031. cmsUNUSED_PARAMETER(nItems);
  2032. }
  2033. static
  2034. void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2035. {
  2036. return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
  2037. cmsUNUSED_PARAMETER(n);
  2038. cmsUNUSED_PARAMETER(self);
  2039. }
  2040. static
  2041. void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2042. {
  2043. cmsPipelineFree((cmsPipeline*) Ptr);
  2044. return;
  2045. cmsUNUSED_PARAMETER(self);
  2046. }
  2047. // LutBToA type
  2048. static
  2049. void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2050. {
  2051. cmsUInt8Number inputChan; // Number of input channels
  2052. cmsUInt8Number outputChan; // Number of output channels
  2053. cmsUInt32Number BaseOffset; // Actual position in file
  2054. cmsUInt32Number offsetB; // Offset to first "B" curve
  2055. cmsUInt32Number offsetMat; // Offset to matrix
  2056. cmsUInt32Number offsetM; // Offset to first "M" curve
  2057. cmsUInt32Number offsetC; // Offset to CLUT
  2058. cmsUInt32Number offsetA; // Offset to first "A" curve
  2059. cmsPipeline* NewLUT = NULL;
  2060. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  2061. if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
  2062. if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
  2063. // Padding
  2064. if (!_cmsReadUInt16Number(io, NULL)) return NULL;
  2065. if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
  2066. if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
  2067. if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
  2068. if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
  2069. if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
  2070. // Allocates an empty LUT
  2071. NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
  2072. if (NewLUT == NULL) return NULL;
  2073. if (offsetB != 0) {
  2074. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan)))
  2075. goto Error;
  2076. }
  2077. if (offsetMat != 0) {
  2078. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
  2079. goto Error;
  2080. }
  2081. if (offsetM != 0) {
  2082. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
  2083. goto Error;
  2084. }
  2085. if (offsetC != 0) {
  2086. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
  2087. goto Error;
  2088. }
  2089. if (offsetA!= 0) {
  2090. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
  2091. goto Error;
  2092. }
  2093. *nItems = 1;
  2094. return NewLUT;
  2095. Error:
  2096. cmsPipelineFree(NewLUT);
  2097. return NULL;
  2098. cmsUNUSED_PARAMETER(SizeOfTag);
  2099. }
  2100. /*
  2101. B
  2102. B - Matrix - M
  2103. B - CLUT - A
  2104. B - Matrix - M - CLUT - A
  2105. */
  2106. static
  2107. cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2108. {
  2109. cmsPipeline* Lut = (cmsPipeline*) Ptr;
  2110. int inputChan, outputChan;
  2111. cmsStage *A = NULL, *B = NULL, *M = NULL;
  2112. cmsStage *Matrix = NULL;
  2113. cmsStage *CLUT = NULL;
  2114. cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
  2115. cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
  2116. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  2117. if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
  2118. if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
  2119. if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
  2120. if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
  2121. cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
  2122. cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
  2123. return FALSE;
  2124. }
  2125. inputChan = cmsPipelineInputChannels(Lut);
  2126. outputChan = cmsPipelineOutputChannels(Lut);
  2127. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
  2128. if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
  2129. if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
  2130. DirectoryPos = io ->Tell(io);
  2131. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2132. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2133. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2134. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2135. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2136. if (A != NULL) {
  2137. offsetA = io ->Tell(io) - BaseOffset;
  2138. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
  2139. }
  2140. if (CLUT != NULL) {
  2141. offsetC = io ->Tell(io) - BaseOffset;
  2142. if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
  2143. }
  2144. if (M != NULL) {
  2145. offsetM = io ->Tell(io) - BaseOffset;
  2146. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
  2147. }
  2148. if (Matrix != NULL) {
  2149. offsetMat = io ->Tell(io) - BaseOffset;
  2150. if (!WriteMatrix(self, io, Matrix)) return FALSE;
  2151. }
  2152. if (B != NULL) {
  2153. offsetB = io ->Tell(io) - BaseOffset;
  2154. if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
  2155. }
  2156. CurrentPos = io ->Tell(io);
  2157. if (!io ->Seek(io, DirectoryPos)) return FALSE;
  2158. if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
  2159. if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
  2160. if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
  2161. if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
  2162. if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
  2163. if (!io ->Seek(io, CurrentPos)) return FALSE;
  2164. return TRUE;
  2165. cmsUNUSED_PARAMETER(nItems);
  2166. }
  2167. static
  2168. void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2169. {
  2170. return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
  2171. cmsUNUSED_PARAMETER(n);
  2172. cmsUNUSED_PARAMETER(self);
  2173. }
  2174. static
  2175. void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2176. {
  2177. cmsPipelineFree((cmsPipeline*) Ptr);
  2178. return;
  2179. cmsUNUSED_PARAMETER(self);
  2180. }
  2181. // ********************************************************************************
  2182. // Type cmsSigColorantTableType
  2183. // ********************************************************************************
  2184. /*
  2185. The purpose of this tag is to identify the colorants used in the profile by a
  2186. unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
  2187. value. The first colorant listed is the colorant of the first device channel of
  2188. a lut tag. The second colorant listed is the colorant of the second device channel
  2189. of a lut tag, and so on.
  2190. */
  2191. static
  2192. void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2193. {
  2194. cmsUInt32Number i, Count;
  2195. cmsNAMEDCOLORLIST* List;
  2196. char Name[34];
  2197. cmsUInt16Number PCS[3];
  2198. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  2199. if (Count > cmsMAXCHANNELS) {
  2200. cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
  2201. return NULL;
  2202. }
  2203. List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
  2204. for (i=0; i < Count; i++) {
  2205. if (io ->Read(io, Name, 32, 1) != 1) goto Error;
  2206. Name[33] = 0;
  2207. if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
  2208. if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
  2209. }
  2210. *nItems = 1;
  2211. return List;
  2212. Error:
  2213. *nItems = 0;
  2214. cmsFreeNamedColorList(List);
  2215. return NULL;
  2216. cmsUNUSED_PARAMETER(SizeOfTag);
  2217. }
  2218. // Saves a colorant table. It is using the named color structure for simplicity sake
  2219. static
  2220. cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2221. {
  2222. cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
  2223. int i, nColors;
  2224. nColors = cmsNamedColorCount(NamedColorList);
  2225. if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
  2226. for (i=0; i < nColors; i++) {
  2227. char root[33];
  2228. cmsUInt16Number PCS[3];
  2229. if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
  2230. root[32] = 0;
  2231. if (!io ->Write(io, 32, root)) return FALSE;
  2232. if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
  2233. }
  2234. return TRUE;
  2235. cmsUNUSED_PARAMETER(nItems);
  2236. cmsUNUSED_PARAMETER(self);
  2237. }
  2238. static
  2239. void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
  2240. {
  2241. cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
  2242. return (void*) cmsDupNamedColorList(nc);
  2243. cmsUNUSED_PARAMETER(n);
  2244. cmsUNUSED_PARAMETER(self);
  2245. }
  2246. static
  2247. void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2248. {
  2249. cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
  2250. return;
  2251. cmsUNUSED_PARAMETER(self);
  2252. }
  2253. // ********************************************************************************
  2254. // Type cmsSigNamedColor2Type
  2255. // ********************************************************************************
  2256. //
  2257. //The namedColor2Type is a count value and array of structures that provide color
  2258. //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
  2259. //device representation of the color are given. Both representations are 16-bit values.
  2260. //The device representation corresponds to the header’s “color space of data” field.
  2261. //This representation should be consistent with the “number of device components”
  2262. //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
  2263. //The PCS representation corresponds to the header’s PCS field. The PCS representation
  2264. //is always provided. Color names are fixed-length, 32-byte fields including null
  2265. //termination. In order to maintain maximum portability, it is strongly recommended
  2266. //that special characters of the 7-bit ASCII set not be used.
  2267. static
  2268. void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2269. {
  2270. cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
  2271. cmsUInt32Number count; // Count of named colors
  2272. cmsUInt32Number nDeviceCoords; // Num of device coordinates
  2273. char prefix[32]; // Prefix for each color name
  2274. char suffix[32]; // Suffix for each color name
  2275. cmsNAMEDCOLORLIST* v;
  2276. cmsUInt32Number i;
  2277. *nItems = 0;
  2278. if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
  2279. if (!_cmsReadUInt32Number(io, &count)) return NULL;
  2280. if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
  2281. if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
  2282. if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
  2283. prefix[31] = suffix[31] = 0;
  2284. v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
  2285. if (v == NULL) {
  2286. cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
  2287. return NULL;
  2288. }
  2289. if (nDeviceCoords > cmsMAXCHANNELS) {
  2290. cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
  2291. return 0;
  2292. }
  2293. for (i=0; i < count; i++) {
  2294. cmsUInt16Number PCS[3];
  2295. cmsUInt16Number Colorant[cmsMAXCHANNELS];
  2296. char Root[33];
  2297. memset(Colorant, 0, sizeof(Colorant));
  2298. if (io -> Read(io, Root, 32, 1) != 1) return NULL;
  2299. if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
  2300. if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
  2301. if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
  2302. }
  2303. *nItems = 1;
  2304. return (void*) v ;
  2305. Error:
  2306. cmsFreeNamedColorList(v);
  2307. return NULL;
  2308. cmsUNUSED_PARAMETER(SizeOfTag);
  2309. }
  2310. // Saves a named color list into a named color profile
  2311. static
  2312. cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2313. {
  2314. cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
  2315. char prefix[32]; // Prefix for each color name
  2316. char suffix[32]; // Suffix for each color name
  2317. int i, nColors;
  2318. nColors = cmsNamedColorCount(NamedColorList);
  2319. if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
  2320. if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
  2321. if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
  2322. strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
  2323. strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
  2324. suffix[31] = prefix[31] = 0;
  2325. if (!io ->Write(io, 32, prefix)) return FALSE;
  2326. if (!io ->Write(io, 32, suffix)) return FALSE;
  2327. for (i=0; i < nColors; i++) {
  2328. cmsUInt16Number PCS[3];
  2329. cmsUInt16Number Colorant[cmsMAXCHANNELS];
  2330. char Root[33];
  2331. if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
  2332. if (!io ->Write(io, 32 , Root)) return FALSE;
  2333. if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
  2334. if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
  2335. }
  2336. return TRUE;
  2337. cmsUNUSED_PARAMETER(nItems);
  2338. cmsUNUSED_PARAMETER(self);
  2339. }
  2340. static
  2341. void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
  2342. {
  2343. cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
  2344. return (void*) cmsDupNamedColorList(nc);
  2345. cmsUNUSED_PARAMETER(n);
  2346. cmsUNUSED_PARAMETER(self);
  2347. }
  2348. static
  2349. void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2350. {
  2351. cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
  2352. return;
  2353. cmsUNUSED_PARAMETER(self);
  2354. }
  2355. // ********************************************************************************
  2356. // Type cmsSigProfileSequenceDescType
  2357. // ********************************************************************************
  2358. // This type is an array of structures, each of which contains information from the
  2359. // header fields and tags from the original profiles which were combined to create
  2360. // the final profile. The order of the structures is the order in which the profiles
  2361. // were combined and includes a structure for the final profile. This provides a
  2362. // description of the profile sequence from source to destination,
  2363. // typically used with the DeviceLink profile.
  2364. static
  2365. cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
  2366. {
  2367. cmsTagTypeSignature BaseType;
  2368. cmsUInt32Number nItems;
  2369. BaseType = _cmsReadTypeBase(io);
  2370. switch (BaseType) {
  2371. case cmsSigTextType:
  2372. if (*mlu) cmsMLUfree(*mlu);
  2373. *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
  2374. return (*mlu != NULL);
  2375. case cmsSigTextDescriptionType:
  2376. if (*mlu) cmsMLUfree(*mlu);
  2377. *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
  2378. return (*mlu != NULL);
  2379. /*
  2380. TBD: Size is needed for MLU, and we have no idea on which is the available size
  2381. */
  2382. case cmsSigMultiLocalizedUnicodeType:
  2383. if (*mlu) cmsMLUfree(*mlu);
  2384. *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
  2385. return (*mlu != NULL);
  2386. default: return FALSE;
  2387. }
  2388. }
  2389. static
  2390. void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2391. {
  2392. cmsSEQ* OutSeq;
  2393. cmsUInt32Number i, Count;
  2394. *nItems = 0;
  2395. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  2396. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  2397. SizeOfTag -= sizeof(cmsUInt32Number);
  2398. OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
  2399. if (OutSeq == NULL) return NULL;
  2400. OutSeq ->n = Count;
  2401. // Get structures as well
  2402. for (i=0; i < Count; i++) {
  2403. cmsPSEQDESC* sec = &OutSeq -> seq[i];
  2404. if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error;
  2405. if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
  2406. SizeOfTag -= sizeof(cmsUInt32Number);
  2407. if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error;
  2408. if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
  2409. SizeOfTag -= sizeof(cmsUInt32Number);
  2410. if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
  2411. if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error;
  2412. SizeOfTag -= sizeof(cmsUInt64Number);
  2413. if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
  2414. if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
  2415. SizeOfTag -= sizeof(cmsUInt32Number);
  2416. if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error;
  2417. if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error;
  2418. }
  2419. *nItems = 1;
  2420. return OutSeq;
  2421. Error:
  2422. cmsFreeProfileSequenceDescription(OutSeq);
  2423. return NULL;
  2424. }
  2425. // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
  2426. // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
  2427. static
  2428. cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
  2429. {
  2430. if (self ->ICCVersion < 0x4000000) {
  2431. if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
  2432. return Type_Text_Description_Write(self, io, Text, 1);
  2433. }
  2434. else {
  2435. if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
  2436. return Type_MLU_Write(self, io, Text, 1);
  2437. }
  2438. }
  2439. static
  2440. cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2441. {
  2442. cmsSEQ* Seq = (cmsSEQ*) Ptr;
  2443. cmsUInt32Number i;
  2444. if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
  2445. for (i=0; i < Seq ->n; i++) {
  2446. cmsPSEQDESC* sec = &Seq -> seq[i];
  2447. if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
  2448. if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
  2449. if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
  2450. if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
  2451. if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
  2452. if (!SaveDescription(self, io, sec ->Model)) return FALSE;
  2453. }
  2454. return TRUE;
  2455. cmsUNUSED_PARAMETER(nItems);
  2456. }
  2457. static
  2458. void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
  2459. {
  2460. return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
  2461. cmsUNUSED_PARAMETER(n);
  2462. cmsUNUSED_PARAMETER(self);
  2463. }
  2464. static
  2465. void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2466. {
  2467. cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
  2468. return;
  2469. cmsUNUSED_PARAMETER(self);
  2470. }
  2471. // ********************************************************************************
  2472. // Type cmsSigProfileSequenceIdType
  2473. // ********************************************************************************
  2474. /*
  2475. In certain workflows using ICC Device Link Profiles, it is necessary to identify the
  2476. original profiles that were combined to create the Device Link Profile.
  2477. This type is an array of structures, each of which contains information for
  2478. identification of a profile used in a sequence
  2479. */
  2480. static
  2481. cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
  2482. cmsIOHANDLER* io,
  2483. void* Cargo,
  2484. cmsUInt32Number n,
  2485. cmsUInt32Number SizeOfTag)
  2486. {
  2487. cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
  2488. cmsPSEQDESC* seq = &OutSeq ->seq[n];
  2489. if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
  2490. if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
  2491. return TRUE;
  2492. }
  2493. static
  2494. void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2495. {
  2496. cmsSEQ* OutSeq;
  2497. cmsUInt32Number Count;
  2498. cmsUInt32Number BaseOffset;
  2499. *nItems = 0;
  2500. // Get actual position as a basis for element offsets
  2501. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  2502. // Get table count
  2503. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  2504. SizeOfTag -= sizeof(cmsUInt32Number);
  2505. // Allocate an empty structure
  2506. OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
  2507. if (OutSeq == NULL) return NULL;
  2508. // Read the position table
  2509. if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
  2510. cmsFreeProfileSequenceDescription(OutSeq);
  2511. return NULL;
  2512. }
  2513. // Success
  2514. *nItems = 1;
  2515. return OutSeq;
  2516. }
  2517. static
  2518. cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
  2519. cmsIOHANDLER* io,
  2520. void* Cargo,
  2521. cmsUInt32Number n,
  2522. cmsUInt32Number SizeOfTag)
  2523. {
  2524. cmsSEQ* Seq = (cmsSEQ*) Cargo;
  2525. if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
  2526. // Store here the MLU
  2527. if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
  2528. return TRUE;
  2529. cmsUNUSED_PARAMETER(SizeOfTag);
  2530. }
  2531. static
  2532. cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2533. {
  2534. cmsSEQ* Seq = (cmsSEQ*) Ptr;
  2535. cmsUInt32Number BaseOffset;
  2536. // Keep the base offset
  2537. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  2538. // This is the table count
  2539. if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
  2540. // This is the position table and content
  2541. if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
  2542. return TRUE;
  2543. cmsUNUSED_PARAMETER(nItems);
  2544. }
  2545. static
  2546. void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
  2547. {
  2548. return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
  2549. cmsUNUSED_PARAMETER(n);
  2550. cmsUNUSED_PARAMETER(self);
  2551. }
  2552. static
  2553. void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2554. {
  2555. cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
  2556. return;
  2557. cmsUNUSED_PARAMETER(self);
  2558. }
  2559. // ********************************************************************************
  2560. // Type cmsSigUcrBgType
  2561. // ********************************************************************************
  2562. /*
  2563. This type contains curves representing the under color removal and black
  2564. generation and a text string which is a general description of the method used
  2565. for the ucr/bg.
  2566. */
  2567. static
  2568. void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2569. {
  2570. cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
  2571. cmsUInt32Number CountUcr, CountBg;
  2572. char* ASCIIString;
  2573. *nItems = 0;
  2574. if (n == NULL) return NULL;
  2575. // First curve is Under color removal
  2576. if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
  2577. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  2578. SizeOfTag -= sizeof(cmsUInt32Number);
  2579. n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
  2580. if (n ->Ucr == NULL) return NULL;
  2581. if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
  2582. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  2583. SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
  2584. // Second curve is Black generation
  2585. if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
  2586. if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
  2587. SizeOfTag -= sizeof(cmsUInt32Number);
  2588. n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
  2589. if (n ->Bg == NULL) return NULL;
  2590. if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
  2591. if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
  2592. SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
  2593. if (SizeOfTag == UINT_MAX) return NULL;
  2594. // Now comes the text. The length is specified by the tag size
  2595. n ->Desc = cmsMLUalloc(self ->ContextID, 1);
  2596. if (n ->Desc == NULL) return NULL;
  2597. ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
  2598. if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
  2599. ASCIIString[SizeOfTag] = 0;
  2600. cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
  2601. _cmsFree(self ->ContextID, ASCIIString);
  2602. *nItems = 1;
  2603. return (void*) n;
  2604. }
  2605. static
  2606. cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2607. {
  2608. cmsUcrBg* Value = (cmsUcrBg*) Ptr;
  2609. cmsUInt32Number TextSize;
  2610. char* Text;
  2611. // First curve is Under color removal
  2612. if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
  2613. if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
  2614. // Then black generation
  2615. if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
  2616. if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
  2617. // Now comes the text. The length is specified by the tag size
  2618. TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
  2619. Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
  2620. if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
  2621. if (!io ->Write(io, TextSize, Text)) return FALSE;
  2622. _cmsFree(self ->ContextID, Text);
  2623. return TRUE;
  2624. cmsUNUSED_PARAMETER(nItems);
  2625. }
  2626. static
  2627. void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2628. {
  2629. cmsUcrBg* Src = (cmsUcrBg*) Ptr;
  2630. cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
  2631. if (NewUcrBg == NULL) return NULL;
  2632. NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
  2633. NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
  2634. NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
  2635. return (void*) NewUcrBg;
  2636. cmsUNUSED_PARAMETER(n);
  2637. }
  2638. static
  2639. void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
  2640. {
  2641. cmsUcrBg* Src = (cmsUcrBg*) Ptr;
  2642. if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
  2643. if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
  2644. if (Src ->Desc) cmsMLUfree(Src ->Desc);
  2645. _cmsFree(self ->ContextID, Ptr);
  2646. }
  2647. // ********************************************************************************
  2648. // Type cmsSigCrdInfoType
  2649. // ********************************************************************************
  2650. /*
  2651. This type contains the PostScript product name to which this profile corresponds
  2652. and the names of the companion CRDs. Recall that a single profile can generate
  2653. multiple CRDs. It is implemented as a MLU being the language code "PS" and then
  2654. country varies for each element:
  2655. nm: PostScript product name
  2656. #0: Rendering intent 0 CRD name
  2657. #1: Rendering intent 1 CRD name
  2658. #2: Rendering intent 2 CRD name
  2659. #3: Rendering intent 3 CRD name
  2660. */
  2661. // Auxiliar, read an string specified as count + string
  2662. static
  2663. cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
  2664. {
  2665. cmsUInt32Number Count;
  2666. char* Text;
  2667. if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
  2668. if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
  2669. if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
  2670. if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
  2671. Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
  2672. if (Text == NULL) return FALSE;
  2673. if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
  2674. _cmsFree(self ->ContextID, Text);
  2675. return FALSE;
  2676. }
  2677. Text[Count] = 0;
  2678. cmsMLUsetASCII(mlu, "PS", Section, Text);
  2679. _cmsFree(self ->ContextID, Text);
  2680. *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
  2681. return TRUE;
  2682. }
  2683. static
  2684. cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
  2685. {
  2686. cmsUInt32Number TextSize;
  2687. char* Text;
  2688. TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
  2689. Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
  2690. if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
  2691. if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
  2692. if (!io ->Write(io, TextSize, Text)) return FALSE;
  2693. _cmsFree(self ->ContextID, Text);
  2694. return TRUE;
  2695. }
  2696. static
  2697. void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2698. {
  2699. cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
  2700. *nItems = 0;
  2701. if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
  2702. if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
  2703. if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
  2704. if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
  2705. if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
  2706. *nItems = 1;
  2707. return (void*) mlu;
  2708. Error:
  2709. cmsMLUfree(mlu);
  2710. return NULL;
  2711. }
  2712. static
  2713. cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2714. {
  2715. cmsMLU* mlu = (cmsMLU*) Ptr;
  2716. if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
  2717. if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
  2718. if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
  2719. if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
  2720. if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
  2721. return TRUE;
  2722. Error:
  2723. return FALSE;
  2724. cmsUNUSED_PARAMETER(nItems);
  2725. }
  2726. static
  2727. void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2728. {
  2729. return (void*) cmsMLUdup((cmsMLU*) Ptr);
  2730. cmsUNUSED_PARAMETER(n);
  2731. cmsUNUSED_PARAMETER(self);
  2732. }
  2733. static
  2734. void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
  2735. {
  2736. cmsMLUfree((cmsMLU*) Ptr);
  2737. return;
  2738. cmsUNUSED_PARAMETER(self);
  2739. }
  2740. // ********************************************************************************
  2741. // Type cmsSigScreeningType
  2742. // ********************************************************************************
  2743. //
  2744. //The screeningType describes various screening parameters including screen
  2745. //frequency, screening angle, and spot shape.
  2746. static
  2747. void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2748. {
  2749. cmsScreening* sc = NULL;
  2750. cmsUInt32Number i;
  2751. sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
  2752. if (sc == NULL) return NULL;
  2753. *nItems = 0;
  2754. if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
  2755. if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
  2756. if (sc ->nChannels > cmsMAXCHANNELS - 1)
  2757. sc ->nChannels = cmsMAXCHANNELS - 1;
  2758. for (i=0; i < sc ->nChannels; i++) {
  2759. if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
  2760. if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
  2761. if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
  2762. }
  2763. *nItems = 1;
  2764. return (void*) sc;
  2765. Error:
  2766. if (sc != NULL)
  2767. _cmsFree(self ->ContextID, sc);
  2768. return NULL;
  2769. cmsUNUSED_PARAMETER(SizeOfTag);
  2770. }
  2771. static
  2772. cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2773. {
  2774. cmsScreening* sc = (cmsScreening* ) Ptr;
  2775. cmsUInt32Number i;
  2776. if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
  2777. if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
  2778. for (i=0; i < sc ->nChannels; i++) {
  2779. if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
  2780. if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
  2781. if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
  2782. }
  2783. return TRUE;
  2784. cmsUNUSED_PARAMETER(nItems);
  2785. cmsUNUSED_PARAMETER(self);
  2786. }
  2787. static
  2788. void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2789. {
  2790. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
  2791. cmsUNUSED_PARAMETER(n);
  2792. }
  2793. static
  2794. void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2795. {
  2796. _cmsFree(self ->ContextID, Ptr);
  2797. }
  2798. // ********************************************************************************
  2799. // Type cmsSigViewingConditionsType
  2800. // ********************************************************************************
  2801. //
  2802. //This type represents a set of viewing condition parameters including:
  2803. //CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’
  2804. //surround tristimulus values.
  2805. static
  2806. void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2807. {
  2808. cmsICCViewingConditions* vc = NULL;
  2809. vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
  2810. if (vc == NULL) return NULL;
  2811. *nItems = 0;
  2812. if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
  2813. if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
  2814. if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
  2815. *nItems = 1;
  2816. return (void*) vc;
  2817. Error:
  2818. if (vc != NULL)
  2819. _cmsFree(self ->ContextID, vc);
  2820. return NULL;
  2821. cmsUNUSED_PARAMETER(SizeOfTag);
  2822. }
  2823. static
  2824. cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  2825. {
  2826. cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
  2827. if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
  2828. if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
  2829. if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
  2830. return TRUE;
  2831. cmsUNUSED_PARAMETER(nItems);
  2832. cmsUNUSED_PARAMETER(self);
  2833. }
  2834. static
  2835. void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2836. {
  2837. return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
  2838. cmsUNUSED_PARAMETER(n);
  2839. }
  2840. static
  2841. void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
  2842. {
  2843. _cmsFree(self ->ContextID, Ptr);
  2844. }
  2845. // ********************************************************************************
  2846. // Type cmsSigMultiProcessElementType
  2847. // ********************************************************************************
  2848. static
  2849. void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  2850. {
  2851. return (void*) cmsStageDup((cmsStage*) Ptr);
  2852. cmsUNUSED_PARAMETER(n);
  2853. cmsUNUSED_PARAMETER(self);
  2854. }
  2855. static
  2856. void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
  2857. {
  2858. cmsStageFree((cmsStage*) Ptr);
  2859. return;
  2860. cmsUNUSED_PARAMETER(self);
  2861. }
  2862. // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
  2863. // The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The
  2864. // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
  2865. // specified either in terms of a formula, or by a sampled curve.
  2866. // Read an embedded segmented curve
  2867. static
  2868. cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
  2869. {
  2870. cmsCurveSegSignature ElementSig;
  2871. cmsUInt32Number i, j;
  2872. cmsUInt16Number nSegments;
  2873. cmsCurveSegment* Segments;
  2874. cmsToneCurve* Curve;
  2875. cmsFloat32Number PrevBreak = -1E22F; // - infinite
  2876. // Take signature and channels for each element.
  2877. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
  2878. // That should be a segmented curve
  2879. if (ElementSig != cmsSigSegmentedCurve) return NULL;
  2880. if (!_cmsReadUInt32Number(io, NULL)) return NULL;
  2881. if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
  2882. if (!_cmsReadUInt16Number(io, NULL)) return NULL;
  2883. if (nSegments < 1) return NULL;
  2884. Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
  2885. if (Segments == NULL) return NULL;
  2886. // Read breakpoints
  2887. for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
  2888. Segments[i].x0 = PrevBreak;
  2889. if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
  2890. PrevBreak = Segments[i].x1;
  2891. }
  2892. Segments[nSegments-1].x0 = PrevBreak;
  2893. Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number
  2894. // Read segments
  2895. for (i=0; i < nSegments; i++) {
  2896. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
  2897. if (!_cmsReadUInt32Number(io, NULL)) goto Error;
  2898. switch (ElementSig) {
  2899. case cmsSigFormulaCurveSeg: {
  2900. cmsUInt16Number Type;
  2901. cmsUInt32Number ParamsByType[] = {4, 5, 5 };
  2902. if (!_cmsReadUInt16Number(io, &Type)) goto Error;
  2903. if (!_cmsReadUInt16Number(io, NULL)) goto Error;
  2904. Segments[i].Type = Type + 6;
  2905. if (Type > 2) goto Error;
  2906. for (j=0; j < ParamsByType[Type]; j++) {
  2907. cmsFloat32Number f;
  2908. if (!_cmsReadFloat32Number(io, &f)) goto Error;
  2909. Segments[i].Params[j] = f;
  2910. }
  2911. }
  2912. break;
  2913. case cmsSigSampledCurveSeg: {
  2914. cmsUInt32Number Count;
  2915. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  2916. Segments[i].nGridPoints = Count;
  2917. Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
  2918. if (Segments[i].SampledPoints == NULL) goto Error;
  2919. for (j=0; j < Count; j++) {
  2920. if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
  2921. }
  2922. }
  2923. break;
  2924. default:
  2925. {
  2926. char String[5];
  2927. _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
  2928. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
  2929. }
  2930. return NULL;
  2931. }
  2932. }
  2933. Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
  2934. for (i=0; i < nSegments; i++) {
  2935. if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
  2936. }
  2937. _cmsFree(self ->ContextID, Segments);
  2938. return Curve;
  2939. Error:
  2940. if (Segments) _cmsFree(self ->ContextID, Segments);
  2941. return NULL;
  2942. }
  2943. static
  2944. cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
  2945. cmsIOHANDLER* io,
  2946. void* Cargo,
  2947. cmsUInt32Number n,
  2948. cmsUInt32Number SizeOfTag)
  2949. {
  2950. cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
  2951. GammaTables[n] = ReadSegmentedCurve(self, io);
  2952. return (GammaTables[n] != NULL);
  2953. cmsUNUSED_PARAMETER(SizeOfTag);
  2954. }
  2955. static
  2956. void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  2957. {
  2958. cmsStage* mpe = NULL;
  2959. cmsUInt16Number InputChans, OutputChans;
  2960. cmsUInt32Number i, BaseOffset;
  2961. cmsToneCurve** GammaTables;
  2962. *nItems = 0;
  2963. // Get actual position as a basis for element offsets
  2964. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  2965. if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
  2966. if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
  2967. if (InputChans != OutputChans) return NULL;
  2968. GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
  2969. if (GammaTables == NULL) return NULL;
  2970. if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
  2971. mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
  2972. }
  2973. else {
  2974. mpe = NULL;
  2975. }
  2976. for (i=0; i < InputChans; i++) {
  2977. if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
  2978. }
  2979. _cmsFree(self ->ContextID, GammaTables);
  2980. *nItems = (mpe != NULL) ? 1 : 0;
  2981. return mpe;
  2982. cmsUNUSED_PARAMETER(SizeOfTag);
  2983. }
  2984. // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
  2985. static
  2986. cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
  2987. {
  2988. cmsUInt32Number i, j;
  2989. cmsCurveSegment* Segments = g ->Segments;
  2990. cmsUInt32Number nSegments = g ->nSegments;
  2991. if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
  2992. if (!_cmsWriteUInt32Number(io, 0)) goto Error;
  2993. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
  2994. if (!_cmsWriteUInt16Number(io, 0)) goto Error;
  2995. // Write the break-points
  2996. for (i=0; i < nSegments - 1; i++) {
  2997. if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
  2998. }
  2999. // Write the segments
  3000. for (i=0; i < g ->nSegments; i++) {
  3001. cmsCurveSegment* ActualSeg = Segments + i;
  3002. if (ActualSeg -> Type == 0) {
  3003. // This is a sampled curve
  3004. if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
  3005. if (!_cmsWriteUInt32Number(io, 0)) goto Error;
  3006. if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
  3007. for (j=0; j < g ->Segments[i].nGridPoints; j++) {
  3008. if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
  3009. }
  3010. }
  3011. else {
  3012. int Type;
  3013. cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
  3014. // This is a formula-based
  3015. if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
  3016. if (!_cmsWriteUInt32Number(io, 0)) goto Error;
  3017. // We only allow 1, 2 and 3 as types
  3018. Type = ActualSeg ->Type - 6;
  3019. if (Type > 2 || Type < 0) goto Error;
  3020. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
  3021. if (!_cmsWriteUInt16Number(io, 0)) goto Error;
  3022. for (j=0; j < ParamsByType[Type]; j++) {
  3023. if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
  3024. }
  3025. }
  3026. // It seems there is no need to align. Code is here, and for safety commented out
  3027. // if (!_cmsWriteAlignment(io)) goto Error;
  3028. }
  3029. return TRUE;
  3030. Error:
  3031. return FALSE;
  3032. }
  3033. static
  3034. cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
  3035. cmsIOHANDLER* io,
  3036. void* Cargo,
  3037. cmsUInt32Number n,
  3038. cmsUInt32Number SizeOfTag)
  3039. {
  3040. _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
  3041. return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
  3042. cmsUNUSED_PARAMETER(SizeOfTag);
  3043. cmsUNUSED_PARAMETER(self);
  3044. }
  3045. // Write a curve, checking first for validity
  3046. static
  3047. cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3048. {
  3049. cmsUInt32Number BaseOffset;
  3050. cmsStage* mpe = (cmsStage*) Ptr;
  3051. _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
  3052. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  3053. // Write the header. Since those are curves, input and output channels are same
  3054. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
  3055. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
  3056. if (!WritePositionTable(self, io, 0,
  3057. mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
  3058. return TRUE;
  3059. cmsUNUSED_PARAMETER(nItems);
  3060. }
  3061. // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
  3062. // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
  3063. // is organized as follows:
  3064. // array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ]
  3065. static
  3066. void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  3067. {
  3068. cmsStage* mpe;
  3069. cmsUInt16Number InputChans, OutputChans;
  3070. cmsUInt32Number nElems, i;
  3071. cmsFloat64Number* Matrix;
  3072. cmsFloat64Number* Offsets;
  3073. if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
  3074. if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
  3075. nElems = InputChans * OutputChans;
  3076. // Input and output chans may be ANY (up to 0xffff)
  3077. Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
  3078. if (Matrix == NULL) return NULL;
  3079. Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
  3080. if (Offsets == NULL) {
  3081. _cmsFree(self ->ContextID, Matrix);
  3082. return NULL;
  3083. }
  3084. for (i=0; i < nElems; i++) {
  3085. cmsFloat32Number v;
  3086. if (!_cmsReadFloat32Number(io, &v)) return NULL;
  3087. Matrix[i] = v;
  3088. }
  3089. for (i=0; i < OutputChans; i++) {
  3090. cmsFloat32Number v;
  3091. if (!_cmsReadFloat32Number(io, &v)) return NULL;
  3092. Offsets[i] = v;
  3093. }
  3094. mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
  3095. _cmsFree(self ->ContextID, Matrix);
  3096. _cmsFree(self ->ContextID, Offsets);
  3097. *nItems = 1;
  3098. return mpe;
  3099. cmsUNUSED_PARAMETER(SizeOfTag);
  3100. }
  3101. static
  3102. cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3103. {
  3104. cmsUInt32Number i, nElems;
  3105. cmsStage* mpe = (cmsStage*) Ptr;
  3106. _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
  3107. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
  3108. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
  3109. nElems = mpe ->InputChannels * mpe ->OutputChannels;
  3110. for (i=0; i < nElems; i++) {
  3111. if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
  3112. }
  3113. for (i=0; i < mpe ->OutputChannels; i++) {
  3114. if (Matrix ->Offset == NULL) {
  3115. if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
  3116. }
  3117. else {
  3118. if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
  3119. }
  3120. }
  3121. return TRUE;
  3122. cmsUNUSED_PARAMETER(nItems);
  3123. cmsUNUSED_PARAMETER(self);
  3124. }
  3125. static
  3126. void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  3127. {
  3128. cmsStage* mpe = NULL;
  3129. cmsUInt16Number InputChans, OutputChans;
  3130. cmsUInt8Number Dimensions8[16];
  3131. cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
  3132. _cmsStageCLutData* clut;
  3133. if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
  3134. if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
  3135. if (InputChans == 0) goto Error;
  3136. if (OutputChans == 0) goto Error;
  3137. if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
  3138. goto Error;
  3139. // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
  3140. nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
  3141. for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
  3142. // Allocate the true CLUT
  3143. mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
  3144. if (mpe == NULL) goto Error;
  3145. // Read the data
  3146. clut = (_cmsStageCLutData*) mpe ->Data;
  3147. for (i=0; i < clut ->nEntries; i++) {
  3148. if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
  3149. }
  3150. *nItems = 1;
  3151. return mpe;
  3152. Error:
  3153. *nItems = 0;
  3154. if (mpe != NULL) cmsStageFree(mpe);
  3155. return NULL;
  3156. cmsUNUSED_PARAMETER(SizeOfTag);
  3157. }
  3158. // Write a CLUT in floating point
  3159. static
  3160. cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3161. {
  3162. cmsUInt8Number Dimensions8[16];
  3163. cmsUInt32Number i;
  3164. cmsStage* mpe = (cmsStage*) Ptr;
  3165. _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
  3166. // Check for maximum number of channels
  3167. if (mpe -> InputChannels > 15) return FALSE;
  3168. // Only floats are supported in MPE
  3169. if (clut ->HasFloatValues == FALSE) return FALSE;
  3170. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
  3171. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
  3172. memset(Dimensions8, 0, sizeof(Dimensions8));
  3173. for (i=0; i < mpe ->InputChannels; i++)
  3174. Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
  3175. if (!io ->Write(io, 16, Dimensions8)) return FALSE;
  3176. for (i=0; i < clut ->nEntries; i++) {
  3177. if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
  3178. }
  3179. return TRUE;
  3180. cmsUNUSED_PARAMETER(nItems);
  3181. cmsUNUSED_PARAMETER(self);
  3182. }
  3183. // This is the list of built-in MPE types
  3184. static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
  3185. {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
  3186. {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
  3187. {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
  3188. {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
  3189. {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
  3190. };
  3191. #define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList))
  3192. static
  3193. cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
  3194. cmsIOHANDLER* io,
  3195. void* Cargo,
  3196. cmsUInt32Number n,
  3197. cmsUInt32Number SizeOfTag)
  3198. {
  3199. cmsStageSignature ElementSig;
  3200. cmsTagTypeHandler* TypeHandler;
  3201. cmsUInt32Number nItems;
  3202. cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
  3203. // Take signature and channels for each element.
  3204. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
  3205. // The reserved placeholder
  3206. if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
  3207. // Read diverse MPE types
  3208. TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
  3209. if (TypeHandler == NULL) {
  3210. char String[5];
  3211. _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
  3212. // An unknown element was found.
  3213. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
  3214. return FALSE;
  3215. }
  3216. // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
  3217. // Read the MPE. No size is given
  3218. if (TypeHandler ->ReadPtr != NULL) {
  3219. // This is a real element which should be read and processed
  3220. if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
  3221. return FALSE;
  3222. }
  3223. return TRUE;
  3224. cmsUNUSED_PARAMETER(SizeOfTag);
  3225. cmsUNUSED_PARAMETER(n);
  3226. }
  3227. // This is the main dispatcher for MPE
  3228. static
  3229. void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  3230. {
  3231. cmsUInt16Number InputChans, OutputChans;
  3232. cmsUInt32Number ElementCount;
  3233. cmsPipeline *NewLUT = NULL;
  3234. cmsUInt32Number BaseOffset;
  3235. // Get actual position as a basis for element offsets
  3236. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  3237. // Read channels and element count
  3238. if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
  3239. if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
  3240. // Allocates an empty LUT
  3241. NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
  3242. if (NewLUT == NULL) return NULL;
  3243. if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
  3244. if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
  3245. if (NewLUT != NULL) cmsPipelineFree(NewLUT);
  3246. *nItems = 0;
  3247. return NULL;
  3248. }
  3249. // Success
  3250. *nItems = 1;
  3251. return NewLUT;
  3252. cmsUNUSED_PARAMETER(SizeOfTag);
  3253. }
  3254. // This one is a liitle bit more complex, so we don't use position tables this time.
  3255. static
  3256. cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3257. {
  3258. cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
  3259. int inputChan, outputChan;
  3260. cmsUInt32Number ElemCount;
  3261. cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
  3262. cmsStageSignature ElementSig;
  3263. cmsPipeline* Lut = (cmsPipeline*) Ptr;
  3264. cmsStage* Elem = Lut ->Elements;
  3265. cmsTagTypeHandler* TypeHandler;
  3266. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  3267. inputChan = cmsPipelineInputChannels(Lut);
  3268. outputChan = cmsPipelineOutputChannels(Lut);
  3269. ElemCount = cmsPipelineStageCount(Lut);
  3270. ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
  3271. if (ElementOffsets == NULL) goto Error;
  3272. ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
  3273. if (ElementSizes == NULL) goto Error;
  3274. // Write the head
  3275. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
  3276. if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
  3277. if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
  3278. DirectoryPos = io ->Tell(io);
  3279. // Write a fake directory to be filled latter on
  3280. for (i=0; i < ElemCount; i++) {
  3281. if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
  3282. if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
  3283. }
  3284. // Write each single tag. Keep track of the size as well.
  3285. for (i=0; i < ElemCount; i++) {
  3286. ElementOffsets[i] = io ->Tell(io) - BaseOffset;
  3287. ElementSig = Elem ->Type;
  3288. TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
  3289. if (TypeHandler == NULL) {
  3290. char String[5];
  3291. _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
  3292. // An unknow element was found.
  3293. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
  3294. goto Error;
  3295. }
  3296. if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
  3297. if (!_cmsWriteUInt32Number(io, 0)) goto Error;
  3298. Before = io ->Tell(io);
  3299. if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
  3300. if (!_cmsWriteAlignment(io)) goto Error;
  3301. ElementSizes[i] = io ->Tell(io) - Before;
  3302. Elem = Elem ->Next;
  3303. }
  3304. // Write the directory
  3305. CurrentPos = io ->Tell(io);
  3306. if (!io ->Seek(io, DirectoryPos)) goto Error;
  3307. for (i=0; i < ElemCount; i++) {
  3308. if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
  3309. if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
  3310. }
  3311. if (!io ->Seek(io, CurrentPos)) goto Error;
  3312. if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
  3313. if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
  3314. return TRUE;
  3315. Error:
  3316. if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
  3317. if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
  3318. return FALSE;
  3319. cmsUNUSED_PARAMETER(nItems);
  3320. }
  3321. static
  3322. void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  3323. {
  3324. return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
  3325. cmsUNUSED_PARAMETER(n);
  3326. cmsUNUSED_PARAMETER(self);
  3327. }
  3328. static
  3329. void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
  3330. {
  3331. cmsPipelineFree((cmsPipeline*) Ptr);
  3332. return;
  3333. cmsUNUSED_PARAMETER(self);
  3334. }
  3335. // ********************************************************************************
  3336. // Type cmsSigVcgtType
  3337. // ********************************************************************************
  3338. #define cmsVideoCardGammaTableType 0
  3339. #define cmsVideoCardGammaFormulaType 1
  3340. // Used internally
  3341. typedef struct {
  3342. double Gamma;
  3343. double Min;
  3344. double Max;
  3345. } _cmsVCGTGAMMA;
  3346. static
  3347. void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
  3348. cmsIOHANDLER* io,
  3349. cmsUInt32Number* nItems,
  3350. cmsUInt32Number SizeOfTag)
  3351. {
  3352. cmsUInt32Number TagType, n, i;
  3353. cmsToneCurve** Curves;
  3354. *nItems = 0;
  3355. // Read tag type
  3356. if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
  3357. // Allocate space for the array
  3358. Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
  3359. if (Curves == NULL) return NULL;
  3360. // There are two possible flavors
  3361. switch (TagType) {
  3362. // Gamma is stored as a table
  3363. case cmsVideoCardGammaTableType:
  3364. {
  3365. cmsUInt16Number nChannels, nElems, nBytes;
  3366. // Check channel count, which should be 3 (we don't support monochrome this time)
  3367. if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
  3368. if (nChannels != 3) {
  3369. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
  3370. goto Error;
  3371. }
  3372. // Get Table element count and bytes per element
  3373. if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
  3374. if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
  3375. // Adobe's quirk fixup. Fixing broken profiles...
  3376. if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
  3377. nBytes = 2;
  3378. // Populate tone curves
  3379. for (n=0; n < 3; n++) {
  3380. Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
  3381. if (Curves[n] == NULL) goto Error;
  3382. // On depending on byte depth
  3383. switch (nBytes) {
  3384. // One byte, 0..255
  3385. case 1:
  3386. for (i=0; i < nElems; i++) {
  3387. cmsUInt8Number v;
  3388. if (!_cmsReadUInt8Number(io, &v)) goto Error;
  3389. Curves[n] ->Table16[i] = FROM_8_TO_16(v);
  3390. }
  3391. break;
  3392. // One word 0..65535
  3393. case 2:
  3394. if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
  3395. break;
  3396. // Unsupported
  3397. default:
  3398. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
  3399. goto Error;
  3400. }
  3401. } // For all 3 channels
  3402. }
  3403. break;
  3404. // In this case, gamma is stored as a formula
  3405. case cmsVideoCardGammaFormulaType:
  3406. {
  3407. _cmsVCGTGAMMA Colorant[3];
  3408. // Populate tone curves
  3409. for (n=0; n < 3; n++) {
  3410. double Params[10];
  3411. if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
  3412. if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
  3413. if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
  3414. // Parametric curve type 5 is:
  3415. // Y = (aX + b)^Gamma + e | X >= d
  3416. // Y = cX + f | X < d
  3417. // vcgt formula is:
  3418. // Y = (Max – Min) * (X ^ Gamma) + Min
  3419. // So, the translation is
  3420. // a = (Max – Min) ^ ( 1 / Gamma)
  3421. // e = Min
  3422. // b=c=d=f=0
  3423. Params[0] = Colorant[n].Gamma;
  3424. Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
  3425. Params[2] = 0;
  3426. Params[3] = 0;
  3427. Params[4] = 0;
  3428. Params[5] = Colorant[n].Min;
  3429. Params[6] = 0;
  3430. Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
  3431. if (Curves[n] == NULL) goto Error;
  3432. }
  3433. }
  3434. break;
  3435. // Unsupported
  3436. default:
  3437. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
  3438. goto Error;
  3439. }
  3440. *nItems = 1;
  3441. return (void*) Curves;
  3442. // Regret, free all resources
  3443. Error:
  3444. cmsFreeToneCurveTriple(Curves);
  3445. _cmsFree(self ->ContextID, Curves);
  3446. return NULL;
  3447. cmsUNUSED_PARAMETER(SizeOfTag);
  3448. }
  3449. // We don't support all flavors, only 16bits tables and formula
  3450. static
  3451. cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3452. {
  3453. cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
  3454. cmsUInt32Number i, j;
  3455. if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
  3456. cmsGetToneCurveParametricType(Curves[1]) == 5 &&
  3457. cmsGetToneCurveParametricType(Curves[2]) == 5) {
  3458. if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
  3459. // Save parameters
  3460. for (i=0; i < 3; i++) {
  3461. _cmsVCGTGAMMA v;
  3462. v.Gamma = Curves[i] ->Segments[0].Params[0];
  3463. v.Min = Curves[i] ->Segments[0].Params[5];
  3464. v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
  3465. if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
  3466. if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
  3467. if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
  3468. }
  3469. }
  3470. else {
  3471. // Always store as a table of 256 words
  3472. if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
  3473. if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
  3474. if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
  3475. if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
  3476. for (i=0; i < 3; i++) {
  3477. for (j=0; j < 256; j++) {
  3478. cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
  3479. cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
  3480. if (!_cmsWriteUInt16Number(io, n)) return FALSE;
  3481. }
  3482. }
  3483. }
  3484. return TRUE;
  3485. cmsUNUSED_PARAMETER(self);
  3486. cmsUNUSED_PARAMETER(nItems);
  3487. }
  3488. static
  3489. void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  3490. {
  3491. cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
  3492. cmsToneCurve** NewCurves;
  3493. NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
  3494. if (NewCurves == NULL) return NULL;
  3495. NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
  3496. NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
  3497. NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
  3498. return (void*) NewCurves;
  3499. cmsUNUSED_PARAMETER(n);
  3500. }
  3501. static
  3502. void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
  3503. {
  3504. cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
  3505. _cmsFree(self ->ContextID, Ptr);
  3506. }
  3507. // ********************************************************************************
  3508. // Type cmsSigDictType
  3509. // ********************************************************************************
  3510. // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
  3511. typedef struct {
  3512. cmsContext ContextID;
  3513. cmsUInt32Number *Offsets;
  3514. cmsUInt32Number *Sizes;
  3515. } _cmsDICelem;
  3516. typedef struct {
  3517. _cmsDICelem Name, Value, DisplayName, DisplayValue;
  3518. } _cmsDICarray;
  3519. // Allocate an empty array element
  3520. static
  3521. cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count)
  3522. {
  3523. e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
  3524. if (e->Offsets == NULL) return FALSE;
  3525. e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
  3526. if (e->Sizes == NULL) {
  3527. _cmsFree(ContextID, e -> Offsets);
  3528. return FALSE;
  3529. }
  3530. e ->ContextID = ContextID;
  3531. return TRUE;
  3532. }
  3533. // Free an array element
  3534. static
  3535. void FreeElem(_cmsDICelem* e)
  3536. {
  3537. if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets);
  3538. if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes);
  3539. e->Offsets = e ->Sizes = NULL;
  3540. }
  3541. // Get rid of whole array
  3542. static
  3543. void FreeArray( _cmsDICarray* a)
  3544. {
  3545. if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
  3546. if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
  3547. if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
  3548. if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
  3549. }
  3550. // Allocate whole array
  3551. static
  3552. cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
  3553. {
  3554. // Empty values
  3555. memset(a, 0, sizeof(_cmsDICarray));
  3556. // On depending on record size, create column arrays
  3557. if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
  3558. if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
  3559. if (Length > 16) {
  3560. if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
  3561. }
  3562. if (Length > 24) {
  3563. if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
  3564. }
  3565. return TRUE;
  3566. Error:
  3567. FreeArray(a);
  3568. return FALSE;
  3569. }
  3570. // Read one element
  3571. static
  3572. cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
  3573. {
  3574. if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
  3575. if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
  3576. // An offset of zero has special meaning and shal be preserved
  3577. if (e ->Offsets[i] > 0)
  3578. e ->Offsets[i] += BaseOffset;
  3579. return TRUE;
  3580. }
  3581. static
  3582. cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
  3583. {
  3584. cmsUInt32Number i;
  3585. // Read column arrays
  3586. for (i=0; i < Count; i++) {
  3587. if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
  3588. if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
  3589. if (Length > 16) {
  3590. if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
  3591. }
  3592. if (Length > 24) {
  3593. if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
  3594. }
  3595. }
  3596. return TRUE;
  3597. }
  3598. // Write one element
  3599. static
  3600. cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i)
  3601. {
  3602. if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
  3603. if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
  3604. return TRUE;
  3605. }
  3606. static
  3607. cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
  3608. {
  3609. cmsUInt32Number i;
  3610. for (i=0; i < Count; i++) {
  3611. if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
  3612. if (!WriteOneElem(io, &a -> Value, i)) return FALSE;
  3613. if (Length > 16) {
  3614. if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE;
  3615. }
  3616. if (Length > 24) {
  3617. if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE;
  3618. }
  3619. }
  3620. return TRUE;
  3621. }
  3622. static
  3623. cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
  3624. {
  3625. cmsUInt32Number nChars;
  3626. // Special case for undefined strings (see ICC Votable
  3627. // Proposal Submission, Dictionary Type and Metadata TAG Definition)
  3628. if (e -> Offsets[i] == 0) {
  3629. *wcstr = NULL;
  3630. return TRUE;
  3631. }
  3632. if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
  3633. nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
  3634. *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
  3635. if (*wcstr == NULL) return FALSE;
  3636. if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
  3637. _cmsFree(e ->ContextID, *wcstr);
  3638. return FALSE;
  3639. }
  3640. // End of string marker
  3641. (*wcstr)[nChars] = 0;
  3642. return TRUE;
  3643. }
  3644. static
  3645. cmsUInt32Number mywcslen(const wchar_t *s)
  3646. {
  3647. const wchar_t *p;
  3648. p = s;
  3649. while (*p)
  3650. p++;
  3651. return (cmsUInt32Number)(p - s);
  3652. }
  3653. static
  3654. cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
  3655. {
  3656. cmsUInt32Number Before = io ->Tell(io);
  3657. cmsUInt32Number n;
  3658. e ->Offsets[i] = Before - BaseOffset;
  3659. if (wcstr == NULL) {
  3660. e ->Sizes[i] = 0;
  3661. e ->Offsets[i] = 0;
  3662. return TRUE;
  3663. }
  3664. n = mywcslen(wcstr);
  3665. if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE;
  3666. e ->Sizes[i] = io ->Tell(io) - Before;
  3667. return TRUE;
  3668. }
  3669. static
  3670. cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
  3671. {
  3672. cmsUInt32Number nItems = 0;
  3673. // A way to get null MLUCs
  3674. if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
  3675. *mlu = NULL;
  3676. return TRUE;
  3677. }
  3678. if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
  3679. *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
  3680. return *mlu != NULL;
  3681. }
  3682. static
  3683. cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
  3684. {
  3685. cmsUInt32Number Before;
  3686. // Special case for undefined strings (see ICC Votable
  3687. // Proposal Submission, Dictionary Type and Metadata TAG Definition)
  3688. if (mlu == NULL) {
  3689. e ->Sizes[i] = 0;
  3690. e ->Offsets[i] = 0;
  3691. return TRUE;
  3692. }
  3693. Before = io ->Tell(io);
  3694. e ->Offsets[i] = Before - BaseOffset;
  3695. if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
  3696. e ->Sizes[i] = io ->Tell(io) - Before;
  3697. return TRUE;
  3698. }
  3699. static
  3700. void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
  3701. {
  3702. cmsHANDLE hDict;
  3703. cmsUInt32Number i, Count, Length;
  3704. cmsUInt32Number BaseOffset;
  3705. _cmsDICarray a;
  3706. wchar_t *NameWCS = NULL, *ValueWCS = NULL;
  3707. cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
  3708. cmsBool rc;
  3709. *nItems = 0;
  3710. // Get actual position as a basis for element offsets
  3711. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  3712. // Get name-value record count
  3713. if (!_cmsReadUInt32Number(io, &Count)) return NULL;
  3714. SizeOfTag -= sizeof(cmsUInt32Number);
  3715. // Get rec length
  3716. if (!_cmsReadUInt32Number(io, &Length)) return NULL;
  3717. SizeOfTag -= sizeof(cmsUInt32Number);
  3718. // Check for valid lengths
  3719. if (Length != 16 && Length != 24 && Length != 32) {
  3720. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
  3721. return NULL;
  3722. }
  3723. // Creates an empty dictionary
  3724. hDict = cmsDictAlloc(self -> ContextID);
  3725. if (hDict == NULL) return NULL;
  3726. // On depending on record size, create column arrays
  3727. if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
  3728. // Read column arrays
  3729. if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
  3730. // Seek to each element and read it
  3731. for (i=0; i < Count; i++) {
  3732. if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
  3733. if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
  3734. if (Length > 16) {
  3735. if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
  3736. }
  3737. if (Length > 24) {
  3738. if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
  3739. }
  3740. if (NameWCS == NULL || ValueWCS == NULL) {
  3741. cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value");
  3742. rc = FALSE;
  3743. }
  3744. else {
  3745. rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
  3746. }
  3747. if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
  3748. if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
  3749. if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
  3750. if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
  3751. if (!rc) goto Error;
  3752. }
  3753. FreeArray(&a);
  3754. *nItems = 1;
  3755. return (void*) hDict;
  3756. Error:
  3757. FreeArray(&a);
  3758. cmsDictFree(hDict);
  3759. return NULL;
  3760. }
  3761. static
  3762. cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
  3763. {
  3764. cmsHANDLE hDict = (cmsHANDLE) Ptr;
  3765. const cmsDICTentry* p;
  3766. cmsBool AnyName, AnyValue;
  3767. cmsUInt32Number i, Count, Length;
  3768. cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
  3769. _cmsDICarray a;
  3770. if (hDict == NULL) return FALSE;
  3771. BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
  3772. // Let's inspect the dictionary
  3773. Count = 0; AnyName = FALSE; AnyValue = FALSE;
  3774. for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
  3775. if (p ->DisplayName != NULL) AnyName = TRUE;
  3776. if (p ->DisplayValue != NULL) AnyValue = TRUE;
  3777. Count++;
  3778. }
  3779. Length = 16;
  3780. if (AnyName) Length += 8;
  3781. if (AnyValue) Length += 8;
  3782. if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
  3783. if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
  3784. // Keep starting position of offsets table
  3785. DirectoryPos = io ->Tell(io);
  3786. // Allocate offsets array
  3787. if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
  3788. // Write a fake directory to be filled latter on
  3789. if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
  3790. // Write each element. Keep track of the size as well.
  3791. p = cmsDictGetEntryList(hDict);
  3792. for (i=0; i < Count; i++) {
  3793. if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error;
  3794. if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
  3795. if (p ->DisplayName != NULL) {
  3796. if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
  3797. }
  3798. if (p ->DisplayValue != NULL) {
  3799. if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
  3800. }
  3801. p = cmsDictNextEntry(p);
  3802. }
  3803. // Write the directory
  3804. CurrentPos = io ->Tell(io);
  3805. if (!io ->Seek(io, DirectoryPos)) goto Error;
  3806. if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
  3807. if (!io ->Seek(io, CurrentPos)) goto Error;
  3808. FreeArray(&a);
  3809. return TRUE;
  3810. Error:
  3811. FreeArray(&a);
  3812. return FALSE;
  3813. cmsUNUSED_PARAMETER(nItems);
  3814. }
  3815. static
  3816. void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
  3817. {
  3818. return (void*) cmsDictDup((cmsHANDLE) Ptr);
  3819. cmsUNUSED_PARAMETER(n);
  3820. cmsUNUSED_PARAMETER(self);
  3821. }
  3822. static
  3823. void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
  3824. {
  3825. cmsDictFree((cmsHANDLE) Ptr);
  3826. cmsUNUSED_PARAMETER(self);
  3827. }
  3828. // ********************************************************************************
  3829. // Type support main routines
  3830. // ********************************************************************************
  3831. // This is the list of built-in types
  3832. static _cmsTagTypeLinkedList SupportedTagTypes[] = {
  3833. {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
  3834. {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] },
  3835. {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] },
  3836. {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] },
  3837. {TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] },
  3838. {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] },
  3839. {TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] },
  3840. {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] },
  3841. {TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] },
  3842. {TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] },
  3843. {TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] },
  3844. {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] },
  3845. {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] },
  3846. {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] },
  3847. {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] },
  3848. {TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] },
  3849. {TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] },
  3850. {TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] },
  3851. {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] },
  3852. {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] },
  3853. {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] },
  3854. {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] },
  3855. {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] },
  3856. {TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] },
  3857. {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] },
  3858. {TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] },
  3859. {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] },
  3860. {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] },
  3861. {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] },
  3862. {TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] },
  3863. {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
  3864. };
  3865. #define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
  3866. // Both kind of plug-ins share same structure
  3867. cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
  3868. {
  3869. return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
  3870. }
  3871. cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
  3872. {
  3873. return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
  3874. }
  3875. // Wrapper for tag types
  3876. cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig)
  3877. {
  3878. return GetHandler(sig, SupportedTagTypes);
  3879. }
  3880. // ********************************************************************************
  3881. // Tag support main routines
  3882. // ********************************************************************************
  3883. typedef struct _cmsTagLinkedList_st {
  3884. cmsTagSignature Signature;
  3885. cmsTagDescriptor Descriptor;
  3886. struct _cmsTagLinkedList_st* Next;
  3887. } _cmsTagLinkedList;
  3888. // This is the list of built-in tags
  3889. static _cmsTagLinkedList SupportedTags[] = {
  3890. { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
  3891. { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
  3892. { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
  3893. { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
  3894. { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
  3895. { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
  3896. // Allow corbis and its broken XYZ type
  3897. { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
  3898. { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
  3899. { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
  3900. { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
  3901. { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
  3902. { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
  3903. { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
  3904. { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]},
  3905. { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
  3906. { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]},
  3907. { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]},
  3908. { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]},
  3909. { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]},
  3910. { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
  3911. { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
  3912. { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
  3913. { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
  3914. { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
  3915. { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
  3916. { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
  3917. { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
  3918. { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
  3919. { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
  3920. { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
  3921. { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
  3922. { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
  3923. { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
  3924. { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
  3925. { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
  3926. { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
  3927. { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
  3928. { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
  3929. { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
  3930. { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
  3931. { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
  3932. { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
  3933. { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
  3934. { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
  3935. { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
  3936. { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
  3937. { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
  3938. { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
  3939. { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
  3940. { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
  3941. { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
  3942. { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
  3943. { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
  3944. { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
  3945. { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
  3946. { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
  3947. { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
  3948. { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
  3949. { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
  3950. { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
  3951. { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
  3952. { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
  3953. { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL}
  3954. };
  3955. /*
  3956. Not supported Why
  3957. ======================= =========================================
  3958. cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
  3959. cmsSigNamedColorTag ==> Deprecated
  3960. cmsSigDataTag ==> Ancient, unused
  3961. cmsSigDeviceSettingsTag ==> Deprecated, useless
  3962. */
  3963. #define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
  3964. cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
  3965. {
  3966. cmsPluginTag* Plugin = (cmsPluginTag*) Data;
  3967. _cmsTagLinkedList *pt, *Anterior;
  3968. if (Data == NULL) {
  3969. SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL;
  3970. return TRUE;
  3971. }
  3972. pt = Anterior = SupportedTags;
  3973. while (pt != NULL) {
  3974. if (Plugin->Signature == pt -> Signature) {
  3975. pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour
  3976. return TRUE;
  3977. }
  3978. Anterior = pt;
  3979. pt = pt ->Next;
  3980. }
  3981. pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
  3982. if (pt == NULL) return FALSE;
  3983. pt ->Signature = Plugin ->Signature;
  3984. pt ->Descriptor = Plugin ->Descriptor;
  3985. pt ->Next = NULL;
  3986. if (Anterior != NULL) Anterior -> Next = pt;
  3987. return TRUE;
  3988. }
  3989. // Return a descriptor for a given tag or NULL
  3990. cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig)
  3991. {
  3992. _cmsTagLinkedList* pt;
  3993. for (pt = SupportedTags;
  3994. pt != NULL;
  3995. pt = pt ->Next) {
  3996. if (sig == pt -> Signature) return &pt ->Descriptor;
  3997. }
  3998. return NULL;
  3999. }