Example #1
0
void HTTP_Stream::parseHttpHeadersIfNeeded(UInt8 *buf, CFIndex bufSize)
{
    if (m_httpHeadersParsed) {
        return;
    }
    m_httpHeadersParsed = true;
    
    /* If the response has the "ICY 200 OK" string,
     * we are dealing with the ShoutCast protocol.
     * The HTTP headers won't be available.
     */
    std::string header;
    
    for (CFIndex k=0; k < bufSize; k++) {
        UInt8 c = buf[k];
        // Ignore non-ASCII chars
        if (c < 32 || c > 126) {
            continue;
        }
        header.push_back(c);
    }
    
    char *p = strstr(header.c_str(), "ICY 200 OK");
    
    // This is an ICY stream, don't try to parse the HTTP headers
    if (p) {
        m_icyStream = true;
        return;
    }
    
    CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(m_readStream, kCFStreamPropertyHTTPResponseHeader);
    if (response) {
        /*
         * If the server responded with the icy-metaint header, the response
         * body will be encoded in the ShoutCast protocol.
         */
        CFStringRef icyMetaIntString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-metaint"));
        if (icyMetaIntString) {
            m_icyStream = true;
            m_icyHeadersParsed = true;
            m_icyHeadersRead = true;
            m_icyMetaDataInterval = CFStringGetIntValue(icyMetaIntString);
            CFRelease(icyMetaIntString);
        }
        
        CFStringRef icyNameString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-name"));
        if (icyNameString) {
            if (m_icyName) {
                CFRelease(m_icyName);
            }
            m_icyName = icyNameString;
            
            if (m_delegate) {
                std::map<CFStringRef,CFStringRef> metadataMap;
                
                metadataMap[CFSTR("IcecastStationName")] = CFStringCreateCopy(kCFAllocatorDefault, m_icyName);
                
                m_delegate->streamMetaDataAvailable(metadataMap);
            }
        }
        
        CFStringRef contentTypeString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Type"));
        if (contentTypeString) {
            CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(contentTypeString), kCFStringEncodingUTF8) + 1;
            char *buf = new char[len];
            if (CFStringGetCString(contentTypeString, buf, len, kCFStringEncodingUTF8)) {
                m_contentType.append(buf);
            }
            delete[] buf;
        
            CFRelease(contentTypeString);
        }
        
        CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Length"));
        if (contentLengthString) {
            m_contentLength = CFStringGetIntValue(contentLengthString);
            
            CFRelease(contentLengthString);
        }
        
        CFRelease(response);
    }
       
    if (m_delegate) {
        m_delegate->streamIsReadyRead();
    }
}
Example #2
0
void HTTP_Stream::parseICYStream(const UInt8 *buf, const CFIndex bufSize)
{
    HS_TRACE("Parsing an IceCast stream, received %li bytes\n", bufSize);
    
    CFIndex offset = 0;
    CFIndex bytesFound = 0;
    if (!m_icyHeadersRead) {
        HS_TRACE("ICY headers not read, reading\n");
        
        for (; offset < bufSize; offset++) {
            if (m_icyHeaderCR && buf[offset] == '\n') {
                if (bytesFound > 0) {
                    m_icyHeaderLines.push_back(createMetaDataStringWithMostReasonableEncoding(&buf[offset-bytesFound-1], bytesFound));
                    
                    bytesFound = 0;
                    
                    HS_TRACE_CFSTRING(m_icyHeaderLines[m_icyHeaderLines.size()-1]);
                    
                    continue;
                }
                
                HS_TRACE("End of ICY headers\n");
                
                m_icyHeadersRead = true;
                break;
            }
            
            if (buf[offset] == '\r') {
                m_icyHeaderCR = true;
                continue;
            } else {
                m_icyHeaderCR = false;
            }
            
            bytesFound++;
        }
    } else if (!m_icyHeadersParsed) {
        HS_TRACE("ICY headers not parsed, parsing\n");
        
        const CFStringRef icyContentTypeHeader = CFSTR("content-type:");
        const CFStringRef icyMetaDataHeader    =  CFSTR("icy-metaint:");
        const CFStringRef icyNameHeader        = CFSTR("icy-name:");

        const CFIndex icyContenTypeHeaderLength = CFStringGetLength(icyContentTypeHeader);
        const CFIndex icyMetaDataHeaderLength   = CFStringGetLength(icyMetaDataHeader);
        const CFIndex icyNameHeaderLength       = CFStringGetLength(icyNameHeader);
        
        for (std::vector<CFStringRef>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
            CFStringRef line = *h;
            const CFIndex lineLength = CFStringGetLength(line);
            
            if (lineLength == 0) {
                continue;
            }
            
            HS_TRACE_CFSTRING(line);
            
            if (CFStringCompareWithOptions(line,
                                           icyContentTypeHeader,
                                           CFRangeMake(0, icyContenTypeHeaderLength),
                                           0) == kCFCompareEqualTo) {
                if (m_contentType) {
                    CFRelease(m_contentType), m_contentType = 0;
                }
                m_contentType = CFStringCreateWithSubstring(kCFAllocatorDefault,
                                                            line,
                                                            CFRangeMake(icyContenTypeHeaderLength, lineLength - icyContenTypeHeaderLength));
                
            }
            
            if (CFStringCompareWithOptions(line,
                                           icyMetaDataHeader,
                                           CFRangeMake(0, icyMetaDataHeaderLength),
                                           0) == kCFCompareEqualTo) {
                CFStringRef metadataInterval = CFStringCreateWithSubstring(kCFAllocatorDefault,
                                                                           line,
                                                                           CFRangeMake(icyMetaDataHeaderLength, lineLength - icyMetaDataHeaderLength));
                
                if (metadataInterval) {
                    m_icyMetaDataInterval = CFStringGetIntValue(metadataInterval);
                    
                    CFRelease(metadataInterval);
                } else {
                    m_icyMetaDataInterval = 0;
                }
            }
            
            if (CFStringCompareWithOptions(line,
                                           icyNameHeader,
                                           CFRangeMake(0, icyNameHeaderLength),
                                           0) == kCFCompareEqualTo) {
                if (m_icyName) {
                    CFRelease(m_icyName);
                }
                
                m_icyName = CFStringCreateWithSubstring(kCFAllocatorDefault,
                                                        line,
                                                        CFRangeMake(icyNameHeaderLength, lineLength - icyNameHeaderLength));
            }
        }
        
        m_icyHeadersParsed = true;
        offset++;
        
        if (m_delegate) {
            m_delegate->streamIsReadyRead();
        }
    }
    
    Stream_Configuration *config = Stream_Configuration::configuration();
    
    if (!m_icyReadBuffer) {
        m_icyReadBuffer = new UInt8[config->httpConnectionBufferSize];
    }
    
    HS_TRACE("Reading ICY stream for playback\n");
    
    UInt32 i=0;
    
    for (; offset < bufSize; offset++) {
        // is this a metadata byte?
        if (m_metaDataBytesRemaining > 0) {
            m_metaDataBytesRemaining--;
            
            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;
                
                if (m_delegate && !m_icyMetaData.empty()) {
                    std::map<CFStringRef,CFStringRef> metadataMap;
                    
                    CFStringRef metaData = createMetaDataStringWithMostReasonableEncoding(&m_icyMetaData[0],
                                                                                          m_icyMetaData.size());
                    
                    if (!metaData) {
                        // Metadata encoding failed, cannot parse.
                        m_icyMetaData.clear();
                        continue;
                    }
                    
                    CFArrayRef tokens = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,
                                                                               metaData,
                                                                               CFSTR(";"));
                    
                    for (CFIndex i=0, max=CFArrayGetCount(tokens); i < max; i++) {
                        CFStringRef token = (CFStringRef) CFArrayGetValueAtIndex(tokens, i);
                        
                        CFRange foundRange;
                        
                        if (CFStringFindWithOptions(token,
                                                    CFSTR("='"),
                                                    CFRangeMake(0, CFStringGetLength(token)),
                                                    NULL,
                                                    &foundRange) == true) {
                            
                            CFRange keyRange = CFRangeMake(0, foundRange.location);
                            
                            CFStringRef metadaKey = CFStringCreateWithSubstring(kCFAllocatorDefault,
                                                                                token,
                                                                                keyRange);
                            
                            CFRange valueRange = CFRangeMake(foundRange.location + 2, CFStringGetLength(token) - keyRange.length - 3);
                            
                            CFStringRef metadaValue = CFStringCreateWithSubstring(kCFAllocatorDefault,
                                                                                  token,
                                                                                  valueRange);
                            
                            metadataMap[metadaKey] = metadaValue;
                        }
                    }
                    
                    CFRelease(tokens);
                    CFRelease(metaData);
                    
                    if (m_icyName) {
                        metadataMap[CFSTR("IcecastStationName")] = CFStringCreateCopy(kCFAllocatorDefault, m_icyName);
                    }
                    
                    m_delegate->streamMetaDataAvailable(metadataMap);
                }
                m_icyMetaData.clear();
                continue;
            }
            
            m_icyMetaData.push_back(buf[offset]);
            continue;
        }
        
        // is this the interval byte?
        if (m_icyMetaDataInterval > 0 && m_dataByteReadCount == m_icyMetaDataInterval) {
            m_metaDataBytesRemaining = buf[offset] * 16;
            
            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;
            }
            continue;
        }
        
        // a data byte
        m_dataByteReadCount++;
        m_icyReadBuffer[i++] = buf[offset];
    }
    
    if (m_delegate && i > 0) {
        m_delegate->streamHasBytesAvailable(m_icyReadBuffer, i);
    }
}
CFStringRef
CopyNextWorkstationName(SCDynamicStoreRef store, CFStringRef currentName)
{
	CFMutableStringRef computerName = NULL;
	CFStringRef macAddress = NULL;
		
	if (currentName) {
	
		/* Sanity check to make sure the current Workstation name is longer than the length of a MAC address string */
		CFIndex totalLengh = CFStringGetLength(currentName);
		if (totalLengh >= (CFIndex)kMACAddressLengh) {
		
			/* Create a substring that chops off the MAC addres, giving us the Computer Name */
			CFRange range = CFRangeMake(0, totalLengh - kMACAddressLengh);
			CFStringRef oldComputerName = CFStringCreateWithSubstring(NULL, currentName, range);
			
			/* If the Computer Name contains a trailing close paren it means that this name may have
			already experienced a name conflict which means it could have a trailing digit to increment */
			if (CFStringHasSuffix(oldComputerName, CFSTR(")"))) {
				CFRange result;
				
				/* Search for the first open paren, starting the search from the end of the Computer Name */
				if (CFStringFindWithOptions(oldComputerName, CFSTR("("), range, kCFCompareBackwards, &result)) {
				
					/* Create a substring which contains the contents between the open and close paren */
					range = CFRangeMake(result.location + 1, CFStringGetLength(oldComputerName) - result.location - 2);
					CFStringRef countString = CFStringCreateWithSubstring(NULL, currentName, range);
					
					/* Try converting the substring to an integer */
					SInt32 conflictCount = CFStringGetIntValue(countString);
					if (conflictCount) {
					
						/* Create a substring of just the Computer Name without the trailing open paren, conflict integer, close paren */
						range = CFRangeMake(0, result.location);
						CFStringRef tempComputerName = CFStringCreateWithSubstring(NULL, oldComputerName, range);
						
						/* Create a mutable copy of the Computer Name base substring */
						computerName = CFStringCreateMutableCopy(NULL, 0, tempComputerName);
						
						/* Create a string containing a space, open paren, previous conflict digit incremented by one, close paren */
						CFStringRef numberString = CFStringCreateWithFormat(NULL, NULL, CFSTR(" (%d)"), ++conflictCount);

						/* Truncate the Computer Name base as neccessary to ensure we can append the conflict digits */
						CFStringTruncateToUTF8Length(computerName, kMaxComputerName - CFStringGetLength(numberString));
						
						/* Append the incremented conflict digit to the Computer Name base string */
						CFStringAppend(computerName, numberString);
					}
				}
			}
			
			/* If computerName is NULL it means that the previous Computer Name didn't contain any conflict digits so append a " (2)" */
			if (!computerName) {
			
				/* Create mutable copy of previous Computer Name */
				computerName = CFStringCreateMutableCopy(NULL, 0, oldComputerName);
				
				/* Make sure we have enough room to append 4 characters to the name by truncating the Computer Name if neccessary */
				CFStringTruncateToUTF8Length(computerName, kMaxComputerName - 4);
				
				/* Append the name conflict digits */
				CFStringAppend(computerName, CFSTR(" (2)"));
			}
			
			CFRelease(oldComputerName);
		} else {
			DbgLog( kLogError, "Workstation name is shorter than a MAC address which shouldn't be possible" );
		}
	
	} else {
		
		/* There's currently no registered Workstation name so get the Computer Name from the dynamic store */
		CFStringRef tempName = SCDynamicStoreCopyComputerName(store, NULL);
		if (tempName) {
			/* Create a mutable copy of the Computer Name */
			computerName = CFStringCreateMutableCopy(NULL, 0, tempName);
			CFRelease(tempName);
			
			/* Truncate the Computer Name to ensure we can append the MAC address */
			CFStringTruncateToUTF8Length(computerName, kMaxComputerName);
		} else {
			return NULL;
		}
	}
	
	/* Copy the primary MAC address string */
	macAddress = CopyPrimaryMacAddress();
	if (!macAddress) {
		if (computerName) {
			CFRelease(computerName);
		}
		return NULL;
	}
	
	/* Append a space */
	CFStringAppend(computerName, CFSTR(" "));
	
	/* Append the MAC address string */
	CFStringAppend(computerName, macAddress);
	CFRelease(macAddress);

	return computerName;
}
Example #4
0
void HTTP_Stream::parseHttpHeadersIfNeeded(const UInt8 *buf, const CFIndex bufSize)
{
    if (m_httpHeadersParsed) {
        return;
    }
    m_httpHeadersParsed = true;
    
    /* If the response has the "ICY 200 OK" string,
     * we are dealing with the ShoutCast protocol.
     * The HTTP headers won't be available.
     */
    if (bufSize >= 10 &&
        buf[0] == 0x49 && buf[1] == 0x43 && buf[2] == 0x59 &&
        buf[3] == 0x20 && buf[4] == 0x32 && buf[5] == 0x30 &&
        buf[6] == 0x30 && buf[7] == 0x20 && buf[8] == 0x4F &&
        buf[9] == 0x4B) {
        m_icyStream = true;
        
        HS_TRACE("Detected an IceCast stream\n");
        
        // This is an ICY stream, don't try to parse the HTTP headers
        return;
    }
    
    HS_TRACE("A regular HTTP stream\n");
    
    CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(m_readStream, kCFStreamPropertyHTTPResponseHeader);
    if (response) {
        /*
         * If the server responded with the icy-metaint header, the response
         * body will be encoded in the ShoutCast protocol.
         */
        CFStringRef icyMetaIntString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-metaint"));
        if (icyMetaIntString) {
            m_icyStream = true;
            m_icyHeadersParsed = true;
            m_icyHeadersRead = true;
            m_icyMetaDataInterval = CFStringGetIntValue(icyMetaIntString);
            CFRelease(icyMetaIntString);
        }
        
        HS_TRACE("icy-metaint: %zu\n", m_icyMetaDataInterval);
        
        CFStringRef icyNameString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-name"));
        if (icyNameString) {
            if (m_icyName) {
                CFRelease(m_icyName);
            }
            m_icyName = icyNameString;
            
            if (m_delegate) {
                std::map<CFStringRef,CFStringRef> metadataMap;
                
                metadataMap[CFSTR("IcecastStationName")] = CFStringCreateCopy(kCFAllocatorDefault, m_icyName);
                
                m_delegate->streamMetaDataAvailable(metadataMap);
            }
        }
        
        if (m_contentType) {
            CFRelease(m_contentType);
        }
        
        m_contentType = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Type"));
        
        HS_TRACE("Content-type: ");
        HS_TRACE_CFSTRING(m_contentType);
        
        CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Length"));
        if (contentLengthString) {
            m_contentLength = CFStringGetIntValue(contentLengthString);
            
            CFRelease(contentLengthString);
        }
        
        CFRelease(response);
    }
       
    if (m_delegate) {
        m_delegate->streamIsReadyRead();
    }
}
/* ------------------------------------------------------------------------------------------------------

SetDateValueFromFITSHeader: read FITS header and set striped string value to attribute name.

------------------------------------------------------------------------------------------------------ */
void SetDateValueFromFITSHeader(const char* filename, 
				CFMutableDictionaryRef attributes, 
				const char* importerAttrName, 
				char* mainKeyword, 
				char* secondaryKeyword1,
				char* secondaryKeyword2)
{
	CFMutableStringRef headerValue = CFStringCreateMutable(kCFAllocatorDefault, (CFIndex)80);

	CFStringRef value1 = getCleanedHeaderValue(filename, mainKeyword);
	if (value1 != NULL) {
		CFIndex valueLength1 = CFStringGetLength(value1);
		if ((valueLength1 >= 19) || (valueLength1 == 10)) {
			CFStringAppend(headerValue, value1); // value of mainKeyword looks OK.
		}
		CFRelease(value1);
	}

	CFStringRef value2 = getCleanedHeaderValue(filename, secondaryKeyword1);
	if (value2 != NULL) {
		CFIndex valueLength2 = CFStringGetLength(value2);
		CFIndex headerValueLength = CFStringGetLength(headerValue);
		if (headerValueLength == 0 && valueLength2 >= 10) {
			CFStringAppend(headerValueLength, value2); // Append value of secondaryKeyword1
		}
		else if (headerValueLength < 19 && valueLength2 >= 19) {
			CFRange range = CFRangeMake(0, headerValueLength);
			CFStringDelete(headerValue, range);
			CFStringAppend(headerValue, value2); // Replace value of current headerValue by value of secondaryKeyword1
		}
		CFRelease(value2);
	}

	CFStringRef value3 = getCleanedHeaderValue(filename, secondaryKeyword2);
	if (value3 != NULL) {
		CFRange r = CFStringFind(value3, CFSTR(":"), 0);
		CFIndex headerValueLength = CFStringGetLength(headerValue);
		if (headerValueLength == 10 && r.location != kCFNotFound) {
			CFStringAppend(headerValue, CFSTR("T"));
			CFStringAppend(headerValue, value3);
		}
		CFRelease(value3);
	}

	CFIndex headerValueLength = CFStringGetLength(headerValue);
	if (headerValueLength > 0) {
		
		CFArrayRef tArray   = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, headerValue, CFSTR("T"));
		CFArrayRef ymdArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, CFArrayGetValueAtIndex(tArray, 0), CFSTR("-"));

		CFGregorianDate gregDate;
		gregDate.year   = 0;
		gregDate.month  = 0;
		gregDate.day    = 0.;
		
		if (CFStringGetLength(CFArrayGetValueAtIndex(ymdArray, 0)) > 0) {
			gregDate.year   = CFStringGetIntValue(CFArrayGetValueAtIndex(ymdArray, 0));
		}
		if (CFStringGetLength(CFArrayGetValueAtIndex(ymdArray, 1)) > 0) {
			gregDate.month  = CFStringGetIntValue(CFArrayGetValueAtIndex(ymdArray, 1));
		}
		if (CFStringGetLength(CFArrayGetValueAtIndex(ymdArray, 2)) > 0) {
			gregDate.day    = CFStringGetIntValue(CFArrayGetValueAtIndex(ymdArray, 2));
		}
		CFRelease(ymdArray);

		gregDate.hour   = 0;
		gregDate.minute = 0;
		gregDate.second = 0.;
		
		CFIndex arraySize = CFArrayGetCount(tArray);
		if (arraySize == 2) {
			CFArrayRef hmsArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, CFArrayGetValueAtIndex(tArray, 1), CFSTR(":"));
			if (CFStringGetLength(CFArrayGetValueAtIndex(hmsArray, 0)) > 0) {
				gregDate.hour   = CFStringGetIntValue(CFArrayGetValueAtIndex(hmsArray, 0));
			}
			if (CFStringGetLength(CFArrayGetValueAtIndex(hmsArray, 1)) > 0) {
				gregDate.minute = CFStringGetIntValue(CFArrayGetValueAtIndex(hmsArray, 1));
			}
			if (CFStringGetLength(CFArrayGetValueAtIndex(hmsArray, 2)) > 0) {
				gregDate.second = CFStringGetDoubleValue(CFArrayGetValueAtIndex(hmsArray, 2));			
			}
			CFRelease(hmsArray);
		}

		CFRelease(tArray);

//		printf("%i %i %i %i %i %f\n\n", gregDate.year, gregDate.month, gregDate.day, gregDate.hour, gregDate.minute, gregDate.second);

		if ((gregDate.year > 0) && (gregDate.month > 0) && (gregDate.day > 0)) {
			CFTimeZoneRef timeZone = CFTimeZoneCreateWithName(kCFAllocatorDefault, CFSTR("GMT"), true);
			CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(gregDate, timeZone);
			CFDateRef date = CFDateCreate(kCFAllocatorDefault, absTime);

			if (timeZone != NULL) {
				CFRelease(timeZone);
			}

			CFStringRef cfImporterAttrName = CFStringCreateWithCString(kCFAllocatorDefault, importerAttrName, kCFStringEncodingUTF8);
			CFDictionaryAddValue(attributes, cfImporterAttrName, date);
			CFRelease(cfImporterAttrName);
			CFRelease(date);
		}
	}

	CFRelease(headerValue);
}