text:
function im_hdr = GE_readHeaderImage(fid, byte_align)
%
% im_hdr = GE_readHeaderImage(fid, byte_align)
%
% Loads the image header from a file with filed id fid
% and returns it as a structure.
% if byte_align = 1 then 32-bit alignment (SGI, LX2 format)
% if byte_align = 0 then 16-bit alignment (Sun, 5.X format)
%
%
% Souheil J. Inati
% Dartmouth College
% May 2000
% souheil.inati@dartmouth.edu
%

% define the structure and read in the data
% to overcome the byte alignment problems
% break up the assignment into pieces using the setfield function

im_hdr = struct('im_suid', fread(fid,4,'uchar')); %Suite id for this image
im_hdr = setfield(im_hdr, 'im_uniq', fread(fid,1,'int16'));            %The Make-Unique Flag
im_hdr = setfield(im_hdr, 'im_diskid', fread(fid,1,'uchar'));          %Disk ID for this Image
fseek(fid, 1, 0);% 16-bit alignment
im_hdr = setfield(im_hdr, 'im_exno', fread(fid,1,'uint16'));            %Exam number for this image
im_hdr = setfield(im_hdr, 'im_seno', fread(fid,1,'int16'));            %Series Number for this image
im_hdr = setfield(im_hdr, 'im_no', fread(fid,1,'int16'));              %Image Number
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'im_datetime', fread(fid,1,'int32'));        %Allocation Image date/time stamp
im_hdr = setfield(im_hdr, 'im_actual_dt', fread(fid,1,'int32'));       %Actual Image date/time stamp
im_hdr = setfield(im_hdr, 'sctime', fread(fid,1,'float32'));             %Duration of scan
im_hdr = setfield(im_hdr, 'slthick', fread(fid,1,'float32'));            %Slice Thickness (mm)
im_hdr = setfield(im_hdr, 'imatrix_X', fread(fid,1,'int16'));          %Image matrix size - X
im_hdr = setfield(im_hdr, 'imatrix_Y', fread(fid,1,'int16'));          %Image matrix size - Y
im_hdr = setfield(im_hdr, 'dfov', fread(fid,1,'float32'));               %Display field of view - X (mm)
im_hdr = setfield(im_hdr, 'dfov_rect', fread(fid,1,'float32'));          %Display field of view - Y (if different)
im_hdr = setfield(im_hdr, 'dim_X', fread(fid,1,'float32'));              %Image dimension - X
im_hdr = setfield(im_hdr, 'dim_Y', fread(fid,1,'float32'));              %Image dimension - Y
im_hdr = setfield(im_hdr, 'pixsize_X', fread(fid,1,'float32'));          %Image pixel size - X
im_hdr = setfield(im_hdr, 'pixsize_Y', fread(fid,1,'float32'));          %Image pixel size - Y
im_hdr = setfield(im_hdr, 'pdid', fread(fid,14,'uchar'));          %Pixel Data ID
im_hdr = setfield(im_hdr, 'contrastIV', fread(fid,17,'uchar'));    %IV Contrast Agent
im_hdr = setfield(im_hdr, 'contrastOral', fread(fid,17,'uchar'));  %Oral Contrast Agent
im_hdr = setfield(im_hdr, 'contmode', fread(fid,1,'int16'));           %Image Contrast Mode
im_hdr = setfield(im_hdr, 'serrx', fread(fid,1,'int16'));              %Series from which prescribed
im_hdr = setfield(im_hdr, 'imgrx', fread(fid,1,'int16'));              %Image from which prescribed
im_hdr = setfield(im_hdr, 'screenformat', fread(fid,1,'int16'));       %Screen Format(8/16 bit)
im_hdr = setfield(im_hdr, 'plane', fread(fid,1,'int16'));              %Plane Type
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'scanspacing', fread(fid,1,'float32'));        %Spacing between scans (mm?)
im_hdr = setfield(im_hdr, 'im_compress', fread(fid,1,'int16'));        %Image compression type for allocation
im_hdr = setfield(im_hdr, 'im_scouttype', fread(fid,1,'int16'));       %Scout Type (AP or lateral)
im_hdr = setfield(im_hdr, 'loc_ras', fread(fid,1,'uchar'));            %RAS letter of image location
fseek(fid, 1, 0); % 16-bit alignment
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'loc', fread(fid,1,'float32'));                %Image location
im_hdr = setfield(im_hdr, 'ctr_R', fread(fid,1,'float32'));              %Center R coord of plane image
im_hdr = setfield(im_hdr, 'ctr_A', fread(fid,1,'float32'));              %Center A coord of plane image
im_hdr = setfield(im_hdr, 'ctr_S', fread(fid,1,'float32'));              %Center S coord of plane image
im_hdr = setfield(im_hdr, 'norm_R', fread(fid,1,'float32'));             %Normal R coord
im_hdr = setfield(im_hdr, 'norm_A', fread(fid,1,'float32'));             %Normal A coord
im_hdr = setfield(im_hdr, 'norm_S', fread(fid,1,'float32'));             %Normal S coord
im_hdr = setfield(im_hdr, 'tlhc_R', fread(fid,1,'float32'));             %R Coord of Top Left Hand Corner
im_hdr = setfield(im_hdr, 'tlhc_A', fread(fid,1,'float32'));             %A Coord of Top Left Hand Corner
im_hdr = setfield(im_hdr, 'tlhc_S', fread(fid,1,'float32'));             %S Coord of Top Left Hand Corner
im_hdr = setfield(im_hdr, 'trhc_R', fread(fid,1,'float32'));             %R Coord of Top Right Hand Corner
im_hdr = setfield(im_hdr, 'trhc_A', fread(fid,1,'float32'));             %A Coord of Top Right Hand Corner
im_hdr = setfield(im_hdr, 'trhc_S', fread(fid,1,'float32'));             %S Coord of Top Right Hand Corner
im_hdr = setfield(im_hdr, 'brhc_R', fread(fid,1,'float32'));             %R Coord of Bottom Right Hand Corner
im_hdr = setfield(im_hdr, 'brhc_A', fread(fid,1,'float32'));             %A Coord of Bottom Right Hand Corner
im_hdr = setfield(im_hdr, 'brhc_S', fread(fid,1,'float32'));             %S Coord of Bottom Right Hand Corner
im_hdr = setfield(im_hdr, 'forimgrev', fread(fid,4,'uchar'));      %Foreign Image Revision
im_hdr = setfield(im_hdr, 'tr', fread(fid,1,'int32'));                 %Pulse repetition time(usec)
im_hdr = setfield(im_hdr, 'ti', fread(fid,1,'int32'));                 %Pulse inversion time(usec)
im_hdr = setfield(im_hdr, 'te', fread(fid,1,'int32'));                 %Pulse echo time(usec)
im_hdr = setfield(im_hdr, 'te2', fread(fid,1,'int32'));                %Second echo echo (usec)
im_hdr = setfield(im_hdr, 'numecho', fread(fid,1,'int16'));            %Number of echoes
im_hdr = setfield(im_hdr, 'echonum', fread(fid,1,'int16'));            %Echo Number
im_hdr = setfield(im_hdr, 'tbldlta', fread(fid,1,'float32'));            %Table Delta
im_hdr = setfield(im_hdr, 'nex', fread(fid,1,'float32'));                %Number of Excitations
im_hdr = setfield(im_hdr, 'contig', fread(fid,1,'int16'));             %Continuous Slices Flag
im_hdr = setfield(im_hdr, 'hrtrate', fread(fid,1,'int16'));            %Cardiac Heart Rate (bpm)
im_hdr = setfield(im_hdr, 'tdel', fread(fid,1,'int32'));               %Delay time after trigger (msec)
im_hdr = setfield(im_hdr, 'saravg', fread(fid,1,'float32'));             %Average SAR
im_hdr = setfield(im_hdr, 'sarpeak', fread(fid,1,'float32'));            %Peak SAR
im_hdr = setfield(im_hdr, 'monsar', fread(fid,1,'int16'));             %Monitor SAR flag
im_hdr = setfield(im_hdr, 'trgwindow', fread(fid,1,'int16'));          %Trigger window (% of R-R interval)
im_hdr = setfield(im_hdr, 'reptime', fread(fid,1,'float32'));            %Cardiac repetition time
im_hdr = setfield(im_hdr, 'imgpcyc', fread(fid,1,'int16'));            %Images per cardiac cycle
im_hdr = setfield(im_hdr, 'xmtgain', fread(fid,1,'int16'));            %Actual Transmit Gain (.1 db)
im_hdr = setfield(im_hdr, 'rcvgain1', fread(fid,1,'int16'));           %Actual Receive Gain Analog (.1 db)
im_hdr = setfield(im_hdr, 'rcvgain2', fread(fid,1,'int16'));           %Actual Receive Gain Digital (.1 db)
im_hdr = setfield(im_hdr, 'mr_flip', fread(fid,1,'int16'));            %Flip Angle for GRASS scans (deg.)
if byte_align; fseek(fid, 2, 0); end % byte alignment
im_hdr = setfield(im_hdr, 'mindat', fread(fid,1,'int32'));             %Minimum Delay after Trigger (uSec)
im_hdr = setfield(im_hdr, 'cphase', fread(fid,1,'int16'));             %Total Cardiac Phase prescribed
im_hdr = setfield(im_hdr, 'swappf', fread(fid,1,'int16'));             %Swap Phase/Frequency Axis
im_hdr = setfield(im_hdr, 'pauseint', fread(fid,1,'int16'));           %Pause Interval (slices)
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'pausetime', fread(fid,1,'float32'));          %Pause Time
im_hdr = setfield(im_hdr, 'obplane', fread(fid,1,'int32'));            %Oblique Plane
im_hdr = setfield(im_hdr, 'slocfov', fread(fid,1,'int32'));            %Slice Offsets on Freq axis
im_hdr = setfield(im_hdr, 'xmtfreq', fread(fid,1,'int32'));            %Center Frequency (0.1 Hz)
im_hdr = setfield(im_hdr, 'autoxmtfreq', fread(fid,1,'int32'));        %Auto Center Frequency (0.1 Hz)
im_hdr = setfield(im_hdr, 'autoxmtgain', fread(fid,1,'int16'));        %Auto Transmit Gain (0.1 dB)
im_hdr = setfield(im_hdr, 'prescan_r1', fread(fid,1,'int16'));         %PreScan R1 - Analog
im_hdr = setfield(im_hdr, 'prescan_r2', fread(fid,1,'int16'));         %PreScan R2 - Digital
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'user_bitmap', fread(fid,1,'int32'));        %Bitmap defining user CVs
im_hdr = setfield(im_hdr, 'cenfreq', fread(fid,1,'int16'));            %Center Frequency Method
im_hdr = setfield(im_hdr, 'imode', fread(fid,1,'int16'));              %Imaging Mode
im_hdr = setfield(im_hdr, 'iopt', fread(fid,1,'int32'));               %Imaging Options
im_hdr = setfield(im_hdr, 'pseq', fread(fid,1,'int16'));               %Pulse Sequence
im_hdr = setfield(im_hdr, 'pseqmode', fread(fid,1,'int16'));           %Pulse Sequence Mode
im_hdr = setfield(im_hdr, 'psdname', fread(fid,33,'uchar'));       %Pulse Sequence Name
fseek(fid,1,0); % 16-bit alignment
if byte_align; fseek(fid, 2, 0); end % byte alignment
im_hdr = setfield(im_hdr, 'psd_datetime', fread(fid,1,'int32'));       %PSD Creation Date and Time
im_hdr = setfield(im_hdr, 'psd_iname', fread(fid,13,'uchar'));     %PSD name from inside PSD
fseek(fid, 1, 0); % 16-bit alignment
im_hdr = setfield(im_hdr, 'ctyp', fread(fid,1,'int16'));               %Coil Type
im_hdr = setfield(im_hdr, 'cname', fread(fid,17,'uchar'));         %Coil Name
fseek(fid, 1, 0); % 16-bit alignment
im_hdr = setfield(im_hdr, 'surfctyp', fread(fid,1,'int16'));           %Surface Coil Type
im_hdr = setfield(im_hdr, 'surfcext', fread(fid,1,'int16'));           %Extremity Coil Flag
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
%rawrunnum
%ftell(fid)
im_hdr = setfield(im_hdr, 'rawrunnum', fread(fid,1,'int32'));          %RawData Run Number
im_hdr = setfield(im_hdr, 'cal_fldstr', fread(fid,1,'uint32'));         %Calibrated Field Strength (x10 uGauss)
im_hdr = setfield(im_hdr, 'supp_tech', fread(fid,1,'int16'));          %SAT fat/water/none
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'vbw', fread(fid,1,'float32'));                %Variable Bandwidth (Hz)
im_hdr = setfield(im_hdr, 'slquant', fread(fid,1,'int16'));            %Number of slices in this scan group
im_hdr = setfield(im_hdr, 'gpre', fread(fid,1,'int16'));               %Graphically prescribed
im_hdr = setfield(im_hdr, 'intr_del', fread(fid,1,'int32'));           %Interimage/interloc delay (uSec)
im_hdr = setfield(im_hdr, 'user0', fread(fid,1,'float32'));              %User Variable 0
im_hdr = setfield(im_hdr, 'user1', fread(fid,1,'float32'));              %User Variable 1
im_hdr = setfield(im_hdr, 'user2', fread(fid,1,'float32'));              %User Variable 2
im_hdr = setfield(im_hdr, 'user3', fread(fid,1,'float32'));              %User Variable 3
im_hdr = setfield(im_hdr, 'user4', fread(fid,1,'float32'));              %User Variable 4
im_hdr = setfield(im_hdr, 'user5', fread(fid,1,'float32'));              %User Variable 5
im_hdr = setfield(im_hdr, 'user6', fread(fid,1,'float32'));              %User Variable 6
im_hdr = setfield(im_hdr, 'user7', fread(fid,1,'float32'));              %User Variable 7
im_hdr = setfield(im_hdr, 'user8', fread(fid,1,'float32'));              %User Variable 8
im_hdr = setfield(im_hdr, 'user9', fread(fid,1,'float32'));              %User Variable 9
im_hdr = setfield(im_hdr, 'user10', fread(fid,1,'float32'));             %User Variable 10
im_hdr = setfield(im_hdr, 'user11', fread(fid,1,'float32'));             %User Variable 11
im_hdr = setfield(im_hdr, 'user12', fread(fid,1,'float32'));             %User Variable 12
im_hdr = setfield(im_hdr, 'user13', fread(fid,1,'float32'));             %User Variable 13
im_hdr = setfield(im_hdr, 'user14', fread(fid,1,'float32'));             %User Variable 14
im_hdr = setfield(im_hdr, 'user15', fread(fid,1,'float32'));             %User Variable 15
im_hdr = setfield(im_hdr, 'user16', fread(fid,1,'float32')); ...
%User Variable 16
%ftell(fid)
im_hdr = setfield(im_hdr, 'user17', fread(fid,1,'float32'));             %User Variable 17
im_hdr = setfield(im_hdr, 'user18', fread(fid,1,'float32'));             %User Variable 18
im_hdr = setfield(im_hdr, 'user19', fread(fid,1,'float32'));             %User Variable 19
im_hdr = setfield(im_hdr, 'user20', fread(fid,1,'float32'));             %User Variable 20
im_hdr = setfield(im_hdr, 'user21', fread(fid,1,'float32'));             %User Variable 21
im_hdr = setfield(im_hdr, 'user22', fread(fid,1,'float32'));             %User Variable 22
im_hdr = setfield(im_hdr, 'user23', fread(fid,1,'float32'));             %Projection Angle
im_hdr = setfield(im_hdr, 'user24', fread(fid,1,'float32'));             %Concat Sat Type Flag
im_hdr = setfield(im_hdr, 'im_alloc_key', fread(fid,13,'uchar'));
fseek(fid, 1, 0); % 16-bit alignment
if byte_align; fseek(fid, 2, 0); end % 32-bit alignment
im_hdr = setfield(im_hdr, 'im_lastmod', fread(fid,1,'int32'));         %Date/Time of Last Change
im_hdr = setfield(im_hdr, 'im_verscre', fread(fid,2,'uchar'));     %Genesis Version - Created
im_hdr = setfield(im_hdr, 'im_verscur', fread(fid,2,'uchar'));     %Genesis Version - Now
im_hdr = setfield(im_hdr, 'im_pds_a', fread(fid,1,'int32'));           %PixelData size - as stored
im_hdr = setfield(im_hdr, 'im_pds_c', fread(fid,1,'int32'));           %PixelData size - Compressed
im_hdr = setfield(im_hdr, 'im_pds_u', fread(fid,1,'int32'));           %PixelData size - UnCompressed
im_hdr = setfield(im_hdr, 'im_checksum', fread(fid,1,'int32'));        %AcqRecon record checksum
im_hdr = setfield(im_hdr, 'im_archived', fread(fid,1,'int32'));        %Image Archive Flag
im_hdr = setfield(im_hdr, 'im_complete', fread(fid,1,'int32'));        %Image Complete Flag
im_hdr = setfield(im_hdr, 'satbits', fread(fid,1,'int16'));            %Bitmap of SAT selections
im_hdr = setfield(im_hdr, 'scic', fread(fid,1,'int16'));               %Surface Coil Intensity Correction Flag
im_hdr = setfield(im_hdr, 'satxloc1', fread(fid,1,'int16'));           %R-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satxloc2', fread(fid,1,'int16'));           %L-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satyloc1', fread(fid,1,'int16'));           %A-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satyloc2', fread(fid,1,'int16'));           %P-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satzloc1', fread(fid,1,'int16'));           %S-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satzloc2', fread(fid,1,'int16'));           %I-side SAT pulse loc rel to lndmrk
im_hdr = setfield(im_hdr, 'satxthick', fread(fid,1,'int16'));          %Thickness of X-axis SAT pulse
im_hdr = setfield(im_hdr, 'satythick', fread(fid,1,'int16'));          %Thickness of Y-axis SAT pulse
im_hdr = setfield(im_hdr, 'satzthick', fread(fid,1,'int16'));          %Thickness of Z-axis SAT pulse
im_hdr = setfield(im_hdr, 'flax', fread(fid,1,'int16'));               %Phase contrast flow axis
im_hdr = setfield(im_hdr, 'venc', fread(fid,1,'int16'));               %Phase contrast velocity encoding
im_hdr = setfield(im_hdr, 'thk_disclmr', fread(fid,1,'int16'));        %Slice Thickness
im_hdr = setfield(im_hdr, 'ps_flag', fread(fid,1,'int16'));            %Auto/Manual Prescan flag
im_hdr = setfield(im_hdr, 'ps_status', fread(fid,1,'int16'));          %Bitmap of changed values
im_hdr = setfield(im_hdr, 'image_type', fread(fid,1,'int16'));         %Magnitude, Phase, Imaginary, or Real
im_hdr = setfield(im_hdr, 'vas_collapse', fread(fid,1,'int16'));       %Collapse Image
im_hdr = setfield(im_hdr, 'user23n', fread(fid,1,'float32'));            %User Variable 23
im_hdr = setfield(im_hdr, 'user24n', fread(fid,1,'float32'));            %User Variable 24
im_hdr = setfield(im_hdr, 'proj_alg', fread(fid,1,'int16'));           %Projection Algorithm
im_hdr = setfield(im_hdr, 'proj_name', fread(fid,13,'uchar'));     %Projection Algorithm Name
fseek(fid, 1, 0); % 16-bit alignment
im_hdr = setfield(im_hdr, 'x_axis_rot', fread(fid,1,'float32'));         %X Axis Rotation
im_hdr = setfield(im_hdr, 'y_axis_rot', fread(fid,1,'float32'));         %Y Axis Rotation
im_hdr = setfield(im_hdr, 'z_axis_rot', fread(fid,1,'float32'));         %Z Axis Rotation
im_hdr = setfield(im_hdr, 'thresh_min1', fread(fid,1,'int32'));        %Lower Range of Pixels 1
im_hdr = setfield(im_hdr, 'thresh_max1', fread(fid,1,'int32'));        %Upper Range of Pixels 1
im_hdr = setfield(im_hdr, 'thresh_min2', fread(fid,1,'int32'));        %Lower Range of Pixels 2
im_hdr = setfield(im_hdr, 'thresh_max2', fread(fid,1,'int32'));        %Upper Range of Pixels 2
im_hdr = setfield(im_hdr, 'echo_trn_len', fread(fid,1,'int16'));       %Echo Train Length for Fast Spin Echo
im_hdr = setfield(im_hdr, 'frac_echo', fread(fid,1,'int16'));          %Fractional Echo - Effective TE Flag
im_hdr = setfield(im_hdr, 'prep_pulse', fread(fid,1,'int16'));         %Preporatory Pulse Option
im_hdr = setfield(im_hdr, 'cphasenum', fread(fid,1,'int16'));          %Cardiac Phase Number
im_hdr = setfield(im_hdr, 'var_echo', fread(fid,1,'int16'));           %Variable Echo Flag
im_hdr = setfield(im_hdr, 'ref_img', fread(fid,1,'uchar'));            %Reference Image Field
im_hdr = setfield(im_hdr, 'sum_img', fread(fid,1,'uchar'));            %Summary Image Field
im_hdr = setfield(im_hdr, 'img_window', fread(fid,1,'uint16'));         %Window Value
im_hdr = setfield(im_hdr, 'img_level', fread(fid,1,'int16'));          %Level Value
im_hdr = setfield(im_hdr, 'slop_int_1', fread(fid,1,'int32'));         %Number of 3D Slabs
im_hdr = setfield(im_hdr, 'slop_int_2', fread(fid,1,'int32'));         %Slice Locs Per 3D Slab
im_hdr = setfield(im_hdr, 'slop_int_3', fread(fid,1,'int32'));         %# of Slice Locs on Each Slab Which Overlap Neighbors
im_hdr = setfield(im_hdr, 'slop_int_4', fread(fid,1,'int32'));         %Image Filtering 0.5/0.2T
im_hdr = setfield(im_hdr, 'slop_int_5', fread(fid,1,'int32'));         %Integer Slop Field 5
im_hdr = setfield(im_hdr, 'slop_float_1', fread(fid,1,'float32'));       %Float Slop Field 1
im_hdr = setfield(im_hdr, 'slop_float_2', fread(fid,1,'float32'));       %Float Slop Field 2
im_hdr = setfield(im_hdr, 'slop_float_3', fread(fid,1,'float32'));       %Float Slop Field 3
im_hdr = setfield(im_hdr, 'slop_float_4', fread(fid,1,'float32'));       %Float Slop Field 4
im_hdr = setfield(im_hdr, 'slop_float_5', fread(fid,1,'float32'));       %Float Slop Field 5
im_hdr = setfield(im_hdr, 'slop_str_1', fread(fid,16,'uchar'));    %String Slop Field 1
im_hdr = setfield(im_hdr, 'slop_str_2', fread(fid,16,'uchar'));    %String Slop Field 2
im_hdr = setfield(im_hdr, 'scanactno', fread(fid,1,'int16'));          %Scan Acquisition Number
im_hdr = setfield(im_hdr, 'vasflags', fread(fid,1,'int16'));           %Magnitude Weighting Flag
im_hdr = setfield(im_hdr, 'vencscale', fread(fid,1,'float32'));          %Scale Weighted Venc
im_hdr = setfield(im_hdr, 'integrity', fread(fid,1,'int16'));          %GE Image Integrity
if byte_align; fseek(fid, 2, 0); end % byte alignment
im_hdr = setfield(im_hdr, 'fphase', fread(fid,1,'int32'));             %Number Of Phases
im_hdr = setfield(im_hdr, 'freq_dir', fread(fid,1,'int16'));           %Frequency Direction
im_hdr = setfield(im_hdr, 'vas_mode', fread(fid,1,'int16'));           %Vascular Mode
im_hdr = setfield(im_hdr, 'image_uid', fread(fid,32,'uchar'));     %Image Unique ID
im_hdr = setfield(im_hdr, 'sop_uid', fread(fid,32,'uchar'));       %Service Obj Class Unique ID
im_hdr = setfield(im_hdr, 'dont_use_1', fread(fid,1,'int16'));         %This field is not used
im_hdr = setfield(im_hdr, 'dont_use_2', fread(fid,1,'int16'));         %This field is not used
im_hdr = setfield(im_hdr, 'dont_use_3', fread(fid,1,'int16'));         %This field is not used
im_hdr = setfield(im_hdr, 'pscopts', fread(fid,1,'int16'));            %bitmap of prescan options
im_hdr = setfield(im_hdr, 'asoffsetx', fread(fid,1,'int16'));          %gradient offset in X-direction
im_hdr = setfield(im_hdr, 'asoffsety', fread(fid,1,'int16'));          %gradient offset in Y-direction
im_hdr = setfield(im_hdr, 'asoffsetz', fread(fid,1,'int16'));          %gradient offset in Z-direction
im_hdr = setfield(im_hdr, 'unoriginal', fread(fid,1,'int16'));         %identifies image as original or unoriginal
im_hdr = setfield(im_hdr, 'interleaves', fread(fid,1,'int16'));        %number of EPI shots
im_hdr = setfield(im_hdr, 'effechospace', fread(fid,1,'int16'));       %effective echo spacing for EPI
im_hdr = setfield(im_hdr, 'viewsperseg', fread(fid,1,'int16'));        %views per segment
im_hdr = setfield(im_hdr, 'rbpm', fread(fid,1,'int16'));               %respiratory rate, breaths per min
im_hdr = setfield(im_hdr, 'rtpoint', fread(fid,1,'int16'));            %respiratory trigger point as percent of max.
im_hdr = setfield(im_hdr, 'rcvrtype', fread(fid,1,'int16'));           %type of receiver used
im_hdr = setfield(im_hdr, 'dbdt', fread(fid,1,'float32'));               %peak rate of change of gradient field, tesla/sec
im_hdr = setfield(im_hdr, 'dbdtper', fread(fid,1,'float32'));            %limit in units of percent of theoretical curve
im_hdr = setfield(im_hdr, 'estdbdtper', fread(fid,1,'float32'));         %PSD estimated limit in units of percent
im_hdr = setfield(im_hdr, 'estdbdtts', fread(fid,1,'float32'));          %PSD estimated limit in Teslas/sec
im_hdr = setfield(im_hdr, 'saravghead', fread(fid,1,'float32'));         %Avg head SAR
im_hdr = setfield(im_hdr, 'neg_scanspacing', fread(fid,1,'float32'));    %Negative scan spacing for overlap slices
im_hdr = setfield(im_hdr, 'offsetfreq', fread(fid,1,'int32'));         %Offset Frequency - Mag.Transfer
im_hdr = setfield(im_hdr, 'user_usage_tag', fread(fid,1,'uint32'));     %Defines how following user CVs are to be filled in
                                                 %Default value = 0x00000000
                                                  %GE range = 0x00000001 - 0x7fffffff
                                                  %Research = 0x80000000 - 0xffffffff
