o
    ae                  
   @   s  d Z ddlZddlmZ ddlZddlZddlmZ ddl	m
Z
 dd Zdd	 Zd
d Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Z d2d3 Z!d4d5 Z"d6d7 Z#d8d9 Z$d:d; Z%d<d= Z&d>d? Z'd@dA Z(dBdC Z)dDdE Z*dFdG Z+djdHdIZ,e-e.e/fdJfe.e/fdJfe.e/fdJfe0dJfe0dJfe0dJfdKZ1dLdM Z2djdNdOZ3e-e.e/fdJfe.e/fdJfe0dJfe0dJfe0dJfdPZ4dQdR Z5dSdT Z6dUdV Z7dWZ8e-e0dXfe.e/fdJfe.e/fdJfe.e/fdJfe.e/fdJfe.e/fdJfe.e/fdJfe0dJfdYZ9dZd[ Z:dkd\d]Z;d^d_ Z<d`da Z=dbdc Z>ddZ?dedf Z@dgdh ZAeBdikrIddlCZCeCD  dS dS )lz"Various low level data validators.    N)open)Mapping)numberTypesc                 C   s,   t | trdS dD ]
}t| |s dS q	dS )zY
    Some objects will likely come in that aren't
    dicts but are dict-ish enough.
    T)keysvaluesitemsF)
isinstancer   hasattr)valueattr r   =/usr/lib/python3/dist-packages/fontTools/ufoLib/validators.pyisDictEnough   s   

r   c                 C   s
   t | |S )"
	Generic. (Added at version 2.)
	)r   )r
   typr   r   r   genericTypeValidator   s   
r   c                 C   sL   t | ttfs	dS t| }t|}|| rdS | D ]
}t |ts# dS qdS )r   FT)r   listtuplesetint)r   validValuesZ	valuesSetZvalidValuesSetr
   r   r   r   genericIntListValidator"   s   
r   c                 C      t | tsdS | dk rdS dS "
	Generic. (Added at version 3.)
	Fr   Tr   r   r
   r   r   r   genericNonNegativeIntValidator1   
   
r   c                 C   r   r   )r   r   r   r   r   r   !genericNonNegativeNumberValidator;   r   r   c                 C   s   t | tsdS | D ]\}\}}|sq|| vr dS q|  D ]	}||vr) dS q |  D ]\}}|| \}}|du r?|s?q.t ||sG dS q.dS )r   FNT)r   r   r   r   )r
   Z	prototypekeyr   requiredvZprototypeTyper   r   r   genericDictValidatorE   s(   

r#   c                 C   s   g d}| |v S )
	Version 2+.
	)ZregularZitalicZboldzbold italicr   )r
   optionsr   r   r   "fontInfoStyleMapStyleNameValidatore   s   r&   c           	      C   s   t | tsdS t| dkrdS g d}ttdftdfd}g }| D ]*}t||s+ dS |d }|d }t|}|s< dS t||}|sF dS || q!|t	|krTdS dS )
	Version 3+.
	Fr   T)r            )rangeMaxPPEMrangeGaspBehaviorr+   r,   )
r   r   lendictr   r#   r   r   appendsorted)	r
   ZvalidBehaviorsdictPrototypeZ	ppemOrderZrangeRecordZppemZbehaviorZppemValidityZbehaviorValidityr   r   r   )fontInfoOpenTypeGaspRangeRecordsValidatorl   s,   


r2   c           
      C   s  t | tsdS t| dksdS | ddkrdS | d\}}|ddkr(dS |ddkr1dS |d\}}}t|dkrAdS t|dkrIdS t|dkrQdS zt|}t|}t|}W n
 tyi   Y dS w |dk sr|d	krtdS t||d }|dk s||krdS |d\}}}	t|dkrdS t|dkrdS t|	dkrdS zt|}t|}t|	}	W n
 ty   Y dS w |d
k s|dkrdS |d
k s|dkrdS |	d
k s|	dkrdS dS )r$   F    r(   /r)   :      r      ;   T)	r   strr-   countsplitr   
ValueErrorcalendarZ
monthrange)
r
   datetimeZyearZmonthZdayZmonthMaxDayZhourZminutesecondr   r   r   $fontInfoOpenTypeHeadCreatedValidator   sf   
rC   c                 C   sR   t | tsdS ttdftdftdftdftdfd}| D ]
}t||s& dS qdS )r'   FT)ZnameIDZ
platformIDZ
encodingIDZ
languageIDstring)r   r   r.   r   r;   r#   )r
   r1   Z
