예제 #1
0
//--------------------------------------------------------------------------
// Process a EXIF marker
// Describes all the drivel that most digital cameras include...
//--------------------------------------------------------------------------
void process_EXIF (char * CharBuf, unsigned int length)
{
    ImageInfo.FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.

    FocalplaneXRes = 0;
    FocalplaneUnits = 0;
    ExifImageWidth = 0;

    if (ShowTags){
        printf("Exif header %d bytes long\n",length);
    }

    {   // Check the EXIF header component
        static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
        if (memcmp(CharBuf+2, ExifHeader,6)){
            ErrExit("Incorrect Exif header");
        }
    }

    if (memcmp(CharBuf+8,"II",2) == 0){
        if (ShowTags) printf("Exif section in Intel order\n");
        MotorolaOrder = 0;
    }else{
        if (memcmp(CharBuf+8,"MM",2) == 0){
            if (ShowTags) printf("Exif section in Motorola order\n");
            MotorolaOrder = 1;
        }else{
            ErrExit("Invalid Exif alignment marker.");
        }
    }

    // Check the next two values for correctness.
    if (Get16u(CharBuf+10) != 0x2a
      || Get32u(CharBuf+12) != 0x08){
        ErrExit("Invalid Exif start (1)");
    }

    LastExifRefd = CharBuf;

    // First directory starts 16 bytes in.  Offsets start at 8 bytes in.
    ProcessExifDir(CharBuf+16, CharBuf+8, length-6);

    // This is how far the interesting (non thumbnail) part of the exif went.
    ExifNonThumbnailLength = LastExifRefd - CharBuf;

    // Compute the CCD width, in milimeters.
    if (FocalplaneXRes != 0){
        ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
    }

    if (ShowTags){
        printf("Thunbnail size of Exif header: %d\n",length-ExifNonThumbnailLength);
    }
}
예제 #2
0
/*************************** newListFromInput **********************************
LinkedList newListFromInput()
Purpose:
	Goes through the input file, for each line, creates a widget and an 
	arrival event for that widget and insert it in a list.
Parameters:
Returns:
	Functionally:
		A LinkedList variable populated from the input.
Notes:
*******************************************************************************/
LinkedList newListFromInput()
{
	/***variables***/
	char szInputBuffer[MAX_LINE_SIZE + 1];
	Widget widget;
	Event arrival;
	LinkedList list;
	int iClock, iNextArrival, iScanfCnt;
	
	//allocate list
	list = newLinkedList();
	
	iClock = 0; 
	while (fgets(szInputBuffer, MAX_LINE_SIZE, pInputFile) != NULL 
			&& iClock <= MAX_ARRIVAL_TIME) //for each line of the input file
	{	
		if (szInputBuffer[0] == '\n') //if line is empty, ignore
		{
			continue;
		}
	
		//populate the widget variable with data from input line and current clock
		iScanfCnt = sscanf(szInputBuffer, "%ld %d %d %d\n", &(widget.lWidgetNr), 
							&(widget.iStep1tu), &(widget.iStep2tu), &iNextArrival);
		widget.iArrivalTime = iClock;
	
		if (iScanfCnt < 4) //if there's less than 4 tokens in the line
		{
			ErrExit(ERR_BAD_INPUT, "%sExpected 4 tokens,received %d successful values\n",
					szInputBuffer, iScanfCnt);
			continue;
		}
	
		if (widget.iStep1tu < 0 || widget.iStep2tu < 0 || iNextArrival < 0)
		//if the values are negative values
		{
			ErrExit(ERR_BAD_INPUT, 
					"%sStep1tu, Step2tu, and DeltaArrival cannot be negative values.\n",
					szInputBuffer, iScanfCnt);
			continue;
		}
	
		//populate the arrival Event variable
		arrival.iEventType = EVT_ARRIVAL;
		arrival.iTime = iClock;
		arrival.widget = widget;
		//insert it into the list
		insertOrderedLL(list, arrival);
		//increment clock for next input line (next widget)
		iClock += iNextArrival;
	}
	
	return list;
}
예제 #3
0
Tree newTree()
{
    Tree tree = (Tree)malloc(sizeof(TreeImp));
    if (tree == NULL)
        ErrExit(ERR_ALGORITHM, "malloc allocation error for TreeImp");
    tree->pRoot = NULL;
    return tree;
}
예제 #4
0
QuoteSelection newQuoteSelection()
{
    QuoteSelection quote = (QuoteSelection)malloc(sizeof(QuoteSelectionImp));
    if (quote == NULL)
        ErrExit(ERR_ALGORITHM, "malloc allocation error for QuoteSelectionImp");
    quote->iQuoteItemCnt = 0;
    return quote;
}
예제 #5
0
int main()
{
    int x = 1, y = -1;

    if (x != y)
        ErrExit("Found x = %d, y = %d; Expected them to be equal!", x, y);
    return EXIT_SUCCESS;
}
예제 #6
0
/******************** newTextList **************************************
TextList newTextList()
Purpose:
    Allocates a new TextList and initalizes it.
Parameters:
    n/a
Returns:
    A pointer to the newly allocated TextList. 
Notes:
    - This uses an array implementation of TextList.  
    - Initializes the number of entries to 0.
**************************************************************************/
TextList newTextList()
{
    TextList textList = (TextList)malloc(sizeof(TextListImp));
    if (textList == NULL)
        ErrExit(ERR_ALGORITHM, "malloc ran out of memory for new TextList");
    textList->iNumEntry = 0;
    return textList;
}
예제 #7
0
/******************** newGraph **************************************
    Graph newGraph()
Purpose:
    Allocates a GraphImp and initializes its data.  It returns a
    Graph. 
Parameters:
    n/a
Notes:
    - Uses malloc to allocate a GraphImp.  It also makes certain
      that malloc didn't fail.
    - Initializes iNumvetices to 0.
    - Initializes the array of vertices to zero bytes.
    - 
Returns:
    Graph - the newly allocated graph.
**************************************************************************/
Graph newGraph()
{
    Graph g = (Graph)malloc(sizeof(GraphImp));
    if (g == NULL)
        ErrExit(ERR_ALGORITHM, "malloc for Graph failed");
    g->iNumVertices = 0;
    memset(g->vertexM, '\0',  sizeof(Vertex)*MAX_VERTICES);
    return g;
}
예제 #8
0
EdgeNode *allocateEdgeNode(Edge value)
{
    EdgeNode *pNew;
    pNew = (EdgeNode *)malloc(sizeof(EdgeNode));
    if (pNew == NULL)
        ErrExit(ERR_ALGORITHM, "No available memory for linked list");
    pNew->edge = value;
    pNew->pNextEdge = NULL;
    return pNew;
}
예제 #9
0
/******************** allocateNodeT ****************************************
 NodeT *allocateNodeT(QuoteSelection quote, Element element)
 Purpose: Allocates memory for a new node in the QuoteSelection tree. Exits
 the program with an error if no memory is available.

 Parameters:
    I/O     Quoteselection quote    Tree to be modified
    I       Element element         Item to be inserted into the tree

 Returns:
    pNew        Returns a pointer to the new node with pSibling and pChild
                pointing to NULL
    ErrExit     No memory available for allocation

 Notes:

 **************************************************************************/