im_hdr = setfield(im_hdr, 'user_fill_mapMSW', fread(fid,1,'uint32'));   %Define what process fills in the user CVs, ifcc or TIR
im_hdr = setfield(im_hdr, 'user_fill_mapLSW', fread(fid,1,'uint32'));   %Define what process fills in the user CVs, ifcc or TIR
im_hdr = setfield(im_hdr, 'user25', fread(fid,1,'float32'));             %User Variable 25
im_hdr = setfield(im_hdr, 'user26', fread(fid,1,'float32'));             %User Variable 26
im_hdr = setfield(im_hdr, 'user27', fread(fid,1,'float32'));             %User Variable 27
im_hdr = setfield(im_hdr, 'user28', fread(fid,1,'float32'));             %User Variable 28
im_hdr = setfield(im_hdr, 'user29', fread(fid,1,'float32'));             %User Variable 29
im_hdr = setfield(im_hdr, 'user30', fread(fid,1,'float32'));             %User Variable 30
im_hdr = setfield(im_hdr, 'user31', fread(fid,1,'float32'));             %User Variable 31
im_hdr = setfield(im_hdr, 'user32', fread(fid,1,'float32'));             %User Variable 32
im_hdr = setfield(im_hdr, 'user33', fread(fid,1,'float32'));             %User Variable 33
im_hdr = setfield(im_hdr, 'user34', fread(fid,1,'float32'));             %User Variable 34
im_hdr = setfield(im_hdr, 'user35', fread(fid,1,'float32'));             %User Variable 35
im_hdr = setfield(im_hdr, 'user36', fread(fid,1,'float32'));             %User Variable 36
im_hdr = setfield(im_hdr, 'user37', fread(fid,1,'float32'));             %User Variable 37
im_hdr = setfield(im_hdr, 'user38', fread(fid,1,'float32'));             %User Variable 38
im_hdr = setfield(im_hdr, 'user39', fread(fid,1,'float32'));             %User Variable 39
im_hdr = setfield(im_hdr, 'user40', fread(fid,1,'float32'));             %User Variable 40
im_hdr = setfield(im_hdr, 'user41', fread(fid,1,'float32'));             %User Variable 41
im_hdr = setfield(im_hdr, 'user42', fread(fid,1,'float32'));             %User Variable 42
im_hdr = setfield(im_hdr, 'user43', fread(fid,1,'float32'));             %User Variable 43
im_hdr = setfield(im_hdr, 'user44', fread(fid,1,'float32'));             %User Variable 44
im_hdr = setfield(im_hdr, 'user45', fread(fid,1,'float32'));             %User Variable 45
im_hdr = setfield(im_hdr, 'user46', fread(fid,1,'float32'));             %User Variable 46
im_hdr = setfield(im_hdr, 'user47', fread(fid,1,'float32'));             %User Variable 47
im_hdr = setfield(im_hdr, 'user48', fread(fid,1,'float32'));             %User Variable 48
im_hdr = setfield(im_hdr, 'slop_int_6', fread(fid,1,'int32'));         %Integer Slop Field 6
im_hdr = setfield(im_hdr, 'slop_int_7', fread(fid,1,'int32'));         %Integer Slop Field 7
im_hdr = setfield(im_hdr, 'slop_int_8', fread(fid,1,'int32'));         %Integer Slop Field 8
im_hdr = setfield(im_hdr, 'slop_int_9', fread(fid,1,'int32'));         %Integer Slop Field 9
im_hdr = setfield(im_hdr, 'mr_padding', fread(fid,32,'uchar'));    %Spare Space

