forkachild / C-Simple-JSON-Parser

Extremely lightweight, easy-to-use & blazing fast JSON parsing library written in pure C
https://forkachild.github.io/C-Simple-JSON-Parser/
MIT License
47 stars 17 forks source link

Bad handling of empty arrays/strings #7

Closed 64bittz closed 2 years ago

64bittz commented 2 years ago

I was parsing a response json from the Mouser API and I noticed that the library didn't parse correctly because there was an empty array ("Errors":[]) and even an empty string ("Key":"") that didn't parse correctly and even cut the name of the entries after them in some cases. IS your library simply not capable of handling empty arrays and strings or is it an error? If it is an error I will post everything needed to understand it correctly. I don't want to litter with the whole code just to understand that simply it can't handle them. P.S.: awesome library, easy and intuitive to use, great work

forkachild commented 2 years ago

Good catch! This is currently an incapability of the library.

This is currently due to the lack of resolution in the error variant of the *_result type, as the parent function that calls the corresponding sub-functions to parse the individual types need to know if something went wrong then it can either

  1. Mark the KV pair as something akin to INVALID.
  2. Remove the KV pair from the result.

I have planned on introducing this feature. Do let me know what you think about the way it should be handled and also if you want to work on the codebase, you're perfectly welcome.

64bittz commented 2 years ago

Thanks a lot for responding and for the proposal. Unfortunately, my C skills are not even comparable to what you do. I tried understanding what your library does, but i couldn't very well. If I had the knowledge I would very gladly correct this. The only thing I did is adapt it to be g++ compilable making a couple of changes, what I have is compilable as C or as C++ without issues. I don't even understand what you mean in your answer, sorry.

Anyway for the empty array I simply found that turning "[]" into "[none]" is parsed correctly (it does change a bit but the meaning is the same i think). For the string I have no idea. Also if the string value of some entry is "", the next entry key will be missing the first 1-2 characters, for example: "SuggestedReplacement":"","MultiSimBlue":0 If I read the last entry key it says "ultiSimBlue".

Thanks for reading

64bittz commented 2 years ago

Also, I have another request, this time a request for help in solving an issue. I have this json

{"Errors":[null],"SearchResults":{"NumberOfResult":2,"Parts":[{"Availability":"4462 In Stock","DataSheetUrl":"https://www.mouser.com/datasheet/2/849/bc846-2891764.pdf","Description":"Bipolar Transistors - BJT Bipolar Transistor, SOT-23, 45V, 100mA, NPN","FactoryStock":"0","ImagePath":"https://www.mouser.com/images/diotecsemiconductor/images/sot-23_SPL.jpg","Category":"Bipolar Transistors - BJT","LeadTime":"56 Days","LifecycleStatus":"New at Mouser","Manufacturer":"Diotec Semiconductor","ManufacturerPartNumber":"BC847B","Min":"1","Mult":"1","MouserPartNumber":"637-BC847B","ProductAttributes":[{"AttributeName":"Packaging","AttributeValue":"Cut Tape"},{"AttributeName":"Packaging","AttributeValue":"MouseReel"},{"AttributeName":"Packaging","AttributeValue":"Reel"},{"AttributeName":"Standard Pack Qty","AttributeValue":"3000"}],"PriceBreaks":[{"Quantity":1,"Price":"0,371 Ôé¼","Currency":"EUR"},{"Quantity":10,"Price":"0,341 Ôé¼","Currency":"EUR"},{"Quantity":100,"Price":"0,186 Ôé¼","Currency":"EUR"},{"Quantity":500,"Price":"0,116 Ôé¼","Currency":"EUR"},{"Quantity":1000,"Price":"0,075 Ôé¼","Currency":"EUR"},{"Quantity":3000,"Price":"0,054 Ôé¼","Currency":"EUR"},{"Quantity":6000,"Price":"0,052 Ôé¼","Currency":"EUR"},{"Quantity":9000,"Price":"0,048 Ôé¼","Currency":"EUR"}],"AlternatePackagings":null,"ProductDetailUrl":"https://www.mouser.it/ProductDetail/Diotec-Semiconductor/BC847B?qs=OlC7AqGiEDnZaP%2FmjLcN6A%3D%3D","Reeling":true,"ROHSStatus":"RoHS Compliant","SuggestedReplacement":null,"MultiSimBlue":0,"InfoMessages":[null],"ProductCompliance":[{"ComplianceName":"TARIC","ComplianceValue":"8541210000"},{"ComplianceName":"CNHTS","ComplianceValue":"8541210000"},{"ComplianceName":"USHTS","ComplianceValue":"8541210095"},{"ComplianceName":"ECCN","ComplianceValue":"EAR99"}]},{"DataSheetUrl":"https://www.mouser.com/datasheet/2/308/BC847-1300131.pdf","Description":"Bipolar Transistors - BJT SOT-23 NPN GP AMP","FactoryStock":null,"ImagePath":"https://www.mouser.com/images/mouserelectronics/images/SOT_23_3_t.jpg","Category":"Bipolar Transistors - BJT","LeadTime":"0 Days","LifecycleStatus":"Obsolete","Manufacturer":"onsemi / Fairchild","ManufacturerPartNumber":"BC847B","Min":"1","Mult":"1","MouserPartNumber":"512-BC847B","ProductAttributes":[null],"PriceBreaks":[null],"AlternatePackagings":null,"ProductDetailUrl":"https://www.mouser.it/ProductDetail/onsemi-Fairchild/BC847B?qs=fKsNvYl5pt9F%252BYE7Yxb4yg%3D%3D","Reeling":false,"ROHSStatus":"No","SuggestedReplacement":null,"MultiSimBlue":0,"InfoMessages":[null],"RestrictionMessage":"Mouser does not sell this product in your region.","ProductCompliance":[{"ComplianceName":"TARIC","ComplianceValue":"8541210000"},{"ComplianceName":"CAHTS","ComplianceValue":"8541210000"},{"ComplianceName":"CNHTS","ComplianceValue":"8541210000"},{"ComplianceName":"USHTS","ComplianceValue":"8541210095"},{"ComplianceName":"ECCN","ComplianceValue":"EAR99"}]}]}}