NodeT *allocateNodeT(Element element)
{
    NodeT *pNew;
    pNew = (NodeT *)malloc(sizeof(NodeT));
    if (pNew == NULL)
        ErrExit(ERR_ALGORITHM, "No available memory for binary tree.");
    pNew->element = element;
    pNew->pChild = NULL;
    pNew->pSibling = NULL;
    return pNew;
}
예제 #10
0
/************************* allocateNodeLL **************************************
NodeLL *allocateNodeLL(LinkedList list, Event value)
Purpose:
	Creates and allocate the memory for a new node including the passed by event.
Parameters:
	I	LinkedList list		The current list.
	I	Event value			The element to be included in the new node.
Returns:
	Functionally:
		A pointer to the new node containing the element we passed it.
Notes:
*******************************************************************************/
NodeLL *allocateNodeLL(LinkedList list, Event value)
{
	NodeLL *pNew = (NodeLL *) malloc(sizeof(NodeLL));
	if (pNew == NULL)
	{
		ErrExit(ERR_ALGORITHM, "No available memory for linked list");
	}
	pNew->event = value;
	pNew->pNext = NULL;
	return pNew;
}
예제 #11
0
/************************* newLinkedList ***************************************
LinkedList newLinkedList()
Purpose:
	Creates and allocates the memory for a new LinkedList with Header Node.
Parameters:
Returns:
	Functionally:
		The newly created list.
Notes: 
	Adapted for a LinkedList with Header Node.
*******************************************************************************/
LinkedList newLinkedList()
{
	LinkedList list = (LinkedList) malloc(sizeof(LinkedListImp));
	if (list == NULL)
	{
		ErrExit(ERR_ALGORITHM, "No available memory for linked list");
	}
	NodeLL *pHeader = (NodeLL *) malloc(sizeof(NodeLL));
	list->pHead = pHeader;
	list->pHead->pNext = NULL;
	return list;
}
예제 #12
0
/****************************** allocNodeQ *************************************
NodeQ *allocNodeQ(Queue queue, QElement value)
Purpose:
	Creates and allocate the memory for a new node including the passed by value.
Parameters:
	I	Queue queue			The current queue.
	I	QElement value		The element to be included in the new node.
Returns:
	Functionally:
		A pointer to the new node containing the element we passed it.
Notes:
*******************************************************************************/
NodeQ *allocNodeQ(Queue queue, QElement value)
{
	NodeQ *pNew;
	pNew = (NodeQ *)malloc(sizeof(NodeQ));
	if (pNew == NULL)
	{
		ErrExit(ERR_ALGORITHM, "No available memory for queue");
	}
	pNew->element = value;
	pNew->pNext = NULL;
	return pNew;
}
예제 #13
0
/******************** getGraphData **************************************
  int getGraphData(struct Data dataM[])
Purpose:
    Populates an array of edges with data from stdin.  The array is 
    terminated when EOF or a 0 0 0 is encountered in the data. 
Parameters:
    O   struct Data dataM[]     An array of edges (to, from, path weight)
Notes:
    - The array of edges is terminated by an edge having a from vertex
      equal to the character '0'.
Returns:
    TRUE - data was read to populate the array of vertices.
    FALSE - no data found.
**************************************************************************/
int getGraphData(struct Data dataM[])
{
    char szInput[100];
    int i = 0;
    int iScanfCnt;
    while (fgets(szInput, 50, stdin) != NULL)
    {
        if (i > MAX_EDGES)
            ErrExit(ERR_BAD_INPUT, "too many edges");
        iScanfCnt = sscanf(szInput, "%c %c %d"
            , &dataM[i].cFrom, &dataM[i].cTo, &dataM[i].iPath);
        if (iScanfCnt < 3)
            ErrExit(ERR_BAD_INPUT, " Found: '%s', scanf count is %d", szInput, iScanfCnt);
        if (dataM[i].cFrom == '0')
        {
            dataM[i].cFrom = '\0';
            break;
        }
        i++;
    }
    return i > 0;
}
예제 #14
0
/*******************************************************************
 void runSimulationA(Simulation sim, int iTimeLimit)
 Purpose:
     Runs a simulation on the event list. Prints a table displaying
     the arrival and departures of travelers
 Parameters:
     I   Simulation simulation
     I   int iTimeLimit
 Returns:
     1. Does not return anything functionally
 Notes:
     1. Uses removeLL function
 *******************************************************************/