nameRecordr   r   r   $fontInfoOpenTypeNameRecordsValidator   s   
&
rE   c                 C   r   )r$   Fr   Tr   r   r   r   r   'fontInfoOpenTypeOS2WeightClassValidator   r   rF   c                 C   s*   t | tsdS | dk rdS | dkrdS dS )r$   Fr(   	   Tr   r   r   r   r   &fontInfoOpenTypeOS2WidthClassValidator   s   
rH   c                 C   s@   t | ttfs	dS t| dkrdS | D ]
}t |ts dS qdS )z
	Version 2.
	F
   Tr   r   r   r-   r   r   r
   r   r   r   *fontInfoVersion2OpenTypeOS2PanoseValidator   s   
rL   c                 C   sN   t | ttfs	dS t| dkrdS | D ]}t |ts dS |dk r$ dS qdS )r'   FrI   r   TrJ   rK   r   r   r   *fontInfoVersion3OpenTypeOS2PanoseValidator   s   
rM   c                 C   sp   t | ttfs	dS t| dkrdS | D ]
}t |ts dS q| \}}|dk s*|dkr,dS |dk s4|dkr6dS dS )r$   Fr)   r         TrJ   )r   r
   ZclassIDZ
subclassIDr   r   r   'fontInfoOpenTypeOS2FamilyClassValidator  s   
rP   c                 C   P   t | ttfs	dS t| dkrdS t| d rdS | D ]
}t |ts% dS qdS )r$   FrN   r)   Tr   r   r   r-   r   rK   r   r   r    fontInfoPostscriptBluesValidator     
rS   c                 C   rQ   )r$   FrI   r)   TrR   rK   r   r   r   %fontInfoPostscriptOtherBluesValidator#  rT   rU   c                 C   s@   t | ttfs	dS t| dkrdS | D ]
}t |ts dS qdS )r$   Fr8   TrR   rK   r   r   r    fontInfoPostscriptStemsValidator2  s   
rV   c                 C   s   t tdd}| |vrdS dS )r$   r(      FT)r   range)r
   r   r   r   r   .fontInfoPostscriptWindowsCharacterSetValidator?  s   rY   c                 C   s    t tdfd}t| |sdS dS )r'   T)idF)r.   r;   r#   r
   r1   r   r   r   %fontInfoWOFFMetadataUniqueIDValidatorH  s   
r\   c                 C   J   t dft dft dft dfd}t| |sdS d| v r#| ddvr#dS dS )r'   TF)nameurldirclassr`   ZltrZrtlr;   r#   getr[   r   r   r   #fontInfoWOFFMetadataVendorValidatorQ     
re   c                 C   s   t tdfd}t| |sdS t| d sdS tdftdftdftdftdfd}| d D ]}t||s6 dS d|v rD|ddvrD dS q,dS )r'   T)creditsFrg   )r^   r_   Zroler`   ra   r`   rb   )r.   r   r#   r-   r;   rd   )r
   r1   Zcreditr   r   r   $fontInfoWOFFMetadataCreditsValidator\  s   
$
rh   c                 C   sB   t tdftdfd}t| |sdS | d D ]	}t|s dS qdS )r'   FT)r_   textri   r.   r;   r   r#   fontInfoWOFFMetadataTextValuer
   r1   ri   r   r   r   (fontInfoWOFFMetadataDescriptionValidatorm  s   
rm   c                 C   sP   t tdftdftdfd}t| |sdS d| v r&| d D ]	}t|s% dS qdS )r'   F)r_   ri   rZ   ri   Trj   rl   r   r   r   $fontInfoWOFFMetadataLicenseValidatory  s   
rn   c                 C   <   t tdfd}t| |sdS | d D ]	}t|s dS qdS r'   T)ri   Fri   r.   r   r#   rk   rl   r   r   r   &fontInfoWOFFMetadataTrademarkValidator     
rr   c                 C   ro   rp   rq   rl   r   r   r   &fontInfoWOFFMetadataCopyrightValidator  rs   rt   c                 C   sD   t dft dft dfd}t| |sdS d| v r | ddvr dS dS )r'   TF)r^   r`   ra   r`   rb   rc   r[   r   r   r   %fontInfoWOFFMetadataLicenseeValidator  s   
ru   c                 C   r]   r'   TF)ri   languager`   ra   r`   rb   rc   r[   r   r   r   rk     rf   rk   c                 C   s2   t | tsdS | sdS | D ]	}t|s dS qdS )r'   FT)r   r   &fontInfoWOFFMetadataExtensionValidator)r
   	extensionr   r   r   'fontInfoWOFFMetadataExtensionsValidator  s   