return


text:
@interface PKTransFinalController ()

@property (nonatomic,strong) UILabel * totalLabel;

@end

@implementation PKTransFinalController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self pick_setNavWithTitle:@"调拨完成"];
}

-(void)createView{

    for(UIView * subView in self.view.subviews){
        [subView removeFromSuperview];
    }

    [self pick_configViewWithPickOutImg:@"finish"];

    UIImageView * imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, NAV_BAR_HEIGHT+100*S6,147/2*S6, 73*S6)];
    imgView.centerX = self.view.centerX;
    [self getBundleImg:@"duigou" callback:^(NSData *imgData) {
        imgView.image = [UIImage imageWithData:imgData];
    }];
    [self.view addSubview:imgView];

    UILabel * titleLable = [Tools createLabelWithFrame:CGRectMake(0, CGRectGetMaxY(imgView.frame)+50*S6, Wscreen,26*S6) textContent:@"调拨出库已全部完成" withFont:[UIFont systemFontOfSize:26*S6] textColor:[UIColor blackColor] textAlignment:NSTextAlignmentCenter];
    titleLable.centerX = self.view.centerX;
    [self.view addSubview:titleLable];

    self.totalLabel = [Tools createLabelWithFrame:CGRectMake(0, CGRectGetMaxY(titleLable.frame)+30*S6, Wscreen-100*S6, 50*S6) textContent:@"" withFont:[UIFont systemFontOfSize:22*S6] textColor:[UIColor blackColor] textAlignment:NSTextAlignmentCenter];
    self.totalLabel.centerX = self.view.centerX;
    self.totalLabel.layer.cornerRadius = 3*S6;
    self.totalLabel.layer.masksToBounds = YES;
    self.totalLabel.layer.borderColor = [PICKER_BORDER_COLOR CGColor];
    self.totalLabel.layer.borderWidth = 1.0*S6;
    [self.view addSubview:self.totalLabel];

    UILabel * descripeLable = [Tools createLabelWithFrame:CGRectMake(0, CGRectGetMaxY(self.totalLabel.frame)+20*S6, Wscreen-135*S6, 60*S6) textContent:@"请把已调拨出库的货品移交至验货台,并当场确认完成交交接。" withFont:[UIFont systemFontOfSize:17*S6] textColor:PICKER_TETMAIN_COLOR textAlignment:NSTextAlignmentLeft];
    descripeLable.centerX = self.view.centerX;
    descripeLable.numberOfLines = 0;
    [self.view addSubview:descripeLable];

    UIButton * checkBtn = [Tools createNormalButtonWithFrame:CGRectMake(0, CGRectGetMaxY(descripeLable.frame)+50*S6, 280*S6, 35*S6) textContent:@"查看已完成任务" withFont:[UIFont systemFontOfSize:15*S6] textColor:[UIColor whiteColor] textAlignment:NSTextAlignmentCenter];
    checkBtn.centerX = self.view.centerX;
    [checkBtn setTitleColor:RGB_COLOR(29, 29, 29, 0.8) forState:UIControlStateHighlighted];
    checkBtn.backgroundColor = PICKER_NAV_COLOR;
    checkBtn.layer.cornerRadius = 35/2.0*S6;
    checkBtn.layer.masksToBounds = YES;
    [self.view addSubview:checkBtn];

    [checkBtn addTarget:self action:@selector(checkAction) forControlEvents:UIControlEventTouchUpInside];

    [self createData];
}