void runSimulationA(Simulation sim, int iTimeLimit)
{
    Event event;                            // Creates a local event variable to store current
                                            // nodes event information into (uses in simulation evaluation)
    Server server1 = newServer("Server 1");           // Creates a new server -
                                            //  - contains Server Name, whether it is busy or not, and a widget
    Server server2 = newServer("Server 2");            // creates the second server for our program (refer to server1 comments)
    Queue queue1 = newQueue("Queue 1");                // Creates a new queue
    Queue queue2 = newQueue("Queue 2");                // Creates a new queue
    
    if (sim->bVerbose == TRUE)
        printf("%-4s %-6s %-10s\n", "TIME", "WIDGET", "EVENT");      //table header
    
    while (removeLL(sim->eventList, &event))
    {
        // buffer to stop arrivals after the time limit
        if (event.iEventType == EVT_ARRIVAL && event.iTime > iTimeLimit)
            continue;
        
        sim->iClock = event.iTime;  // advance clock to current event time
        
        // the switch evaluates the eventType
        switch(event.iEventType)
        {
            case EVT_ARRIVAL:
                arrival(sim, &event.widget);
                queueUp(sim, queue1, &event.widget);
                seize(sim, queue1, server1);
                break;
            case EVT_SERVER1_COMPLETE:
                release(sim, queue1, server1, &event.widget);
                queueUp(sim, queue2, &event.widget);
                seize(sim, queue2, server2);
                break;
            case EVT_SERVER2_COMPLETE:
                release(sim, queue2, server2, &event.widget);
                leaveSystem(sim, event.widget);
                break;
            default:
                ErrExit(ERR_ALGORITHM, "Unknown event type: %d\n", event.iEventType);
        }
    }
    // prints the averages produced by the simulation
    printStatistics(sim, queue1, queue2);

    // frees servers and queues used in simulation A
    free(server1);
    free(server2);
    free(queue1);
    free(queue2);
}
예제 #15
0
/******************** addTextEntry **************************************
void addTextEntry(TextList textList, TextEntry text)
Purpose:
    Adds a text entry to the TextList.  It replaces it if it already exists.
Parameters:
    I/O TextList textList       A text list which contains many text
                                entries. The text entry is added to
                                this.
    I   TextEntry text          The text entry to be added to the
                                text list. 
Returns:
    n/a
Notes:
    - This uses an array implementation of TextList.  If the number of
      entries excedes MAX_TEXT_LIST_SIZE, it exits.
**************************************************************************/
void addTextEntry(TextList textList, TextEntry text)
{
    // See if it already exists
    int iFound = findText(textList, text.szId);
    if (iFound >= 0)
    {   // Replace the text entry
        textList->arrayM[iFound] = text;
        return;
    }
    // Not found, so try to insert it
    // Array boundary check
    if (textList->iNumEntry >= MAX_TEXT_LIST_SIZE)
        ErrExit(ERR_DATA, "Too many text entries");
    textList->arrayM[textList->iNumEntry] = text;
    textList->iNumEntry++;
}
예제 #16
0
/******************** getToken **************************************
char * getToken (char *pszInputTxt, char szToken[], int iTokenSize)
Purpose:
    Examines the input text to return the next token.  It also
    returns the position in the text after that token.  This function
    does not skip over white space, but it assumes the input uses 
    spaces to separate tokens.
Parameters:
    I   char *pszInputTxt       input buffer to be parsed
    O   char szToken[]          Returned token.
    I   int iTokenSize          The size of the token variable.  This is used
                                to prevent overwriting memory.  The size
                                should be the memory size minus 1 (for
                                the zero byte).
Returns:
    Functionally:
        Pointer to the next character following the delimiter after the token.
        NULL - no token found.
    szToken parm - the returned token.  If not found, it will be an
        empty string.
Notes:
    - If the token is larger than the szToken parm, we return a truncated value.
    - If a token isn't found, szToken is set to an empty string
    - This function does not skip over white space occurring prior to the token.
**************************************************************************/
char * getToken(char *pszInputTxt, char szToken[], int iTokenSize)
{
    int iDelimPos;                      // found position of delim
    int iCopy;                          // number of characters to copy
    char szDelims[20] = " \n\r";        // delimiters
    szToken[0] = '\0';

    // check for NULL pointer 
    if (pszInputTxt == NULL)
        ErrExit(ERR_ALGORITHM
        , "getToken passed a NULL pointer");

    // Check for no token if at zero byte
    if (*pszInputTxt == '\0')
        return NULL;

    // get the position of the first delim
    iDelimPos = strcspn(pszInputTxt, szDelims);

    // if the delim position is at the first character, return no token.
    if (iDelimPos == 0)
        return NULL;

    // see if we have more characters than target token, if so, trunc
    if (iDelimPos > iTokenSize)
        iCopy = iTokenSize;             // truncated size
    else
        iCopy = iDelimPos;

    // copy the token into the target token variable
    memcpy(szToken, pszInputTxt, iCopy);
    szToken[iCopy] = '\0';              // null terminate

    // advance the position
    pszInputTxt += iDelimPos;
    if (*pszInputTxt == '\0')
        return pszInputTxt;
    else
        return pszInputTxt + 1;
}
예제 #17
0
int main()
{
    // Variables for diagnosis tree
    NodeT *root = NULL;

    // Variables for text List
    TextEntry text;
    TextList textList = newTextList();

    // Variables for driver input control
    char szInputBuffer[MAX_LINE_SIZE+1];            // input command line
    int iScanfCnt;                                  // sscanf return
    char *pszRemaining;                             // getToken returns this
    Token szCommand;                                // Input Command

    //Variables for reading data input command arguments
    Element element;                                // Binary Tree element
    char szParentId[MAX_ID_SIZE + 1];               // parent Id for NODE command
    char cYN;                                       // Y or N value for NODE command
    char szAnswers[MAX_NUMBER_ANSWERS];             // Text for answers
    
    // Variables for results
    char *pszResultId;                              // Result of searchT or help
    
    // Read command lines until EOF
    while (fgets(szInputBuffer, MAX_LINE_SIZE, stdin) != NULL)
    {
        printf("%s", szInputBuffer);

        // If the line is just a comment, ignore it
        if (szInputBuffer[0] == '*')
            continue;                               // Command is a comment so skip it
        
        // get the command
        pszRemaining = getToken(szInputBuffer, szCommand, MAX_TOKEN_SIZE);

        // Determine what to invoke based on the command

        if (strcmp(szCommand, "ROOT") == 0)
        {   // ROOT id      - create the root for the tree
            pszRemaining = getToken(pszRemaining, element.szId, MAX_ID_SIZE);
            if (pszRemaining == NULL)
                ErrExit(ERR_DATA, "Invalid data for ROOT command, missing ID");

            element.cNodeType = 'Q';
            root = allocateNodeT(element);
        }

        else if (strcmp(szCommand, "NODE") == 0)
        {   // NODE type id parentId yn
            iScanfCnt = sscanf(pszRemaining, "%c %s %s %c"
                , &element.cNodeType, element.szId
                , szParentId, &cYN);
            if (iScanfCnt < 4)
                ErrExit(ERR_DATA, "Invalid data for NODE command: '%s'", pszRemaining);

            // insert your code to check warning cases and handle the insertion
            insert(root, szParentId, element, cYN);
        }

        else if (strcmp(szCommand, "TEXT") == 0)
        {   // TEXT type id displayText
            iScanfCnt = sscanf(pszRemaining, "%c %s %79[^\n]", &text.cType, text.szId, text.szText);
            if (iScanfCnt < 3)
                ErrExit(ERR_DATA, "Invalid data for TEXT command: '%s'", pszRemaining);

            addTextEntry(textList, text);
        }

        else if (strcmp(szCommand, "PRINT") == 0)
        {   // PRINT using your prettyPrintT routine
            prettyPrintT(root, 0, textList);
            printf("\n\n");
        }

        else if (strcmp(szCommand, "HELP") == 0)
        {   // HELP id answers
            pszRemaining = getToken(pszRemaining, szAnswers, MAX_NUMBER_ANSWERS);
            if (pszRemaining == NULL)
                ErrExit(ERR_DATA, "Invalid data for HELP command, missing answers");

            pszResultId = help(root, szAnswers, 0, textList);

            // It is expected that help might return NULL, if the tree is 
            // not defined properly.  (not necessarily a student error)
            if (pszResultId == NULL)
                printf("\t*** Warning:  NULL returned from HELP\n");
            else 
                printf("\t%s: %s\n", pszResultId
                     , getText(textList, pszResultId));
        }

        else if (strcmp(szCommand, "DELETE") == 0)
        {
            pszRemaining = getToken(pszRemaining, element.szId, MAX_ID_SIZE);
            if (pszRemaining == NULL)
                ErrExit(ERR_DATA, "Invalid data for DELETE command, missing ID");

            // insert your code for the DELETE command which should remove the 
            // specified ID from its parent node and also free the subtree defined by
            // the specified ID
            deleteNode(root, element.szId);
        }
    }
    // Your code to free the tree
    freeT(root);
    // Free the textList
    free(textList);

    printf("\n");
    return 0;
}
예제 #18
0
/**************************** runSimulation ************************************
void runSimulation(Simulation sim, int iTimeLimit)
Purpose:
	Goes through a list of events in a Simulation and run them as they are 
	encountered.
Parameters:
	I	Simulation sim		The simulation variable containing the list of 
							events.
	I	int iTimeLimit		A time limit upon which the simulation will terminate 
							if it is reached before all of the events are ran.
Returns:
Notes:
*******************************************************************************/
void runSimulation(Simulation sim, int iTimeLimit)
{	
	//Variables
	Event event;
	Server server1, server2;
	Queue queue1, queue2;
	
	//create servers and queues
	server1 = newServer("Server 1");
	queue1 = newQueue("Queue 1");
	if (sim->cRunType == 'A')
	{
		server2 = newServer("Server 2");
		queue2 = newQueue("Queue 2");	
	}

	//begin simulation
	printHeader(sim);
	while (removeLL(sim->eventList, &event)) 
	{	
		if (event.iTime > iTimeLimit)
		{
			printFooter(sim, queue1, queue2);	
			freeServersAndQueues(sim, server1, server2, queue1, queue2);	
			ErrExit(ERR_BAD_INPUT, "Event time (%d) is out of simulation bounds (%d)\n", 
					event.iTime, iTimeLimit);
		}

		sim->iClock = event.iTime;
		switch (event.iEventType)
		{
			case EVT_ARRIVAL:
				arrival(sim, &event.widget);
				queueUp(sim, &event.widget, queue1);
				seize(sim, queue1, server1);
				break;

			case EVT_SERVER1_COMPLETE:
				release(sim, queue1, server1);
				if (sim->cRunType == 'A') //Alternative A follows up with server 2
				{
					queueUp(sim, &event.widget, queue2);
					seize(sim, queue2, server2);
				}
				else //Alternative B and Current leave after server 1
				{
					leaveSystem(sim, &event.widget);
				}
				break;

			case EVT_SERVER2_COMPLETE:
				release(sim, queue2, server2);
				leaveSystem(sim, &event.widget);
				break;
		
			default:
				ErrExit(ERR_ALGORITHM, "Unknown event type: %d\n", event.iEventType);
		}
	}
	
	printFooter(sim, queue1, queue2);	
	freeServersAndQueues(sim, server1, server2, queue1, queue2);	
}
예제 #19
0
//--------------------------------------------------------------------------
// Parse the marker stream until SOS or EOI is seen;
//--------------------------------------------------------------------------
static int ReadJpegSections (FILE * infile,ReadMode_t ReadMode)
{
    int a;
    int HaveCom = FALSE;

    a = fgetc(infile);


    if (a != 0xff || fgetc(infile) != M_SOI){
        return FALSE;
    }
    for(;SectionsRead < MAX_SECTIONS-1;){
        int itemlen;
        int marker = 0;
        int ll,lh, got;
        uchar * Data;

        for (a=0;a<7;a++){
            marker = fgetc(infile);
            if (marker != 0xff) break;

            if (a >= 6){

                printf("too many padding bytes\n");

                return FALSE;

            }
        }

        if (marker == 0xff){
            // 0xff is legal padding, but if we get that many, something's wrong.
            ErrExit("too many padding bytes!");
        }

        Sections[SectionsRead].Type = marker;
  
        // Read the length of the section.
        lh = fgetc(infile);
        ll = fgetc(infile);

        itemlen = (lh << 8) | ll;

        if (itemlen < 2){
            ErrExit("invalid marker");
        }

        Sections[SectionsRead].Size = itemlen;

        Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end.
        if (Data == NULL){
            ErrExit("Could not allocate memory");
        }
        Sections[SectionsRead].Data = Data;

        // Store first two pre-read bytes.
        Data[0] = (uchar)lh;
        Data[1] = (uchar)ll;

        got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section.
        if (got != itemlen-2){
            ErrExit("reading from file");
        }
        SectionsRead += 1;

        //printf("Marker '%x' size %d\n",marker, itemlen);
        switch(marker){

            case M_SOS:   // stop before hitting compressed data 
                // If reading entire image is requested, read the rest of the data.
                if (ReadMode & READ_IMAGE){
                    int cp, ep, size;
                    // Determine how much file is left.
                    cp = ftell(infile);
                    fseek(infile, 0, SEEK_END);
                    ep = ftell(infile);
                    fseek(infile, cp, SEEK_SET);

                    size = ep-cp;
                    Data = (uchar *)malloc(size);
                    if (Data == NULL){
                        ErrExit("could not allocate data for entire image");
                    }

                    got = fread(Data, 1, size, infile);
                    if (got != size){
                        ErrExit("could not read the rest of the image");
                    }

                    Sections[SectionsRead].Data = Data;
                    Sections[SectionsRead].Size = size;
                    Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
                    SectionsRead ++;
                    HaveAll = 1;
                }
                return TRUE;

            case M_EOI:   // in case it's a tables-only JPEG stream
                printf("No image in jpeg!\n");
                return FALSE;

            case M_COM: // Comment section
                if (HaveCom || ((ReadMode & READ_EXIF) == 0)){
                    // Discard this section.
                    free(Sections[--SectionsRead].Data);
                }else{
                    process_COM(Data, itemlen);
                    HaveCom = TRUE;
                }
                break;

            case M_JFIF:
                // Regular jpegs always have this tag, exif images have the exif
                // marker instead, althogh ACDsee will write images with both markers.
                // this program will re-create this marker on absence of exif marker.

                free(Sections[--SectionsRead].Data);
                break;

            case M_EXIF:

                if (SectionsRead <= 2){
                    // Seen files from some 'U-lead' software with Vivitar scanner
                    // that uses marker 31 later in the file (no clue what for!)
                    process_EXIF((char *)Data, itemlen);
                }else{
                    // Discard this section.
                    free(Sections[--SectionsRead].Data);
                }
                break;

            case M_SOF0: 
            case M_SOF1: 
            case M_SOF2: 
            case M_SOF3: 
            case M_SOF5: 
            case M_SOF6: 
            case M_SOF7: 
            case M_SOF9: 
            case M_SOF10:
            case M_SOF11:
            case M_SOF13:
            case M_SOF14:
            case M_SOF15:
                process_SOFn(Data, marker);
                break;
            default:
                // Skip any other unknown sections.
                if (ShowTags){
                    printf("Unknown Jpeg section marker 0x%02x size %d\n",marker, itemlen);
                }
                break;
        }
    }
    return TRUE;
}
예제 #20
0
//--------------------------------------------------------------------------
// Process one of the nested EXIF directories.
//--------------------------------------------------------------------------
static void ProcessExifDir(char * DirStart, char * OffsetBase, unsigned ExifLength)
{
    int de;
    int a;
    int NumDirEntries;

    NumDirEntries = Get16u(DirStart);

    if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
        ErrExit("Illegally sized directory");
    }

    if (ShowTags){
        printf("Directory with %d entries\n",NumDirEntries);
    }

    for (de=0;de<NumDirEntries;de++){
        int Tag, Format, Components;
        char * ValuePtr;
        int ByteCount;
        char * DirEntry;
        DirEntry = DirStart+2+12*de;

        Tag = Get16u(DirEntry);
        Format = Get16u(DirEntry+2);
        Components = Get32u(DirEntry+4);

        if ((Format-1) >= NUM_FORMATS) {
            // (-1) catches illegal zero case as unsigned underflows to positive large.
            ErrExit("Illegal format code in EXIF dir");
        }

        ByteCount = Components * BytesPerFormat[Format];

        if (ByteCount > 4){
            unsigned OffsetVal;
            OffsetVal = Get32u(DirEntry+8);
            // If its bigger than 4 bytes, the dir entry contains an offset.
            if (OffsetVal+ByteCount > ExifLength){
                // Bogus pointer offset and / or bytecount value
                printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);

                ErrExit("Illegal pointer offset value in EXIF");
            }
            ValuePtr = OffsetBase+OffsetVal;
        }else{
            // 4 bytes or less and value is in the dir entry itself
            ValuePtr = DirEntry+8;
        }

        if (LastExifRefd < ValuePtr+ByteCount){
            // Keep track of last byte in the exif header that was actually referenced.
            // That way, we know where the discardable thumbnail data begins.
            LastExifRefd = ValuePtr+ByteCount;
        }

        if (ShowTags){
            // Show tag name
            for (a=0;;a++){
                if (TagTable[a].Tag == 0){
                    printf("  Unknown Tag %04x Value = ", Tag);
                    break;
                }
                if (TagTable[a].Tag == Tag){
                    printf("    %s = ",TagTable[a].Desc);
                    break;
                }
            }

            // Show tag value.
            switch(Format){

                case FMT_UNDEFINED:
                    // Undefined is typically an ascii string.

                case FMT_STRING:
                    // String arrays printed without function call (different from int arrays)
                    printf("\"");
                    for (a=0;a<ByteCount;a++){
                        if (isprint((ValuePtr)[a])){
                            putchar((ValuePtr)[a]);
                        }
                    }
                    printf("\"\n");
                    break;

                default:
                    // Handle arrays of numbers later (will there ever be?)
                    PrintFormatNumber(ValuePtr, Format);
            }
        }

        // Extract useful components of tag
        switch(Tag){

            case TAG_MAKE:
                strncpy(ImageInfo.CameraMake, ValuePtr, 31);
                break;

            case TAG_MODEL:
                strncpy(ImageInfo.CameraModel, ValuePtr, 39);
                break;

            case TAG_DATETIME_ORIGINAL:
                strncpy(ImageInfo.DateTime, ValuePtr, 19);
                break;

            case TAG_USERCOMMENT:
                // Olympus has this padded with trailing spaces.  Remove these first.
                for (a=ByteCount;;){
                    a--;
                    if ((ValuePtr)[a] == ' '){
                        (ValuePtr)[a] = '\0';
                    }else{
                        break;
                    }
                    if (a == 0) break;
                }

                // Copy the comment
                if (memcmp(ValuePtr, "ASCII",5) == 0){
                    for (a=5;a<10;a++){
                        int c;
                        c = (ValuePtr)[a];
                        if (c != '\0' && c != ' '){
                            strncpy(ImageInfo.Comments, a+ValuePtr, 199);
                            break;
                        }
                    }
                    
                }else{
                    strncpy(ImageInfo.Comments, ValuePtr, 199);
                }
                break;

            case TAG_FNUMBER:
                // Simplest way of expressing aperture, so I trust it the most.
                // (overwrite previously computd value if there is one)
                ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_APERTURE:
            case TAG_MAXAPERTURE:
                // More relevant info always comes earlier, so only use this field if we don't 
                // have appropriate aperture information yet.
                if (ImageInfo.ApertureFNumber == 0){
                    ImageInfo.ApertureFNumber 
                        = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
                }
                break;

            case TAG_FOCALLENGTH:
                // Nice digital cameras actually save the focal length as a function
                // of how farthey are zoomed in.
                ImageInfo.FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_SUBJECT_DISTANCE:
                // Inidcates the distacne the autofocus camera is focused to.
                // Tends to be less accurate as distance increases.
                ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_EXPOSURETIME:
                // Simplest way of expressing exposure time, so I trust it most.
                // (overwrite previously computd value if there is one)
                ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_SHUTTERSPEED:
                // More complicated way of expressing exposure time, so only use
                // this value if we don't already have it from somewhere else.
                if (ImageInfo.ExposureTime == 0){
                    ImageInfo.ExposureTime 
                        = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
                }
                break;

            case TAG_FLASH:
                if (ConvertAnyFormat(ValuePtr, Format)){
                    ImageInfo.FlashUsed = 1;
                }
                break;

            case TAG_EXIF_IMAGELENGTH:
            case TAG_EXIF_IMAGEWIDTH:
                // Use largest of height and width to deal with images that have been
                // rotated to portrait format.
                a = (int)ConvertAnyFormat(ValuePtr, Format);
                if (ExifImageWidth < a) ExifImageWidth = a;
                break;

            case TAG_FOCALPLANEXRES:
                FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_FOCALPLANEUNITS:
                switch((int)ConvertAnyFormat(ValuePtr, Format)){
                    case 1: FocalplaneUnits = 25.4; break; // inch
                    case 2: 
                        // According to the information I was using, 2 means meters.
                        // But looking at the Cannon powershot's files, inches is the only
                        // sensible value.
                        FocalplaneUnits = 25.4;
                        break;

                    case 3: FocalplaneUnits = 10;   break;  // centimeter
                    case 4: FocalplaneUnits = 1;    break;  // milimeter
                    case 5: FocalplaneUnits = .001; break;  // micrometer
                }
                break;

                // Remaining cases contributed by: Volker C. Schoech ([email protected])

            case TAG_EXPOSURE_BIAS:
                ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_WHITEBALANCE:
                ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_METERING_MODE:
                ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_EXPOSURE_PROGRAM:
                ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
                break;

            case TAG_ISO_EQUIVALENT:
                ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
                if ( ImageInfo.ISOequivalent < 80 ) ImageInfo.ISOequivalent *= 200;
                break;

            case TAG_COMPRESSION_LEVEL:
                ImageInfo.CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
                break;
        }

        if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
            char * SubdirStart;
            SubdirStart = OffsetBase + Get32u(ValuePtr);
            if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
                ErrExit("Illegal subdirectory link");
            }
            ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
            continue;
        }
    }
}