rz   c                 C   sl   t tdftdftdfd}t| |sdS d| v r&| d D ]	}t|s% dS q| d D ]	}t|s3 dS q*dS )r'   FT)namesr   rZ   r{   r   )r.   r   r;   r#   *fontInfoWOFFMetadataExtensionNameValidator*fontInfoWOFFMetadataExtensionItemValidator)r
   r1   r^   itemr   r   r   rx     s   
rx   c                 C   sd   t tdftdftdfd}t| |sdS | d D ]	}t|s! dS q| d D ]	}t|s/ dS q&dS )r'   FT)rZ   r{   r   r{   r   )r.   r;   r   r#   r|   +fontInfoWOFFMetadataExtensionValueValidator)r
   r1   r^   valr   r   r   r}     s   
r}   c                 C   r]   rv   rc   r[   r   r   r   r|     rf   r|   c                 C   r]   rv   rc   r[   r   r   r   r     rf   r   c                 C   b   t | tsdS |du rt }| D ]}t|s dS |d}|dur.||v r) dS || qdS r'   FN
identifierT)r   r   r   guidelineValidatorrd   add)r
   identifiersZguider   r   r   r   guidelinesValidator     


r   F)xyangler^   colorr   c                 C   s   t | tsdS | d}| d}| d}|du r |du r dS |du s(|du r.|dur.dS |dur<|dur<|du r<dS |durL|dk rFdS |dkrLdS | d}|dur[t|s[dS | d	}|durjt|sjdS d
S )r'   Fr   r   r   Nr   ih  r   r   T)r#   _guidelineDictPrototyperd   identifierValidatorcolorValidator)r
   r   r   r   r   r   r   r   r   r     s0   





r   c                 C   r   r   )r   r   r   anchorValidatorrd   r   )r
   r   Zanchorr   r   r   r   anchorsValidator8  r   r   )r   r   r^   r   r   c                 C   sv   t | tsdS | d}| d}|du s|du rdS | d}|dur*t|s*dS | d}|dur9t|s9dS dS )r'   Fr   r   Nr   r   T)r#   _anchorDictPrototyperd   r   r   )r
   r   r   r   r   r   r   r   r   P  s   




r   c                 C   sZ   d}d}t | tsdS | sdS t| dkrdS | D ]}t|}||k s'||kr* dS qdS )z
	Version 3+.

	>>> identifierValidator("a")
	True
	>>> identifierValidator("")
	False
	>>> identifierValidator("a" * 101)
	False
	    ~   Fd   T)r   r;   r-   ord)r
   ZvalidCharactersMinZvalidCharactersMaxcr   r   r   r   i  s   
r   c              	   C   s   t | tsdS | d}t|dkrdS |D ]A}| }d}zt|}d}W n	 ty/   Y nw |sDzt|}d}W n	 tyC   Y nw |sI dS |dk rP dS |dkrW dS qdS )a  
	Version 3+.

	>>> colorValidator("0,0,0,0")
	True
	>>> colorValidator(".5,.5,.5,.5")
	True
	>>> colorValidator("0.5,0.5,0.5,0.5")
	True
	>>> colorValidator("1,1,1,1")
	True

	>>> colorValidator("2,0,0,0")
	False
	>>> colorValidator("0,2,0,0")
	False
	>>> colorValidator("0,0,2,0")
	False
	>>> colorValidator("0,0,0,2")
	False

	>>> colorValidator("1r,1,1,1")
	False
	>>> colorValidator("1,1g,1,1")
	False
	>>> colorValidator("1,1,1b,1")
	False
	>>> colorValidator("1,1,1,1a")
	False

	>>> colorValidator("1 1 1 1")
	False
	>>> colorValidator("1 1,1,1")
	False
	>>> colorValidator("1,1 1,1")
	False
	>>> colorValidator("1,1,1 1")
	False

	>>> colorValidator("1, 1, 1, 1")
	True
	F,r7   Tr   r(   )r   r;   r=   r-   stripr   r>   float)r
   partspartZ	convertedr   r   r   r     s:   
+
r   s   PNG

T)fileNameZxScaleZxyScaleZyxScaleZyScaleZxOffsetZyOffsetr   c                 C   s<   t | tsdS | d sdS | d}|durt|sdS dS )r'   Fr   r   NT)r#   _imageDictPrototyperd   r   )r
   r   r   r   r   imageValidator  s   