And I have this piece of code

   json_object_t *json = json_parse(response);

   json_object_t *data;

   json_array_t *parts;

   json_object_t *part;

   data = json->entries[1].value.as_object;
   parts = data->entries[1].value.as_array;

   if(parts->count != data->entries[0].value.as_number)
   {
      return;
   }

   for(int i = 0; i < parts->count /*data->entries[0].value.as_number*/; i++)
   {
      part = parts[i].values->as_object;

      printf("i = %d\n", i);

      for(size_t j = 0; j < part->count; j++)
      {
         if(!strcmp("DataSheetUrl", part->entries[j].key))
         {
            printf("Datasheet url: %s\n", part->entries[j].value.as_string);
         }
      }
   }

   json_free(json);

It prints the first datasheet link just fine, but the second one not. If I call part->count on the second item of the array it reports some high random number which isn't correct. For some reason it knows it's a 2 item array but the second item is not accessible. The array I'm talking about is the array with the "Parts" key, after "NumberOfResult". Am I doing something wrong?

forkachild commented 2 years ago

Thanks a lot for responding and for the proposal. Unfortunately, my C skills are not even comparable to what you do. I tried understanding what your library does, but i couldn't very well. If I had the knowledge I would very gladly correct this. The only thing I did is adapt it to be g++ compilable making a couple of changes, what I have is compilable as C or as C++ without issues. I don't even understand what you mean in your answer, sorry.

Anyway for the empty array I simply found that turning "[]" into "[none]" is parsed correctly (it does change a bit but the meaning is the same i think). For the string I have no idea. Also if the string value of some entry is "", the next entry key will be missing the first 1-2 characters, for example: "SuggestedReplacement":"","MultiSimBlue":0 If I read the last entry key it says "ultiSimBlue".

Thanks for reading

This is due to the mishandling of error during empty values. I'm fixing this.

forkachild commented 2 years ago

Also, I have another request, this time a request for help in solving an issue. I have this json