-(void)createData{

    NSDictionary * dict = @{@"model":@"internal.trans.mobile",@"method":@"get_state",@"args":@[@""],@"kwargs":@{}};
    [PickerNetManager pick_requestPickerDataWithURL:PICKER_TASK param:dict callback:^(id responseObject, NSError *error) {
        if(error == nil){

            if([responseObject integerValue]== 0){
                [self dealWithResult];
            }
        }else{
            [self pick_loginByThirdParty:error];
        }
    }];
}

-(void)dealWithResult{

    [KUSERDEFAUL setValue:self.responseObj[@"data"][@"id"] forKey:PKTransServerID];
    NSLog(@"最后界面的值: %@; 类型:%@",[KUSERDEFAUL objectForKey:PKTransServerID],[[KUSERDEFAUL objectForKey:SERVEALERTID] class]);
    [[NSNotificationCenter defaultCenter]postNotificationName:PKTransFinishedNotice object:nil];

    NSString * total = [NSString stringWithFormat:@"分拣盘内总数: %@",self.responseObj[@"data"][@"total"]];
    self.totalLabel.text = total;
}

-(void)checkAction{

    PKTransController * pickOutVc = [[PKTransController alloc]initWithData:self.responseObj fromVc:self];
    [self pushToViewControllerWithTransition:pickOutVc withDirection:@"left" type:NO];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

redpajama_set_name: RedPajamaGithub


text:
/* TEMPLATE GENERATED TESTCASE FILE
Filename: CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_82_bad.cpp
Label Definition File: CWE121_Stack_Based_Buffer_Overflow__CWE805.label.xml
Template File: sources-sink-82_bad.tmpl.cpp
*/
/*
 * @description
 * CWE: 121 Stack Based Buffer Overflow
 * BadSource:  Set data pointer to the bad buffer
 * GoodSource: Set data pointer to the good buffer
 * Sinks: loop
 *    BadSink : Copy int64_t array to data using a loop
 * Flow Variant: 82 Data flow: data passed in a parameter to an virtual method called via a pointer
 *
 * */
#ifndef OMITBAD

#include "std_testcase.h"
#include "CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_82.h"

namespace CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_82
{

void CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_82_bad::action(int64_t * data)
{
    {
        int64_t source[100] = {0}; /* fill with 0's */
        {
            size_t i;
            /* POTENTIAL FLAW: Possible buffer overflow if data < 100 */
            for (i = 0; i < 100; i++)
            {
                data[i] = source[i];
            }
            printLongLongLine(data[0]);
        }
    }
}

}
#endif /* OMITBAD */


text:
package benchmark;

import com.carrotsearch.junitbenchmarks.AbstractBenchmark;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.Clock;
import com.carrotsearch.junitbenchmarks.annotation.BenchmarkMethodChart;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.osgl.util.S;

@BenchmarkOptions(benchmarkRounds = 15000, warmupRounds = 1000, clock = Clock.NANO_TIME)
@BenchmarkMethodChart(filePrefix = "map-types-benchmark-barchart")
public class StringConcatBenchmark extends AbstractBenchmark {

    private static String s1;
    private static String s2;
    private static String s3;
    private static String s4;
    private static String s5;
    private static String s6;
    private static String s12;
    private static int i12;
    private static String s123;
    private static int i123;
    private static String s123456;
    private static int i123456;

    @BeforeClass
    public static void prepare() {
        s1 = S.random();
        s2 = S.random();
        s3 = S.random();
        s4 = S.random();
        s5 = S.random();
        s6 = S.random();
        s12 = s1 + s2;
        i12 = s12.length();
        s123 = s12 + s3;
        i123 = s123.length();
        s123456 = s123 + s4 + s5 + s6;
        i123456 = s123456.length();
    }

    @Test
    public void _ignore() {
        String s = new StringBuilder(s1).append(s2).append(s3).append(s4).append(s5).append(s6).toString();
        for (int i = 0; i < 1000; ++i) {
            s = new StringBuilder(s1).append(s2).append(s3).append(s4).append(s5).append(s6).toString();
        }
        Assert.assertSame(i123456, s.length());
    }

    @Test
    public void concat6a() {
        String s = S.concat(s1, s2, s3, s4, s5, s6);
        for (int i = 0; i < 1000; ++i) {
            s = S.concat(s1, s2, s3, s4, s5, s6);
        }
        Assert.assertSame(i123456, s.length());
    }

}


text:
// Copyright (c) rubicon IT GmbH, www.rubicon.eu
//
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership.  rubicon licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License.  You may obtain a copy of the
// License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations
// under the License.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using Remotion.Linq.Parsing.Structure.IntermediateModel;

namespace Remotion.Linq.Parsing.Structure.NodeTypeProviders
{
	/// <summary>
	/// Maps the <see cref="MethodInfo"/> objects used in <see cref="MethodCallExpression"/> objects to the respective <see cref="IExpressionNode"/>
	/// types. This is used by <see cref="ExpressionTreeParser"/> when a <see cref="MethodCallExpression"/> is encountered to instantiate the
	/// right <see cref="IExpressionNode"/> for the given method.
	/// </summary>
	public sealed class MethodInfoBasedNodeTypeRegistry : INodeTypeProvider
	{
		private static readonly Dictionary<MethodInfo, Lazy<MethodInfo[]>> s_genericMethodDefinitionCandidates =
			new Dictionary<MethodInfo, Lazy<MethodInfo[]>>();

		/// <summary>
		/// Creates a <see cref="MethodInfoBasedNodeTypeRegistry"/> and automatically registers all types implementing <see cref="IExpressionNode"/>
		/// from a given type sequence that offer a public static <c>SupportedMethods</c> field.
		/// </summary>
		/// <returns>A <see cref="MethodInfoBasedNodeTypeRegistry"/> with all <see cref="IExpressionNode"/> types with a <c>SupportedMethods</c>
		/// field registered.</returns>
		public static MethodInfoBasedNodeTypeRegistry CreateFromTypes(IEnumerable<Type> searchedTypes)
		{
			var expressionNodeTypes =
				from t in searchedTypes
				where typeof(IExpressionNode).IsAssignableFrom(t)
				select t;

			var supportedMethodsForTypes =
				from t in expressionNodeTypes
				let supportedMethodsField = t.GetField("SupportedMethods")
				select new
					   {
						   Type = t,
						   Methods =
							   supportedMethodsField != null && supportedMethodsField.IsStatic
								   ? (IEnumerable<MethodInfo>)supportedMethodsField.GetValue(null)
								   : Enumerable.Empty<MethodInfo>()
					   };

			var registry = new MethodInfoBasedNodeTypeRegistry();

			foreach (var methodsForType in supportedMethodsForTypes)
			{
				registry.Register(methodsForType.Methods, methodsForType.Type);
			}

			return registry;
		}

		/// <summary>
		/// Gets the registerable method definition from a given <see cref="MethodInfo"/>. A registerable method is a <see cref="MethodInfo"/> object
		/// that can be registered via a call to <see cref="Register"/>. When the given <paramref name="method"/> is passed to
		/// <see cref="GetNodeType"/> and its corresponding registerable method was registered, the correct node type is returned.
		/// </summary>
		/// <param name="method">The method for which the registerable method should be retrieved. Must not be <see langword="null" />.</param>
		/// <param name="throwOnAmbiguousMatch">
		///   <see langword="true" /> to throw a <see cref="NotSupportedException"/> if the method cannot be matched to a distinct generic method definition,
		///   <see langword="false" /> to return <see langword="null" /> if an unambiguous match is not possible.
		/// </param>
		/// <returns>
		/// <para>
		///   <paramref name="method"/> itself, unless it is a closed generic method or declared in a closed generic type. In the latter cases,
		///   the corresponding generic method definition respectively the method declared in a generic type definition is returned.
		/// </para><para>
		///   If no generic method definition could be matched and <paramref name="throwOnAmbiguousMatch"/> was set to <see langword="false" />,
		///   <see langword="null" /> is returned.
		/// </para>
		/// </returns>
		/// <exception cref="NotSupportedException">
		/// Thrown if <paramref name="throwOnAmbiguousMatch"/> is set to <see langword="true" /> and no distinct generic method definition could be resolved.
		/// </exception>
		public static MethodInfo GetRegisterableMethodDefinition(MethodInfo method, bool throwOnAmbiguousMatch)
		{
			var genericMethodDefinition = method.IsGenericMethod ? method.GetGenericMethodDefinition() : method;
			if (!genericMethodDefinition.DeclaringType.IsGenericType)
				return genericMethodDefinition;

			// Simple, fast solution, not possible in PCL because of missing MethodHandle property on MethodInfo type:
			// var declaringTypeDefinition = genericMethodDefinition.DeclaringType.GetGenericTypeDefinition();
			// return (MethodInfo) MethodBase.GetMethodFromHandle (genericMethodDefinition.MethodHandle, declaringTypeDefinition.TypeHandle);

			Lazy<MethodInfo[]> candidates;
			lock (s_genericMethodDefinitionCandidates)
			{
				if (!s_genericMethodDefinitionCandidates.TryGetValue(method, out candidates))
				{
					candidates = new Lazy<MethodInfo[]>(
						() => GetGenericMethodDefinitionCandidates(genericMethodDefinition),
						LazyThreadSafetyMode.ExecutionAndPublication);
					s_genericMethodDefinitionCandidates.Add(method, candidates);
				}
			}

			if (candidates.Value.Length == 1)
				return candidates.Value[0];

			if (!throwOnAmbiguousMatch)
				return null;

			throw new NotSupportedException(
				string.Format(
					"A generic method definition cannot be resolved for method '{0}' on type '{1}' because a distinct match is not possible. "
					+ @"The method can still be registered using the following syntax:

public static readonly NameBasedRegistrationInfo[] SupportedMethodNames =
	new[] {{
		new NameBasedRegistrationInfo (
			""{2}"",
			mi => /* match rule based on MethodInfo */
		)
	}};",
					method,
					genericMethodDefinition.DeclaringType.GetGenericTypeDefinition(),
					method.Name));
		}

		private static MethodInfo[] GetGenericMethodDefinitionCandidates(MethodInfo referenceMethodDefinition)
		{
			var declaringTypeDefinition = referenceMethodDefinition.DeclaringType.GetGenericTypeDefinition();

			var referenceMethodSignature =
				new[] { new { Name = "returnValue", Type = referenceMethodDefinition.ReturnType } }
					.Concat(referenceMethodDefinition.GetParameters().Select(p => new { Name = p.Name, Type = p.ParameterType }))
					.ToArray();

			var candidates = declaringTypeDefinition.GetMethods()
				.Select(
					m => new
						 {
							 Method = m,
							 SignatureNames = new[] { "returnValue" }.Concat(m.GetParameters().Select(p => p.Name)).ToArray(),
							 SignatureTypes = new[] { m.ReturnType }.Concat(m.GetParameters().Select(p => p.ParameterType)).ToArray()
						 })
				.Where(c => c.Method.Name == referenceMethodDefinition.Name && c.SignatureTypes.Length == referenceMethodSignature.Length)
				.ToArray();

			for (int i = 0; i < referenceMethodSignature.Length; i++)
			{
				candidates = candidates
					.Where(c => c.SignatureNames[i] == referenceMethodSignature[i].Name)
					.Where(c => c.SignatureTypes[i] == referenceMethodSignature[i].Type || c.SignatureTypes[i].ContainsGenericParameters)
					.ToArray();
			}

			return candidates.Select(c => c.Method).ToArray();
		}

		private readonly Dictionary<MethodInfo, Type> _registeredMethodInfoTypes = new Dictionary<MethodInfo, Type>();

		/// <summary>
		/// Returns the count of the registered <see cref="MethodInfo"/>s.
		/// </summary>
		public int RegisteredMethodInfoCount
		{
			get { return _registeredMethodInfoTypes.Count; }
		}

		/// <summary>
		/// Registers the specific <paramref name="methods"/> with the given <paramref name="nodeType"/>. The given methods must either be non-generic
		/// or open generic method definitions. If a method has already been registered before, the later registration overwrites the earlier one.
		/// </summary>
		public void Register(IEnumerable<MethodInfo> methods, Type nodeType)
		{
			foreach (var method in methods)
			{
				if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
				{
					var message = string.Format(
						"Cannot register closed generic method '{0}', try to register its generic method definition instead.", method.Name);
					throw new InvalidOperationException(message);
				}

				if (method.DeclaringType.IsGenericType && !method.DeclaringType.IsGenericTypeDefinition)
				{
					var message = string.Format(
						"Cannot register method '{0}' in closed generic type '{1}', try to register its equivalent in the generic type definition instead.",
						method.Name,
						method.DeclaringType);
					throw new InvalidOperationException(message);
				}

				_registeredMethodInfoTypes[method] = nodeType;
			}
		}

		/// <summary>
		/// Determines whether the specified method was registered with this <see cref="MethodInfoBasedNodeTypeRegistry"/>.
		/// </summary>
		public bool IsRegistered(MethodInfo method)
		{
			return GetNodeType(method) != null;
		}

		/// <summary>
		/// Gets the type of <see cref="IExpressionNode"/> registered with this <see cref="MethodInfoBasedNodeTypeRegistry"/> instance that
		/// matches the given <paramref name="method"/>, returning <see langword="null" /> if none can be found.
		/// </summary>
		public Type GetNodeType(MethodInfo method)
		{
			var methodDefinition = GetRegisterableMethodDefinition(method, throwOnAmbiguousMatch: false);
			if (methodDefinition == null)
				return null;

			Type result;
			_registeredMethodInfoTypes.TryGetValue(methodDefinition, out result);
			return result;
		}
	}
}


text:
using System.Diagnostics.Contracts;
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Text;
using System.Threading.Tasks;

namespace System.ServiceModel.Channels
{
    internal class SocketConnection : IConnection
    {
        private static EventHandler<SocketAsyncEventArgs> s_onReceiveAsyncCompleted;
        private static EventHandler<SocketAsyncEventArgs> s_onSocketSendCompleted;

        // common state
        private Socket _socket;
        private bool _noDelay = false;
        private TimeSpan _sendTimeout;
        private TimeSpan _receiveTimeout;
        private CloseState _closeState;
        private bool _aborted;

        // close state
        private static Action<object> s_onWaitForFinComplete = new Action<object>(OnWaitForFinComplete);
        private TimeoutHelper _closeTimeoutHelper;
        private bool _isShutdown;

        // read state
        private SocketAsyncEventArgs _asyncReadEventArgs;
        private TimeSpan _readFinTimeout;
        private int _asyncReadSize;
        private byte[] _readBuffer;
        private int _asyncReadBufferSize;
        private object _asyncReadState;
        private Action<object> _asyncReadCallback;
        private Exception _asyncReadException;
        private bool _asyncReadPending;

        // write state
        private SocketAsyncEventArgs _asyncWriteEventArgs;
        private object _asyncWriteState;
        private Action<object> _asyncWriteCallback;
        private Exception _asyncWriteException;
        private bool _asyncWritePending;

        private static Action<SocketConnection> s_onSendTimeout;
        private static Action<SocketConnection> s_onReceiveTimeout;
        private IOTimer<SocketConnection> _receiveTimer;
        private IOTimer<SocketConnection> _sendTimer;
        private string _timeoutErrorString;
        private TransferOperation _timeoutErrorTransferOperation;
        private ConnectionBufferPool _connectionBufferPool;
        private string _remoteEndpointAddressString;

        public SocketConnection(Socket socket, ConnectionBufferPool connectionBufferPool)
        {
            _connectionBufferPool = connectionBufferPool ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(connectionBufferPool));
            _socket = socket ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(socket));
            _closeState = CloseState.Open;
            _readBuffer = _connectionBufferPool.Take();
            _asyncReadBufferSize = _readBuffer.Length;
            _sendTimeout = _receiveTimeout = TimeSpan.MaxValue;
            _closeState = CloseState.Open;
            _socket.SendBufferSize = _socket.ReceiveBufferSize = _asyncReadBufferSize;
            _sendTimeout = _receiveTimeout = TimeSpan.MaxValue;
        }

        public int AsyncReadBufferSize
        {
            get { return _asyncReadBufferSize; }
        }

        public byte[] AsyncReadBuffer
        {
            get { return _readBuffer; }
        }

        private object ThisLock
        {
            get { return this; }
        }

        private IOTimer<SocketConnection> SendTimer
        {
            get
            {
                if (_sendTimer == null)
                {
                    if (s_onSendTimeout == null)
                    {
                        s_onSendTimeout = OnSendTimeout;
                    }

                    _sendTimer = new IOTimer<SocketConnection>(s_onSendTimeout, this);
                }

                return _sendTimer;
            }
        }

        private IOTimer<SocketConnection> ReceiveTimer
        {
            get
            {
                if (_receiveTimer == null)
                {
                    if (s_onReceiveTimeout == null)
                    {
                        s_onReceiveTimeout = OnReceiveTimeout;
                    }

                    _receiveTimer = new IOTimer<SocketConnection>(s_onReceiveTimeout, this);
                }

                return _receiveTimer;
            }
        }

        private IPEndPoint RemoteEndPoint
        {
            get
            {
                if (!_socket.Connected)
                {
                    return null;
                }

                return (IPEndPoint)_socket.RemoteEndPoint;
            }
        }

        private string RemoteEndpointAddressString
        {
            get
            {
                if (_remoteEndpointAddressString == null)
                {
                    IPEndPoint remote = RemoteEndPoint;
                    if (remote == null)
                    {
                        return string.Empty;
                    }
                    _remoteEndpointAddressString = remote.Address + ":" + remote.Port;
                }

                return _remoteEndpointAddressString;
            }
        }

        private static void OnReceiveAsyncCompleted(object sender, SocketAsyncEventArgs e)
        {
            ((SocketConnection)e.UserToken).OnReceiveAsync(sender, e);
        }

        private static void OnSendAsyncCompleted(object sender, SocketAsyncEventArgs e)
        {
            ((SocketConnection)e.UserToken).OnSendAsync(sender, e);
        }

        private static void OnWaitForFinComplete(object state)
        {
            // Callback for read on a socket which has had Shutdown called on it. When
            // the response FIN packet is received from the remote host, the pending
            // read will complete with 0 bytes read. If more than 0 bytes has been read,
            // then something has gone wrong as we should have no pending data to be received.
            SocketConnection thisPtr = (SocketConnection)state;

            try
            {
                int bytesRead;

                try
                {
                    bytesRead = thisPtr.EndRead();

                    if (bytesRead > 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, thisPtr.RemoteEndPoint)));
                    }
                }
                catch (TimeoutException timeoutException)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
                        SR.Format(SR.SocketCloseReadTimeout, thisPtr.RemoteEndPoint, thisPtr._readFinTimeout),
                        timeoutException));
                }

                thisPtr.ContinueClose(thisPtr._closeTimeoutHelper.RemainingTime());
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                Fx.Exception.TraceUnhandledException(e);

                // The user has no opportunity to clean up the connection in the async and linger
                // code path, ensure cleanup finishes.
                thisPtr.Abort();
            }
        }

        private static void OnReceiveTimeout(SocketConnection socketConnection)
        {
            try
            {
                socketConnection.Abort(SR.Format(SR.SocketAbortedReceiveTimedOut, socketConnection._receiveTimeout), TransferOperation.Read);
            }
            catch (SocketException)
            {
                // Guard against unhandled SocketException in timer callbacks
            }
        }

        private static void OnSendTimeout(SocketConnection socketConnection)
        {
            try
            {
                socketConnection.Abort(4,	// TraceEventType.Warning
                    SR.Format(SR.SocketAbortedSendTimedOut, socketConnection._sendTimeout), TransferOperation.Write);
            }
            catch (SocketException)
            {
                // Guard against unhandled SocketException in timer callbacks
            }
        }

        public void Abort()
        {
            Abort(null, TransferOperation.Undefined);
        }

        private void Abort(string timeoutErrorString, TransferOperation transferOperation)
        {
            int traceEventType = 4;	// TraceEventType.Warning;

            // we could be timing out a cached connection

            Abort(traceEventType, timeoutErrorString, transferOperation);
        }

        private void Abort(int traceEventType)
        {
            Abort(traceEventType, null, TransferOperation.Undefined);
        }

        private void Abort(int traceEventType, string timeoutErrorString, TransferOperation transferOperation)
        {
            lock (ThisLock)
            {
                if (_closeState == CloseState.Closed)
                {
                    return;
                }

                _timeoutErrorString = timeoutErrorString;
                _timeoutErrorTransferOperation = transferOperation;
                _aborted = true;
                _closeState = CloseState.Closed;

                if (!_asyncReadPending)
                {
                    DisposeReadEventArgs();
                }

                if (!_asyncWritePending)
                {
                    DisposeWriteEventArgs();
                }

                DisposeReceiveTimer();
                DisposeSendTimer();
            }

            _socket.LingerState = new LingerOption(true, 0);
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Dispose();
        }

        private void AbortRead()
        {
            lock (ThisLock)
            {
                if (_asyncReadPending)
                {
                    if (_closeState != CloseState.Closed)
                    {
                        SetUserToken(_asyncReadEventArgs, null);
                        _asyncReadPending = false;
                        CancelReceiveTimer();
                    }
                    else
                    {
                        DisposeReadEventArgs();
                    }
                }
            }
        }

        private void CancelReceiveTimer()
        {
            if (_receiveTimer != null)
            {
                _receiveTimer.Cancel();
            }
        }

        private void CancelSendTimer()
        {
            _sendTimer?.Cancel();
        }

        private void CloseAsyncAndLinger()
        {
            _readFinTimeout = _closeTimeoutHelper.RemainingTime();

            try
            {
                // A FIN (shutdown) packet has already been sent to the remote host and we're waiting for the remote
                // host to send a FIN back. A pending read on a socket will complete returning zero bytes when a FIN
                // packet is received.
                if (BeginReadCore(0, 1, _readFinTimeout, s_onWaitForFinComplete, this) == AsyncCompletionResult.Queued)
                {
                    return;
                }

                int bytesRead = EndRead();

                // Any NetTcp session handshake will have been completed at this point so if any data is returned, something
                // very wrong has happened.
                if (bytesRead > 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, RemoteEndPoint)));
                }
            }
            catch (TimeoutException timeoutException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
                    SR.Format(SR.SocketCloseReadTimeout, RemoteEndPoint, _readFinTimeout), timeoutException));
            }

            ContinueClose(_closeTimeoutHelper.RemainingTime());
        }

        public void Close(TimeSpan timeout, bool asyncAndLinger)
        {
            lock (ThisLock)
            {
                if (_closeState == CloseState.Closing || _closeState == CloseState.Closed)
                {
                    // already closing or closed, so just return
                    return;
                }
                _closeState = CloseState.Closing;
            }

            _closeTimeoutHelper = new TimeoutHelper(timeout);

            // first we shutdown our send-side
            Shutdown(timeout);
            CloseCore(asyncAndLinger);
        }

        private void CloseCore(bool asyncAndLinger)
        {
            if (asyncAndLinger)
            {
                CloseAsyncAndLinger();
            }
            else
            {
                CloseSync();
            }
        }

        private void CloseSync()
        {
            byte[] dummy = new byte[1];

            // A FIN (shutdown) packet has already been sent to the remote host and we're waiting for the remote
            // host to send a FIN back. A pending read on a socket will complete returning zero bytes when a FIN
            // packet is received.

            int bytesRead;
            _readFinTimeout = _closeTimeoutHelper.RemainingTime();

            try
            {
                bytesRead = ReadCore(dummy, 0, 1, _readFinTimeout, true);

                // Any NetTcp session handshake will have been completed at this point so if any data is returned, something
                // very wrong has happened.
                if (bytesRead > 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, RemoteEndPoint)));
                }
            }
            catch (TimeoutException timeoutException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
                    SR.Format(SR.SocketCloseReadTimeout, RemoteEndPoint, _readFinTimeout), timeoutException));
            }

            // finally we call Close with whatever time is remaining
            ContinueClose(_closeTimeoutHelper.RemainingTime());
        }

        private void ContinueClose(TimeSpan timeout)
        {
            // Use linger to attempt a graceful socket shutdown. Allowing a clean shutdown handshake
            // will allow the service side to close it's socket gracefully too. A hard shutdown would
            // cause the server to receive an exception which affects performance and scalability.
            _socket.LingerState = new LingerOption(true, (int)timeout.TotalSeconds);
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Dispose();

            lock (ThisLock)
            {
                // Abort could have been called on a separate thread and cleaned up
                // our buffers/completion here
                if (_closeState != CloseState.Closed)
                {
                    if (!_asyncReadPending)
                    {
                        DisposeReadEventArgs();
                    }

                    if (!_asyncWritePending)
                    {
                        DisposeWriteEventArgs();
                    }
                }

                _closeState = CloseState.Closed;
                DisposeReceiveTimer();
                DisposeSendTimer();
            }
        }

        private void Shutdown(TimeSpan timeout)
        {
            lock (ThisLock)
            {
                if (_isShutdown)
                {
                    return;
                }

                _isShutdown = true;
            }

            ShutdownCore(timeout);
        }

        private void ShutdownCore(TimeSpan timeout)
        {
            // Attempt to close the socket gracefully by sending a shutdown (FIN) packet
            try
            {
                _socket.Shutdown(SocketShutdown.Send);
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertSendException(socketException, TimeSpan.MaxValue));
            }
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
                if (ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow);
                }
            }
        }

        private void ThrowIfNotOpen()
        {
            if (_closeState == CloseState.Closing || _closeState == CloseState.Closed)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertObjectDisposedException(new ObjectDisposedException(
                    this.GetType().ToString(), SR.SocketConnectionDisposed), TransferOperation.Undefined));
            }
        }

        private void ThrowIfClosed()
        {
            if (_closeState == CloseState.Closed)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertObjectDisposedException(new ObjectDisposedException(
                    this.GetType().ToString(), SR.SocketConnectionDisposed), TransferOperation.Undefined));
            }
        }

        private Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime)
        {
            return ConvertTransferException(socketException, _sendTimeout, socketException,
                _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime);
        }

        private Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime)
        {
            return ConvertTransferException(socketException, _receiveTimeout, socketException,
                _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime);
        }

        internal static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException)
        {
            return ConvertTransferException(socketException, timeout, originalException,
                false, null, TransferOperation.Undefined, null, TimeSpan.MaxValue);
        }

        private Exception ConvertObjectDisposedException(ObjectDisposedException originalException, TransferOperation transferOperation)
        {
            if (_timeoutErrorString != null)
            {
                return ConvertTimeoutErrorException(originalException, _timeoutErrorString, _timeoutErrorTransferOperation);
            }
            else if (_aborted)
            {
                return new CommunicationObjectAbortedException(SR.SocketConnectionDisposed, originalException);
            }
            else
            {
                return originalException;
            }
        }

        private static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException,
            bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation,
            SocketConnection socketConnection, TimeSpan remainingTime)
        {
            if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
            {
                return new CommunicationObjectAbortedException(socketException.Message, socketException);
            }

            if (timeoutErrorString != null)
            {
                return ConvertTimeoutErrorException(originalException, timeoutErrorString, timeoutErrorTransferOperation);
            }

            // 10053 can occur due to our timeout sockopt firing, so map to TimeoutException in that case
            if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNABORTED &&
                remainingTime <= TimeSpan.Zero)
            {
                TimeoutException timeoutException = new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout), originalException);
                return timeoutException;
            }

            if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAENETRESET ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNABORTED ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNRESET)
            {
                if (aborted)
                {
                    return new CommunicationObjectAbortedException(SR.TcpLocalConnectionAborted, originalException);
                }
                else
                {
                    CommunicationException communicationException = new CommunicationException(SR.Format(SR.TcpConnectionResetError, timeout), originalException);
                    return communicationException;
                }
            }
            else if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
            {
                TimeoutException timeoutException = new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout), originalException);
                return timeoutException;
            }
            else
            {
                if (aborted)
                {
                    return new CommunicationObjectAbortedException(SR.Format(SR.TcpTransferError, (int)socketException.SocketErrorCode, socketException.Message), originalException);
                }
                else
                {
                    CommunicationException communicationException = new CommunicationException(SR.Format(SR.TcpTransferError, (int)socketException.SocketErrorCode, socketException.Message), originalException);
                    return communicationException;
                }
            }
        }

        private static Exception ConvertTimeoutErrorException(Exception originalException, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation)
        {
            Contract.Assert(timeoutErrorString != null, "Argument timeoutErrorString must not be null.");

            if (timeoutErrorTransferOperation != TransferOperation.Undefined)
            {
                return new TimeoutException(timeoutErrorString, originalException);
            }
            else
            {
                return new CommunicationException(timeoutErrorString, originalException);
            }
        }

        public AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
            Action<object> callback, object state)
        {
            if (WcfEventSource.Instance.SocketAsyncWriteStartIsEnabled())
            {
                TraceWriteStart(size, true);
            }

            return BeginWriteCore(buffer, offset, size, immediate, timeout, callback, state);
        }

        private void TraceWriteStart(int size, bool async)
        {
            if (!async)
            {
                WcfEventSource.Instance.SocketWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddressString);
            }
            else
            {
                WcfEventSource.Instance.SocketAsyncWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddressString);
            }
        }

        private AsyncCompletionResult BeginWriteCore(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
            Action<object> callback, object state)
        {
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
            bool abortWrite = true;

            try
            {
                lock (ThisLock)
                {
                    Contract.Assert(!_asyncWritePending, "Called BeginWrite twice.");
                    ThrowIfClosed();
                    EnsureWriteEventArgs();
                    SetImmediate(immediate);
                    SetWriteTimeout(timeout, false);
                    SetUserToken(_asyncWriteEventArgs, this);
                    _asyncWritePending = true;
                    _asyncWriteCallback = callback;
                    _asyncWriteState = state;
                }

                _asyncWriteEventArgs.SetBuffer(buffer, offset, size);

                if (_socket.SendAsync(_asyncWriteEventArgs))
                {
                    abortWrite = false;
                    return AsyncCompletionResult.Queued;
                }

                HandleSendAsyncCompleted();
                abortWrite = false;
                return AsyncCompletionResult.Completed;
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertSendException(socketException, TimeSpan.MaxValue));
            }
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
                if (ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow);
                }
            }
            finally
            {
                if (abortWrite)
                {
                    AbortWrite();
                }
            }
        }

        public void EndWrite()
        {
            EndWriteCore();
        }

        private void EndWriteCore()
        {
            if (_asyncWriteException != null)
            {
                AbortWrite();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(_asyncWriteException);
            }

            lock (ThisLock)
            {
                if (!_asyncWritePending)
                {
                    Contract.Assert(false, "SocketConnection.EndWrite called with no write pending.");
                    throw new Exception("SocketConnection.EndWrite called with no write pending.");
                }

                SetUserToken(_asyncWriteEventArgs, null);
                _asyncWritePending = false;

                if (_closeState == CloseState.Closed)
                {
                    DisposeWriteEventArgs();
                }
            }
        }

        private void FinishWrite()
        {
            Action<object> asyncWriteCallback = _asyncWriteCallback;
            object asyncWriteState = _asyncWriteState;

            _asyncWriteState = null;
            _asyncWriteCallback = null;

            asyncWriteCallback(asyncWriteState);
        }

        public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
        {
            WriteCore(buffer, offset, size, immediate, timeout);
        }

        private void WriteCore(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
        {
            // as per http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b201213
            // we shouldn't write more than 64K synchronously to a socket
            const int maxSocketWrite = 64 * 1024;

            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);

            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            try
            {
                SetImmediate(immediate);
                int bytesToWrite = size;

                while (bytesToWrite > 0)
                {
                    SetWriteTimeout(timeoutHelper.RemainingTime(), true);
                    size = Math.Min(bytesToWrite, maxSocketWrite);
                    _socket.Send(buffer, offset, size, SocketFlags.None);
                    bytesToWrite -= size;
                    offset += size;
                    timeout = timeoutHelper.RemainingTime();
                }
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertSendException(socketException, timeoutHelper.RemainingTime()));
            }
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
                if (ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow);
                }
            }
        }

        public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
        {
            try
            {
                Write(buffer, offset, size, immediate, timeout);
            }
            finally
            {
                bufferManager.ReturnBuffer(buffer);
            }
        }

        public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
        {
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
            ThrowIfNotOpen();
            int bytesRead = ReadCore(buffer, offset, size, timeout, false);
            if (WcfEventSource.Instance.SocketReadStopIsEnabled())
            {
                TraceSocketReadStop(bytesRead, false);
            }

            return bytesRead;
        }

        private int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool closing)
        {
            int bytesRead = 0;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            try
            {
                SetReadTimeout(timeoutHelper.RemainingTime(), true, closing);
                bytesRead = _socket.Receive(buffer, offset, size, SocketFlags.None);
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    ConvertReceiveException(socketException, timeoutHelper.RemainingTime()));
            }
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
                if (ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow);
                }
            }

            return bytesRead;
        }

        public virtual AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
            Action<object> callback, object state)
        {
            ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size);
            this.ThrowIfNotOpen();
            var completionResult = this.BeginReadCore(offset, size, timeout, callback, state);
            if (completionResult == AsyncCompletionResult.Completed && WcfEventSource.Instance.SocketReadStopIsEnabled())
            {
                TraceSocketReadStop(_asyncReadSize, true);
            }

            return completionResult;
        }

        private void TraceSocketReadStop(int bytesRead, bool async)
        {
            if (!async)
            {
                WcfEventSource.Instance.SocketReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddressString);
            }
            else
            {
                WcfEventSource.Instance.SocketAsyncReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddressString);
            }
        }

        private AsyncCompletionResult BeginReadCore(int offset, int size, TimeSpan timeout,
            Action<object> callback, object state)
        {
            bool abortRead = true;

            lock (ThisLock)
            {
                ThrowIfClosed();
                EnsureReadEventArgs();
                _asyncReadState = state;
                _asyncReadCallback = callback;
                SetUserToken(_asyncReadEventArgs, this);
                _asyncReadPending = true;
                SetReadTimeout(timeout, false, false);
            }

            try
            {
                if (offset != _asyncReadEventArgs.Offset ||
                    size != _asyncReadEventArgs.Count)
                {
                    _asyncReadEventArgs.SetBuffer(offset, size);
                }

                if (ReceiveAsync())
                {
                    abortRead = false;
                    return AsyncCompletionResult.Queued;
                }

                HandleReceiveAsyncCompleted();
                _asyncReadSize = _asyncReadEventArgs.BytesTransferred;

                abortRead = false;
                return AsyncCompletionResult.Completed;
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertReceiveException(socketException, TimeSpan.MaxValue));
            }
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
                if (ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow);
                }
            }
            finally
            {
                if (abortRead)
                {
                    AbortRead();
                }
            }
        }

        private bool ReceiveAsync()
        {
            return _socket.ReceiveAsync(_asyncReadEventArgs);
        }

        private void OnReceiveAsync(object sender, SocketAsyncEventArgs eventArgs)
        {
            Contract.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
            CancelReceiveTimer();

            try
            {
                HandleReceiveAsyncCompleted();
                _asyncReadSize = eventArgs.BytesTransferred;
            }
            catch (SocketException socketException)
            {
                _asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue);
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception))
                {
                    throw;
                }
                _asyncReadException = exception;
            }

            FinishRead();
        }

        private void HandleReceiveAsyncCompleted()
        {
            if (_asyncReadEventArgs.SocketError == SocketError.Success)
            {
                return;
            }

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)_asyncReadEventArgs.SocketError));
        }

        private void FinishRead()
        {
            if (_asyncReadException != null && WcfEventSource.Instance.SocketReadStopIsEnabled())
            {
                TraceSocketReadStop(_asyncReadSize, true);
            }

            Action<object> asyncReadCallback = _asyncReadCallback;
            object asyncReadState = _asyncReadState;

            _asyncReadState = null;
            _asyncReadCallback = null;

            asyncReadCallback(asyncReadState);
        }

        // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result.
        public int EndRead()
        {
            return EndReadCore();
        }

        // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result.
        private int EndReadCore()
        {
            if (_asyncReadException != null)
            {
                AbortRead();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(_asyncReadException);
            }

            lock (ThisLock)
            {
                if (!_asyncReadPending)
                {
                    Contract.Assert(false, "SocketConnection.EndRead called with no read pending.");
                    throw new Exception("SocketConnection.EndRead called with no read pending.");
                }

                SetUserToken(_asyncReadEventArgs, null);
                _asyncReadPending = false;

                if (_closeState == CloseState.Closed)
                {
                    DisposeReadEventArgs();
                }
            }

            return _asyncReadSize;
        }

        // This method should be called inside ThisLock
        private void DisposeReadEventArgs()
        {
            if (_asyncReadEventArgs != null)
            {
                _asyncReadEventArgs.Completed -= s_onReceiveAsyncCompleted;
                _asyncReadEventArgs.Dispose();
            }

            // We release the buffer only if there is no outstanding I/O
            TryReturnReadBuffer();
        }

        // This method should be called inside ThisLock
        private void DisposeReceiveTimer()
        {
            if (_receiveTimer != null)
            {
                _receiveTimer.Dispose();
            }
        }

        private void OnSendAsync(object sender, SocketAsyncEventArgs eventArgs)
        {
            Contract.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
            CancelSendTimer();

            try
            {
                HandleSendAsyncCompleted();
                Contract.Assert(eventArgs.BytesTransferred == _asyncWriteEventArgs.Count, "The socket SendAsync did not send all the bytes.");
            }
            catch (SocketException socketException)
            {
                _asyncWriteException = ConvertSendException(socketException, TimeSpan.MaxValue);
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception))
                {
                    throw;
                }

                _asyncWriteException = exception;
            }

            FinishWrite();
        }

        private void HandleSendAsyncCompleted()
        {
            if (_asyncWriteEventArgs.SocketError == SocketError.Success)
            {
                return;
            }

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)_asyncWriteEventArgs.SocketError));
        }

        // This method should be called inside ThisLock
        private void DisposeWriteEventArgs()
        {
            if (_asyncWriteEventArgs != null)
            {
                _asyncWriteEventArgs.Completed -= s_onSocketSendCompleted;
                _asyncWriteEventArgs.Dispose();
            }
        }

        // This method should be called inside ThisLock
        private void DisposeSendTimer()
        {
            if (_sendTimer != null)
            {
                _sendTimer.Dispose();
            }
        }

        private void AbortWrite()
        {
            lock (ThisLock)
            {
                if (_asyncWritePending)
                {
                    if (_closeState != CloseState.Closed)
                    {
                        SetUserToken(_asyncWriteEventArgs, null);
                        _asyncWritePending = false;
                        CancelSendTimer();
                    }
                    else
                    {
                        DisposeWriteEventArgs();
                    }
                }
            }
        }

        // This method should be called inside ThisLock
        private void ReturnReadBuffer()
        {
            // We release the buffer only if there is no outstanding I/O
            this.TryReturnReadBuffer();
        }

        // This method should be called inside ThisLock
        private void TryReturnReadBuffer()
        {
            // The buffer must not be returned and nulled when an abort occurs. Since the buffer
            // is also accessed by higher layers, code that has not yet realized the stack is
            // aborted may be attempting to read from the buffer.
            if (_readBuffer != null && !_aborted)
            {
                _connectionBufferPool.Return(_readBuffer);
                _readBuffer = null;
            }
        }

        private void SetUserToken(SocketAsyncEventArgs args, object userToken)
        {
            // The socket args can be pinned by the overlapped callback. Ensure SocketConnection is
            // only pinned when there is outstanding IO.
            if (args != null)
            {
                args.UserToken = userToken;
            }
        }

        private void SetImmediate(bool immediate)
        {
            if (immediate != _noDelay)
            {
                lock (ThisLock)
                {
                    ThrowIfNotOpen();
                    _socket.NoDelay = immediate;
                }
                _noDelay = immediate;
            }
        }

        private void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing)
        {
            if (synchronous)
            {
                CancelReceiveTimer();

                // 0 == infinite for winsock timeouts, so we should preempt and throw
                if (timeout <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout)));
                }

                if (UpdateTimeout(_receiveTimeout, timeout))
                {
                    lock (ThisLock)
                    {
                        if (!closing || _closeState != CloseState.Closing)
                        {
                            ThrowIfNotOpen();
                        }
                        _socket.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout);
                    }
                    _receiveTimeout = timeout;
                }
            }
            else
            {
                _receiveTimeout = timeout;
                if (timeout == TimeSpan.MaxValue)
                {
                    CancelReceiveTimer();
                }
                else
                {
                    ReceiveTimer.ScheduleAfter(timeout);
                }
            }
        }

        private void SetWriteTimeout(TimeSpan timeout, bool synchronous)
        {
            if (synchronous)
            {
                CancelSendTimer();

                // 0 == infinite for winsock timeouts, so we should preempt and throw
                if (timeout <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout)));
                }

                if (UpdateTimeout(_sendTimeout, timeout))
                {
                    lock (ThisLock)
                    {
                        ThrowIfNotOpen();
                        _socket.SendTimeout = TimeoutHelper.ToMilliseconds(timeout);
                    }
                    _sendTimeout = timeout;
                }
            }
            else
            {
                _sendTimeout = timeout;
                if (timeout == TimeSpan.MaxValue)
                {
                    CancelSendTimer();
                }
                else
                {
                    SendTimer.ScheduleAfter(timeout);
                }
            }
        }

        private bool UpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout)
        {
            if (oldTimeout == newTimeout)
            {
                return false;
            }

            long threshold = oldTimeout.Ticks / 10;
            long delta = Math.Max(oldTimeout.Ticks, newTimeout.Ticks) - Math.Min(oldTimeout.Ticks, newTimeout.Ticks);

            return delta > threshold;
        }

        // This method should be called inside ThisLock
        private void EnsureReadEventArgs()
        {
            if (_asyncReadEventArgs == null)
            {
                // Init ReadAsync state
                if (s_onReceiveAsyncCompleted == null)
                {
                    s_onReceiveAsyncCompleted = new EventHandler<SocketAsyncEventArgs>(OnReceiveAsyncCompleted);
                }

                _asyncReadEventArgs = new SocketAsyncEventArgs();
                _asyncReadEventArgs.SetBuffer(_readBuffer, 0, _readBuffer.Length);
                _asyncReadEventArgs.Completed += s_onReceiveAsyncCompleted;
            }
        }

        // This method should be called inside ThisLock
        private void EnsureWriteEventArgs()
        {
            if (_asyncWriteEventArgs == null)
            {
                // Init SendAsync state
                if (s_onSocketSendCompleted == null)
                {
                    s_onSocketSendCompleted = new EventHandler<SocketAsyncEventArgs>(OnSendAsyncCompleted);
                }

                _asyncWriteEventArgs = new SocketAsyncEventArgs();
                _asyncWriteEventArgs.Completed += s_onSocketSendCompleted;
            }
        }

        public object GetCoreTransport()
        {
            return _socket;
        }

        private enum CloseState
        {
            Open,
            Closing,
            Closed,
        }

        private enum TransferOperation
        {
            Write,
            Read,
            Undefined,
        }
    }

    internal class SocketConnectionInitiator : IConnectionInitiator
    {
        private int _bufferSize;
        private ConnectionBufferPool _connectionBufferPool;

        public SocketConnectionInitiator(int bufferSize)
        {
            _bufferSize = bufferSize;
            _connectionBufferPool = new ConnectionBufferPool(bufferSize);
        }

        private IConnection CreateConnection(IPAddress address, int port)
        {
            Socket socket = null;
            try
            {
                AddressFamily addressFamily = address.AddressFamily;
                socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect(new IPEndPoint(address, port));
                return new SocketConnection(socket, _connectionBufferPool);
            }
            catch
            {
                socket.Dispose();
                throw;
            }
        }

        private async Task<IConnection> CreateConnectionAsync(IPAddress address, int port)
        {
            Socket socket = null;
            try
            {
                AddressFamily addressFamily = address.AddressFamily;
                socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
                await socket.ConnectAsync(new IPEndPoint(address, port));
                return new SocketConnection(socket, _connectionBufferPool);
            }
            catch
            {
                socket.Dispose();
                throw;
            }
        }

        public static Exception ConvertConnectException(SocketException socketException, Uri remoteUri, TimeSpan timeSpent, Exception innerException)
        {
            if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
            {
                return new CommunicationObjectAbortedException(socketException.Message, socketException);
            }

            if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAEADDRNOTAVAIL ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNREFUSED ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAENETDOWN ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAENETUNREACH ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAEHOSTDOWN ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAEHOSTUNREACH ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
            {
                if (timeSpent == TimeSpan.MaxValue)
                {
                    return new EndpointNotFoundException(SR.Format(SR.TcpConnectError, remoteUri.AbsoluteUri, (int)socketException.SocketErrorCode, socketException.Message), innerException);
                }
                else
                {
                    return new EndpointNotFoundException(SR.Format(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, (int)socketException.SocketErrorCode, socketException.Message, timeSpent), innerException);
                }
            }
            else if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAENOBUFS)
            {
                return new OutOfMemoryException(SR.TcpConnectNoBufs, innerException);
            }
            else if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES ||
                (int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_OUTOFMEMORY)
            {
                return new OutOfMemoryException(SR.InsufficentMemory, socketException);
            }
            else
            {
                if (timeSpent == TimeSpan.MaxValue)
                {
                    return new CommunicationException(SR.Format(SR.TcpConnectError, remoteUri.AbsoluteUri, (int)socketException.SocketErrorCode, socketException.Message), innerException);
                }
                else
                {
                    return new CommunicationException(SR.Format(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, (int)socketException.SocketErrorCode, socketException.Message, timeSpent), innerException);
                }
            }
        }

        private static async Task<IPAddress[]> GetIPAddressesAsync(Uri uri)
        {
            if (uri.HostNameType == UriHostNameType.IPv4 ||
                uri.HostNameType == UriHostNameType.IPv6)
            {
                IPAddress ipAddress = IPAddress.Parse(uri.DnsSafeHost);
                return new IPAddress[] { ipAddress };
            }

            IPAddress[] addresses = null;

            try
            {
                addresses = await DnsCache.ResolveAsync(uri);
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.Format(SR.UnableToResolveHost, uri.Host), socketException));
            }

            if (addresses.Length == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.Format(SR.UnableToResolveHost, uri.Host)));
            }

            return addresses;
        }

        private static TimeoutException CreateTimeoutException(Uri uri, TimeSpan timeout, IPAddress[] addresses, int invalidAddressCount,
            SocketException innerException)
        {
            StringBuilder addressStringBuilder = new StringBuilder();
            for (int i = 0; i < invalidAddressCount; i++)
            {
                if (addresses[i] == null)
                {
                    continue;
                }

                if (addressStringBuilder.Length > 0)
                {
                    addressStringBuilder.Append(", ");
                }
                addressStringBuilder.Append(addresses[i].ToString());
            }

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
                SR.Format(SR.TcpConnectingToViaTimedOut, uri.AbsoluteUri, timeout.ToString(),
                invalidAddressCount, addresses.Length, addressStringBuilder.ToString()), innerException));
        }

        public IConnection Connect(Uri uri, TimeSpan timeout)
        {
            int port = uri.Port;
            IPAddress[] addresses = SocketConnectionInitiator.GetIPAddressesAsync(uri).GetAwaiter().GetResult();
            IConnection socketConnection = null;
            SocketException lastException = null;

            if (port == -1)
            {
                port = TcpUri.DefaultPort;
            }

            int invalidAddressCount = 0;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            for (int i = 0; i < addresses.Length; i++)
            {
                if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
                }

                DateTime connectStartTime = DateTime.UtcNow;
                try
                {
                    socketConnection = CreateConnection(addresses[i], port);
                    lastException = null;
                    break;
                }
                catch (SocketException socketException)
                {
                    invalidAddressCount++;
                    lastException = socketException;
                }
            }

            if (socketConnection == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.Format(SR.NoIPEndpointsFoundForHost, uri.Host)));
            }

            if (lastException != null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    SocketConnectionInitiator.ConvertConnectException(lastException, uri,
                    timeoutHelper.ElapsedTime(), lastException));
            }

            return socketConnection;
        }

        public async Task<IConnection> ConnectAsync(Uri uri, TimeSpan timeout)
        {
            int port = uri.Port;
            IPAddress[] addresses = await SocketConnectionInitiator.GetIPAddressesAsync(uri);
            IConnection socketConnection = null;
            SocketException lastException = null;

            if (port == -1)
            {
                port = TcpUri.DefaultPort;
            }

            int invalidAddressCount = 0;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            for (int i = 0; i < addresses.Length; i++)
            {
                if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
                }

                DateTime connectStartTime = DateTime.UtcNow;
                try
                {
                    socketConnection = await CreateConnectionAsync(addresses[i], port);
                    lastException = null;
                    break;
                }
                catch (SocketException socketException)
                {
                    invalidAddressCount++;
                    lastException = socketException;
                }
            }

            if (socketConnection == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.Format(SR.NoIPEndpointsFoundForHost, uri.Host)));
            }

            if (lastException != null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    SocketConnectionInitiator.ConvertConnectException(lastException, uri,
                    timeoutHelper.ElapsedTime(), lastException));
            }

            return socketConnection;
        }
    }
}