r   c                 C   s   | dus|dus|dusJ | dur-t | d}|d}W d   n1 s'w   Y  n|dur8|dd }n|durJ| }|d}|| |tkrPdS dS )z>
	Version 3+.

	This checks the signature of the image data.
	Nrb   )Fz,Image does not begin with the PNG signature.TN)r   readtellseekpngSignature)pathdataZfileObjfZ	signatureposr   r   r   pngValidator  s   

r   c                 C   sr  t |tjjr
|}ntj|}d}t | tsd|fS t }t }i }| D ]}t |ts2d|f  S t|dks>d|f  S |D ]}t |t	sOd|f    S q@|\}	}
|
dkre|

dsedd|
 f  S t|	dkrn dS ||
s{dd	|
 f  S |	d
kr|
dkr dS |	|v rdd|	 f  S ||	 |
|v rdd|
 f  S ||
 |
||	< q%d| v }|sdS dS )z;
	Check the validity of layercontents.plist.
	Version 3+.
	z1layercontents.plist in not in the correct format.Fr)   Zglyphszglyphs.z3Invalid directory name (%s) in layercontents.plist.r   )Fz(Empty layer name in layercontents.plist.z A glyphset does not exist at %s.zpublic.default)FzIThe name public.default is being used by a layer that is not the default.z1The layer name %s is used by more than one layer.z0The directory %s is used by more than one layer.)Fz1The required default glyph set is not in the UFO.r   )r   fsbaseZFSZosfsZOSFSr   r   r-   r;   
startswithexistsr   r   )r
   ZufoPathOrFileSystemZ
fileSystemZbogusFileMessageZusedLayerNamesZusedDirectoriescontentsentryiZ	layerNameZdirectoryNameZfoundDefaultr   r   r   layerContentsValidator  sN   







r   c                 C   s  d}t | s
d|fS i }i }|  D ]l\}}t|ts!d|f  S t|ttfs.d|f  S |s3 dS |dr~|dsC|dsCqtdt|krN dS |drV|}n|}|D ]#}t|tskdd	| f    S ||v rydd
| f    S |||< qZqdS )a>  
	Check the validity of the groups.
	Version 3+ (though it's backwards compatible with UFO 1 and UFO 2).

	>>> groups = {"A" : ["A", "A"], "A2" : ["A"]}
	>>> groupsValidator(groups)
	(True, None)

	>>> groups = {"" : ["A"]}
	>>> valid, msg = groupsValidator(groups)
	>>> valid
	False
	>>> print(msg)
	A group has an empty name.

	>>> groups = {"public.awesome" : ["A"]}
	>>> groupsValidator(groups)
	(True, None)

	>>> groups = {"public.kern1." : ["A"]}
	>>> valid, msg = groupsValidator(groups)
	>>> valid
	False
	>>> print(msg)
	The group data contains a kerning group with an incomplete name.
	>>> groups = {"public.kern2." : ["A"]}
	>>> valid, msg = groupsValidator(groups)
	>>> valid
	False
	>>> print(msg)
	The group data contains a kerning group with an incomplete name.

	>>> groups = {"public.kern1.A" : ["A"], "public.kern2.A" : ["A"]}
	>>> groupsValidator(groups)
	(True, None)

	>>> groups = {"public.kern1.A1" : ["A"], "public.kern1.A2" : ["A"]}
	>>> valid, msg = groupsValidator(groups)
	>>> valid
	False
	>>> print(msg)
	The glyph "A" occurs in too many kerning groups.
	z,The group data is not in the correct format.F)FzA group has an empty name.zpublic.zpublic.kern1.zpublic.kern2.zpublic.kernN.)Fz@The group data contains a kerning group with an incomplete name.z-The group data %s contains an invalid member.z1The glyph "%s" occurs in too many kerning groups.r   )r   r   r   r;   r   r   r   r-   )r
   bogusFormatMessageZfirstSideMappingZsecondSideMappingZ	groupNameZ	glyphListd	glyphNamer   r   r   groupsValidator<  s8   ,