{"Errors":[null],"SearchResults":{"NumberOfResult":2,"Parts":[{"Availability":"4462 In Stock","DataSheetUrl":"https://www.mouser.com/datasheet/2/849/bc846-2891764.pdf","Description":"Bipolar Transistors - BJT Bipolar Transistor, SOT-23, 45V, 100mA, NPN","FactoryStock":"0","ImagePath":"https://www.mouser.com/images/diotecsemiconductor/images/sot-23_SPL.jpg","Category":"Bipolar Transistors - BJT","LeadTime":"56 Days","LifecycleStatus":"New at Mouser","Manufacturer":"Diotec Semiconductor","ManufacturerPartNumber":"BC847B","Min":"1","Mult":"1","MouserPartNumber":"637-BC847B","ProductAttributes":[{"AttributeName":"Packaging","AttributeValue":"Cut Tape"},{"AttributeName":"Packaging","AttributeValue":"MouseReel"},{"AttributeName":"Packaging","AttributeValue":"Reel"},{"AttributeName":"Standard Pack Qty","AttributeValue":"3000"}],"PriceBreaks":[{"Quantity":1,"Price":"0,371 Ôé¼","Currency":"EUR"},{"Quantity":10,"Price":"0,341 Ôé¼","Currency":"EUR"},{"Quantity":100,"Price":"0,186 Ôé¼","Currency":"EUR"},{"Quantity":500,"Price":"0,116 Ôé¼","Currency":"EUR"},{"Quantity":1000,"Price":"0,075 Ôé¼","Currency":"EUR"},{"Quantity":3000,"Price":"0,054 Ôé¼","Currency":"EUR"},{"Quantity":6000,"Price":"0,052 Ôé¼","Currency":"EUR"},{"Quantity":9000,"Price":"0,048 Ôé¼","Currency":"EUR"}],"AlternatePackagings":null,"ProductDetailUrl":"https://www.mouser.it/ProductDetail/Diotec-Semiconductor/BC847B?qs=OlC7AqGiEDnZaP%2FmjLcN6A%3D%3D","Reeling":true,"ROHSStatus":"RoHS Compliant","SuggestedReplacement":null,"MultiSimBlue":0,"InfoMessages":[null],"ProductCompliance":[{"ComplianceName":"TARIC","ComplianceValue":"8541210000"},{"ComplianceName":"CNHTS","ComplianceValue":"8541210000"},{"ComplianceName":"USHTS","ComplianceValue":"8541210095"},{"ComplianceName":"ECCN","ComplianceValue":"EAR99"}]},{"DataSheetUrl":"https://www.mouser.com/datasheet/2/308/BC847-1300131.pdf","Description":"Bipolar Transistors - BJT SOT-23 NPN GP AMP","FactoryStock":null,"ImagePath":"https://www.mouser.com/images/mouserelectronics/images/SOT_23_3_t.jpg","Category":"Bipolar Transistors - BJT","LeadTime":"0 Days","LifecycleStatus":"Obsolete","Manufacturer":"onsemi / Fairchild","ManufacturerPartNumber":"BC847B","Min":"1","Mult":"1","MouserPartNumber":"512-BC847B","ProductAttributes":[null],"PriceBreaks":[null],"AlternatePackagings":null,"ProductDetailUrl":"https://www.mouser.it/ProductDetail/onsemi-Fairchild/BC847B?qs=fKsNvYl5pt9F%252BYE7Yxb4yg%3D%3D","Reeling":false,"ROHSStatus":"No","SuggestedReplacement":null,"MultiSimBlue":0,"InfoMessages":[null],"RestrictionMessage":"Mouser does not sell this product in your region.","ProductCompliance":[{"ComplianceName":"TARIC","ComplianceValue":"8541210000"},{"ComplianceName":"CAHTS","ComplianceValue":"8541210000"},{"ComplianceName":"CNHTS","ComplianceValue":"8541210000"},{"ComplianceName":"USHTS","ComplianceValue":"8541210095"},{"ComplianceName":"ECCN","ComplianceValue":"EAR99"}]}]}}

And I have this piece of code

   json_object_t *json = json_parse(response);

   json_object_t *data;

   json_array_t *parts;

   json_object_t *part;

   data = json->entries[1].value.as_object;
   parts = data->entries[1].value.as_array;

   if(parts->count != data->entries[0].value.as_number)
   {
      return;
   }

   for(int i = 0; i < parts->count /*data->entries[0].value.as_number*/; i++)
   {
      part = parts[i].values->as_object;

      printf("i = %d\n", i);

      for(size_t j = 0; j < part->count; j++)
      {
         if(!strcmp("DataSheetUrl", part->entries[j].key))
         {
            printf("Datasheet url: %s\n", part->entries[j].value.as_string);
         }
      }
   }

   json_free(json);

It prints the first datasheet link just fine, but the second one not. If I call part->count on the second item of the array it reports some high random number which isn't correct. For some reason it knows it's a 2 item array but the second item is not accessible. The array I'm talking about is the array with the "Parts" key, after "NumberOfResult". Am I doing something wrong?

This is happening because you are trying to index into the array container, not the inside of the array

Change this

part = parts[i].values->as_object

To this

part = parts->values[i].as_object
forkachild commented 2 years ago

Please check the PR, test your code against the issue branch and let me know

64bittz commented 2 years ago

Ok so changing that line worked fine, I can't believe I missed that. As for the empty arrays/strings, I'll do a workaround and replace the [] with [null] and the "" with "empty". It's not the same in json, but since I don't need to output this and my code is aware of this, I'll take this path. Thanks a lot. Your library was really really helpful

forkachild commented 2 years ago

Did you check this branch?