r   c                 C   s   d}t | tsd|fS |  D ]=\}}t |tsd|f  S t |ts)d|f  S | D ]\}}t |ts>d|f    S t |tsKd|f    S q-qdS )a  
	Check the validity of the kerning data structure.
	Version 3+ (though it's backwards compatible with UFO 1 and UFO 2).

	>>> kerning = {"A" : {"B" : 100}}
	>>> kerningValidator(kerning)
	(True, None)

	>>> kerning = {"A" : ["B"]}
	>>> valid, msg = kerningValidator(kerning)
	>>> valid
	False
	>>> print(msg)
	The kerning data is not in the correct format.

	>>> kerning = {"A" : {"B" : "100"}}
	>>> valid, msg = kerningValidator(kerning)
	>>> valid
	False
	>>> print(msg)
	The kerning data is not in the correct format.
	z.The kerning data is not in the correct format.Fr   )r   r   r   r;   r   )r   r   firstZ
secondDictrB   r
   r   r   r   kerningValidator  s    




r   z-The lib data is not in the correct format: %sc                 C   s   t | sdt| j }dt| fS |  D ]M\}} t|ts+ddt|j|f f  S |dkrbd}t| ttfsGdt| j }d|| f  S | D ]}t|tsadt|j }d|| f    S qIqdS )	ab  
	Check the validity of the lib.
	Version 3+ (though it's backwards compatible with UFO 1 and UFO 2).

	>>> lib = {"foo" : "bar"}
	>>> fontLibValidator(lib)
	(True, None)

	>>> lib = {"public.awesome" : "hello"}
	>>> fontLibValidator(lib)
	(True, None)

	>>> lib = {"public.glyphOrder" : ["A", "C", "B"]}
	>>> fontLibValidator(lib)
	(True, None)

	>>> lib = "hello"
	>>> valid, msg = fontLibValidator(lib)
	>>> valid
	False
	>>> print(msg)  # doctest: +ELLIPSIS
	The lib data is not in the correct format: expected a dictionary, ...

	>>> lib = {1: "hello"}
	>>> valid, msg = fontLibValidator(lib)
	>>> valid
	False
	>>> print(msg)
	The lib key is not properly formatted: expected str, found int: 1

	>>> lib = {"public.glyphOrder" : "hello"}
	>>> valid, msg = fontLibValidator(lib)
	>>> valid
	False
	>>> print(msg)  # doctest: +ELLIPSIS
	public.glyphOrder is not properly formatted: expected list or tuple,...

	>>> lib = {"public.glyphOrder" : ["A", 1, "B"]}
	>>> valid, msg = fontLibValidator(lib)
	>>> valid
	False
	>>> print(msg)  # doctest: +ELLIPSIS
	public.glyphOrder is not properly formatted: expected str,...
	expected a dictionary, found %sFzAThe lib key is not properly formatted: expected str, found %s: %rzpublic.glyphOrderz/public.glyphOrder is not properly formatted: %sz expected list or tuple, found %szexpected str, found %sr   )	r   type__name___bogusLibFormatMessager   r   r;   r   r   )r
   reasonr    ZbogusGlyphOrderMessager   r   r   r   fontLibValidator  s,   -

r   c                 C   sp   t | sdt| j }dt| fS |  D ] \}} t|ts*d| }dt| f  S |dkr5t| s5 dS qdS )a  
	Check the validity of the lib.
	Version 3+ (though it's backwards compatible with UFO 1 and UFO 2).

	>>> lib = {"foo" : "bar"}
	>>> glyphLibValidator(lib)
	(True, None)

	>>> lib = {"public.awesome" : "hello"}
	>>> glyphLibValidator(lib)
	(True, None)

	>>> lib = {"public.markColor" : "1,0,0,0.5"}
	>>> glyphLibValidator(lib)
	(True, None)

	>>> lib = {"public.markColor" : 1}
	>>> valid, msg = glyphLibValidator(lib)
	>>> valid
	False
	>>> print(msg)
	public.markColor is not properly formatted.
	r   Fzkey (%s) should be a stringzpublic.markColor)Fz+public.markColor is not properly formatted.r   )r   r   r   r   r   r   r;   r   )r
   r   r    r   r   r   glyphLibValidator  s   
r   __main__)N)NNN)E__doc__r?   ior   Zfs.baser   Zfs.osfsZcollections.abcr   ZfontTools.ufoLib.utilsr   r   r   r   r   r   r#   r&   r2   rC   rE   rF   rH   rL   rM   rP   rS   rU   rV   rY   r\   re   rh   rm   rn   rr   rt   ru   rk   rz   rx   r}   r|   r   r   r.   r   r   r;   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ZdoctestZtestmodr   r   r   r   <module>   s    

 ;
		

'J
;O*E
&